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