前端面试题小记(一)

139 阅读2分钟
var a = 1;
a = 2; 
window.a = 3;
//构造函数
function Test() {
    let a = 4;
    this.a = 5;
    setTimeout(() => {
        console.log(a);
    }, 10);
    setTimeout(function() {
        console.log(a);
    }, 20);
    setTimeout(() => {
        console.log(this.a);
    }, 30);
    setTimeout(function() {
        console.log(this.a);
    }, 40);
}
const test = new Test(); // 4 4 5 3

这个是一个非常简单的面试题,主要考察了变量作用域、this关键字的行为以及箭头函数与普通函数在处理this时的区别。

  • 代码1-3行,var创建的变量在全局作用域下生效,并且挂载到window对象上。即window.a与a值都是3.
  • Test是一个构造函数,let a = 4; 定义了一个块级作用域的变量a,这个a只在构造函数内部可见,并且不会影响到全局变量a
  • this.a = 5 设置了Test构造函数的实例的属性a的值是5

依次来看4个setTimeout:

  • 第一个setTimeout执行,包裹的是一个箭头函数,箭头函数的作用域中没有定义a变量,只能往上一级的作用域中寻找a变量,恰好构造函数Test定义了局部变量a(let a = 4;),这个a的值是4.
  • 第二个setTimeout执行,包裹的是一个普通函数,同理,去寻找a变量,这个a的值是4.
  • 第三个setTimeout执行,包裹的是一个箭头函数,它的this的值是在函数创建时确定的,而不是在函数调用时确定的,意味着箭头函数会继承其所在上下文的this值,而不会创建自己的this,所以这里的this的值是构造函数生成的实例对象test,故a的值是5。
  • 第三个setTimeout执行,包裹的是一个普通函数,这里普通函数的this会指向window,故a的值是3。
  • 最终输出:4 4 5 3

补充:

箭头函数的this指向: this的值是在函数创建时确定的,而不是在函数调用时确定的。这意味着箭头函数会继承其所在上下文的this值,而不会创建自己的this

  • 箭头函数被定义在一个普通函数中,它的this指向普通函数的this。
  • 箭头函数被定义全局作用域中,它的this就指向全局对象(在浏览器环境中是window对象,在Node.js环境中是global对象)
  • 在构造函数或类的方法中定义的箭头函数,它的this执向实例对象。

可以看下下面的代码的输出:

var a = 1;
a = 2; 
window.a = 3;
//构造函数
function Test() {
    let a = 4;
    this.a = 5;
    setTimeout(() => {
        console.log(a);
    }, 10);
    setTimeout(function() {
        console.log(a);
    }, 20);
    setTimeout(() => {
        console.log(this.a);
    }, 30);
    setTimeout(function() {
        console.log(this.a);
    }, 40);
    this.sayA = () => {
        console.log('test.A1', this.a); // 5
    }
    this.sayA2 = function() {
        console.log('test.A2', this.a); // 5
    }

}

const sayA2 = () => {
    const sayA3 = () => {
        console.log('A3', this.a); // 3
    }
    console.log('A2', this.a); // 3
    sayA3()
}
const test = new Test(); // 4 4 5 3
const test2 = {
    a: 6,
    sayA4: () => {
        console.log('test2.A4', this.a); // 3
    },
    sayA5: function() {
        console.log('test2.A5', this.a); // 6
    }
}
test.sayA(); // 5
test.sayA2(); // 5
sayA2() // 3 3
test2.sayA4() // 3
test2.sayA5() // 6