this-challenge
1. 全局调用
js
var a = 10;
function foo() {
console.log("this1", this);
console.log(window.a);
console.log(this.a);
}
console.log("this2", this);
foo();
查看答案/解析
答案:
js
// this2 Window
// this1 Window
// 10
// 10
解析:
- 全局的 this 指向 window
- 非严格模式下,全局调用的函数 this 指向 window
var a = 10
会在 window 上挂载 a, 相当于window.a = 10
, 因此 window.a => 10- this 指向 window
2. 严格模式
js
"use strict";
var a = 10;
function foo() {
console.log("this1", this);
console.log(window.a);
console.log(this.a);
}
console.log("this2", this);
foo();
查看答案/解析
答案:
js
// 'this2' Window
// 'this1' undefined
// 10
// Uncaught TypeError: Cannot read property 'a' of undefined
解析:
- 严格模式下,全局的 this 不受影响,仍然指向 window
- 严格模式下,全局调用的函数 this 指向 undefined
- 严格模式下,
var a = 10
仍然会在 window 上挂载, 因此依然输出 10 - 上面说到函数内的 this 是 undefined,因此访问 this.a 会报错
3. const、let、var
js
let a = 10;
const b = 20;
function foo() {
console.log(this.a);
console.log(this.b);
}
foo();
console.log(window.a);
查看答案/解析
答案:
js
// undefined;
// undefined;
// undefined;
解析:
let 和 const 是不会向 window 上挂载的,因此都是 undefined
4. 同名变量
js
var a = 1;
function foo() {
var a = 2;
console.log(this);
console.log(this.a);
}
foo();
查看答案/解析
答案:
js
// Window
// 1
解析:
全局调用的函数中 this 指向 Window,因此 this.a
=> 1
5. 函数嵌套
javascript
var a = 1;
function foo() {
var a = 2;
function inner() {
console.log(this.a);
}
inner();
}
foo();
查看答案/解析
答案:
js
// 1
解析:
这里具有迷惑性,因为 this.a 是在 foo 函数内,可能潜意识中 this 指向的是 foo 这个作用域。 事实上,调用的函数(inner)仍然是以全局的方式调用,因此 this 仍指向 Window
6. 函数被改变
javascript
function foo() {
console.log(this.a);
}
var obj = { a: 1, foo };
var a = 2;
var foo2 = obj.foo;
var obj2 = { a: 3, foo2: obj.foo };
obj.foo();
foo2();
obj2.foo2();
查看答案/解析
答案:
js
// 1
// 2
// 3
解析:
obj.foo()
中的 this 指向调用者 objfoo2()
发生了隐式丢失,调用者是 window,使得foo()
中的 this 指向 windowfoo3()
发生了隐式丢失,调用者是 obj2,使得foo()
中的 this 指向 obj2
7. 函数当参数
javascript
function foo() {
console.log(this.a);
}
function doFoo(fn) {
console.log(this);
fn();
}
var obj = { a: 1, foo };
var a = 2;
doFoo(obj.foo);
查看答案/解析
答案:
js
// Window
// 2
解析:
- 全局调用,所以指向 Window
- 虽然传递的是
obj.foo()
, 但是调用的时候是fn()
,依然是全局调用的,因此 this 指向 Window
8. 函数当参数 2
javascript
function foo() {
console.log(this.a);
}
function doFoo(fn) {
console.log(this);
fn();
}
var obj = { a: 1, foo };
var a = 2;
var obj2 = { a: 3, doFoo };
obj2.doFoo(obj.foo);
查看答案/解析
答案:
js
// { a:3, doFoo: f }
// 2
解析:
- 由于是通过 obj2 调用的
doFoo()
,因此 this 指向的是 obj2 - 调用
fn()
时,仍然是全局调用的,因此 this 指向 Window
9. setTimeout 中的 this
javascript
var obj1 = { a: 1 };
var obj = {
a: 2,
foo: function () {
setTimeout(function () {
console.log(this.a);
}, 0);
},
};
var a = 3;
obj.foo();
obj.foo.call(obj1);
查看答案/解析
答案:
js
// 3
解析:
- 这里的关键点:setTimeout 中的函数指向是 Window。
- 虽然使用了 call,但是这里的 call 改变的是 foo 方法的 this,对 setTimeout 中的函数其实是没有影响的
10. call
javascript
var obj = {
a: "obj",
foo: function () {
console.log("foo:", this.a);
return function () {
console.log("inner:", this.a);
};
},
};
var a = "window";
var obj2 = { a: "obj2" };
obj.foo()();
obj.foo.call(obj2)();
obj.foo().call(obj2);
查看答案/解析
答案:
js
// foo: obj
// inner: window
// foo: obj2
// inner: window
// foo: obj
// inner: obj2
解析:
- obj 调用 foo,因此 this 指向 obj 输出
- 将 1 的返回值继续调用,此时是全局调用,所以 this 指向 Window
obj.foo.call(obj2)
是将 foo 这个函数显示的绑定到了 obj2,因此指向 obj2- 将 3 的返回值继续调用,此时是全局调用,所以 this 指向 Window
- obj 调用 foo,因此 this 指向 obj 输出
- 将 4 的返回值通过 call 显示绑定 this,因此 this 指向 obj2
11. 多次 bind
javascript
var obj = {
a: 0,
foo: function () {
console.log(this.a);
},
};
var obj1 = { a: 1 };
var obj2 = { a: 2 };
var a = 3;
obj.foo.bind(obj1).bind(obj2)();
查看答案/解析
答案:
js
// 1
解析:
bind 操作只有第一次绑定有效果,之后再次进行绑定,不会有效果。因此 this 永远指向第一次绑定的对象 obj1
12. new
javascript
function A(val) {
this.a = val;
this.foo = function () {
console.log(this.a);
return function () {
console.log(this.a);
};
};
}
var a = 2;
var instance = new A(1);
instance.foo()();
查看答案/解析
答案:
js
// 1
// 2
解析:
- new 的时候会把 this 绑定到创建出的实例上,因此调用 instance.foo() 时 this 指向 instance 对象
- 继续调用 1 的返回值时,相当于全局调用,因此 this 指向 Window
13. 箭头函数
javascript
var obj = {
name: "obj",
foo1: () => {
console.log(this.name);
},
foo2: function () {
console.log(this.name);
return () => {
console.log(this.name);
};
},
foo3: () => {
console.log(this.name);
return () => {
console.log(this.name);
};
},
};
var name = "window";
obj.foo1();
obj.foo2()();
obj.foo3()();
查看答案/解析
答案:
js
// window
// obj
// obj
// window
// window
解析: 箭头函数的 this 是在定义时就确定好的,并且是由外层的作用域来决定
- foo1 是箭头函数,因此无论是谁调用它,它的 this 都指向外层作用域,这里的外层就是 window
obj.foo2()
是普通函数因此 this 指向调用它的对象,也就是 obj- 2 的返回值是箭头函数,所以该函数的 this 指向外层,也就是 foo2,因此 this 是 obj
- 同 1
- 4 的返回值是箭头函数,所以该函数的 this 指向外层,也就是 foo1 的 this,因此是 window
14. 箭头函数 + call
javascript
var name = "window";
var obj1 = {
name: "obj1",
foo1: function () {
console.log(this.name);
return () => {
console.log(this.name);
};
},
foo2: () => {
console.log(this.name);
return function () {
console.log(this.name);
};
},
};
var obj2 = {
name: "obj2",
};
obj1.foo1.call(obj2)();
obj1.foo1().call(obj2);
obj1.foo2.call(obj2)();
obj1.foo2().call(obj2);
查看答案/解析
答案:
js
// obj2
// obj2
// obj1
// obj1
// window
// window
// window
// obj2
解析:
obj1.foo1.call(obj2)
this 被 call 修改为 obj2- 1 的返回值是箭头函数,调用时指向外层作用域,因此也是 obj2
obj1.foo1()
因为是 obj1 调用的 所以 this 指向 obj1- 3 的返回值是箭头函数,但是箭头函数不能被改变指向,因此 call 无效,所以仍然指向外层,即 obj1
obj1.foo2.call(obj2)
,因为 foo2 是箭头函数,无法被改变指向,所以仍然指向外层,即 window- 5 的返回值是普通函数,相当于全局调用,所以 this 指向 window
obj1.foo2()
箭头函数指向外层,即 window- 7 的返回值是普通函数,被执行了
.call(obj2)
,因此指向 obj2
15. new + 箭头函数 + call
javascript
var name = "window";
function Person(name) {
this.name = name;
this.obj = {
name: "obj",
foo1: function () {
return function () {
console.log(this.name);
};
},
foo2: function () {
return () => {
console.log(this.name);
};
},
};
}
var person1 = new Person("person1");
var person2 = new Person("person2");
person1.obj.foo1()();
person1.obj.foo1.call(person2)();
person1.obj.foo1().call(person2);
person1.obj.foo2()();
person1.obj.foo2.call(person2)();
person1.obj.foo2().call(person2);
查看答案/解析
答案:
js
// window
// window
// person2
// obj
解析:
person1.obj.foo1()
返回一个普通函数,在执行调用时相当于全局调用,因此 指向 windowperson1.obj.foo1.call(person2)
与 1 同理person1.obj.foo1()
返回一个普通函数,调用时被 call 改变了 this,因此指向 person2person1.obj.foo2()
这里是 person1 中的 obj 调用了 foo2,因此 foo2 中的 this 指向 obj,其返回值是箭头函数,因此 this 也是指向 objperson1.obj.foo2.call(person2)
foo2 的 this 被 call 修改 指向 person2,因此返回的箭头函数也是指向 person2person1.obj.foo2()
与 4 一样,函数的 this 是 obj,因为返回值是箭头函数,call 无法改变,因此指向还是 obj