9 个你可能不知道答案的常见 JavaScript 面试题

不管你喜不喜欢,面试官尝尝会问到棘手的问题。

原因是,这些问题可以告诉你很多关于你对语言的核心理解,借此考虑你是否适合这份工作。

这些问题中涉及的常见概念包括:

  • 提升
  • 比表
  • 范围域
  • 值与引用类型
  • 原型继承

今天我们要一石二鸟。准备好迎接下一次面试并立即复习核心概念。

为typeof未定义?

var y = 1;
if (function f() {}) {
  y += typeof f;
}

console.log(y); // 1undefined

解释

  • 条件语句 if(function f() {}) 返回 function f() {} 为真,因此代码在 if 语句内执行。
  • typeof f 返回 undefined 因为函数 f(){} 从未在 if 语句之外声明过,所以它在 if 括号之外“不存在” if (f(){}) {它不在这里}

这就是我们“修复”此代码片段的方式:

var y = 1;

function f() {}; //在 if 括号外声明函数

if (f) { //f 存在,所以我们进入 if 块
  y += typeof f; //这里 typeof f 是function
}

console.log(y); // 1function

写一个闭包的例子

function createFunction(msg) {
    return function(name) {
        return msg + name;
    }
}

let myFunc = createFunction("Hey ");
console.log(myFunc("Dude")); // Hey Dude

解释

  • 第一个函数(createFunction)返回一个匿名函数
  • 匿名函数从外部函数返回参数 msg(createFunction()) +name。

当我们声明javascript变量let myFunc = createFunction("Hey ") 时,变量 myFunc 持有对外部返回的匿名函数的引用

有趣的是,当您调用myFunc("Dude")(仅传递“name”参数)时,它仍然“记住”执行 createFunction() 时传入的 msg 的值。

从创建函数的外部“范围”访问变量的能力是闭包的定义之一。


编写一个可以像 multiply(2)(5)(10) 一样调用并返回 100 的 multiply() 函数

这与上面的示例类似,不同之处在于我们正在重新调整一个附加函数并立即调用所有函数(不使用变量来保存引用)

function multiply(x) {
    return function(y){
        return function(z) {
          return x*y*z;
        };
    }
}

multiply(2)(5)(10) //100

调用方法

multiply(2)(5)(10)

我们正在一个接一个地调用返回的函数。

我们可以使用中间变量使其更清晰。 我们来看一下:

let func1 = multiply(2); // x is 2
console.log(func1) // function(y) { return function(z) { return x*y*z } }

let func2 = func1(5); // y is 5
console.log(func1) // function(z) { return x*y*z }

func2(10); // z is 10
// finally has all 3 values and returns their product.


局部变量的删除运算符

以下代码的输出是什么?

let output = (function(x) {
    delete x;
    return x;
})(0);

删除运算符旨在用于删除对象的属性,而不是值类型(在本例中为数字)。

以下代码会起作用:

let obj = { name: 'Gus', age: 32 }
delete obj.age;

console.log(obj) // { name: 'Gus' }

对象上的删除运算符

const Person = {
    name: 'Gus',
    age: 32,
}

const person1 = Object.create(Person);
delete person1.age

console.log(person1.Age); // 32
  • 创建 person1 时,其原型设置为 Person 对象。
  • 当实例的 'age' 属性被删除时,我们仍然可以访问原型对象(Person)的 'age' 属性
  • 这就是为什么它不起作用的原因。


数组上的删除运算符

arr.length 的结果是什么?

  let arr = ["a", "b", "c", "d"];
  delete arr[2];

  arr.length // 4
  • 在数组上使用时,删除运算符将删除元素设置为“空”,但不会将其从数组中删除,也不会更改数组的长度。

两个 console.log 的值是多少?

var favouriteAnime = "Dragon Ball";
(function() {
    console.log(favouriteAnime);
    var favouriteAnime = "Naruto";
    console.log(favouriteAnime);
})();

// undefined 
// Naruto

以下是编译器如何解释这段代码:

var favouriteAnime; // 使用 undefined 声明和初始化
(function() {
    console.log(favouriteAnime);
    var favouriteAnime = "Naruto";
    console.log(favouriteAnime);
})();

favouriteAnime = "Dragon Ball";

// undefined 
// Naruto

声明 JavaScript 函数和变量时要记住一些事情。

  • 变量赋值(myVar = 5) 优先于函数声明(function func(){})
  • 函数声明(function func(){}) 优先于变量声明var 、let 或 const
  • 函数声明 (function func(){}) 被提升到变量声明 (var myVar;) 之上,但未被提升到变量赋值 (myVar = 5;) 之上。

作为最佳实践,您应该始终在调用函数之前声明它们。

在此处了解有关提升的更多信息

你会如何检查一个数字是否是整数?

检查一个数字是小数还是整数的一个非常简单的方法是查看除以 1 时是否还有余数。

function isInt(num) {
  return num % 1 === 0;
}

console.log(isInt(4)); // true
console.log(isInt(12.2)); // false
console.log(isInt(0.3)); // false

结论

请亲自尝试这些示例。

这个微小的动作将帮助您更长时间地记住所学内容。

这是我们今天看到的内容的回顾:

  • 为什么 typeof f 是未定义的?
  • 写一个闭包的例子
  • 编写一个可以像 multiply(2)(5)(10) 一样调用并返回 100 的 multiply() 函数
  • 局部变量的删除运算符
  • 对象上的删除运算符
  • 数组上的删除运算符
  • 两个 console.log 的值是多少?
  • 你会如何检查一个数字是否是整数?

谢谢阅读!