一、全局下的this
浏览器环境指向window,Node环境指向Global
console.log(this); // Window
二、对象调用
谁调用指向谁
var obj = {
num: 0,
fun() {
console.log(this); // {num: 0, fun: ƒ} 指向 obj 对象
},
};
obj.fun();
三、独立调用
浏览器环境指向window,Node环境指向Global
function fun() {
console.log(this); // Window
}
// 独立调用
fun();
var obj = {
num: 0,
fun() {
function test() {
console.log(this); // Window
}
// 独立调用
test();
// 立即执行函数也是独立调用
(function fun() {
console.log(this); // Window
})();
},
};
obj.fun();
var obj = {
num: 0,
fun() {
function test() {
console.log(this); // Window
}
// 形成闭包
return test;
},
};
// obj.fun()返回一个函数,然后直接调用
obj.fun()();
function foo() {
console.log(this);
}
function bar(fn) {
// 独立调用
fn(); // window
}
var obj = {
foo,
};
// 传递的是对foo函数的引用,但此时没有调用
bar(obj.foo);
四、new
class Person {
constructor() {}
fun() {
console.log(this);
}
}
const person = new Person();
person.fun(); // Person {}
function Fun() {
console.log(this);
}
let obj = { name: "obj" };
// new 的优先级比bind要高
let fun_bind = Fun.bind(obj);
new fun_bind(); // Fun {}
下面这种情况虽然不会出现,但需要注意
class Person {
constructor() {
let obj = { name: "sun" };
// 在构造函数中返回一个值,如果是引用数据类型会改变返回结果,如果是基本数据类型则不会改变
return obj;
}
fun() {
console.log(this);
}
}
const person = new Person();
console.log(person); // {name: 'sun'}
五、箭头函数
-
箭头函数没有自己的this指向,所以它会根据作用域链一层一层往外找。
function fun() { return () => { console.log(this); }; } var obj = { a: 1, fun, }; // 这里obj.fun()返回了一个箭头函数,通过独立调用,指向的却不是 window ,所以独立调用对箭头函数无效 obj.fun()(); // {a: 1, fun: ƒ}
function fun() { return () => { console.log(this); }; } var obj = { a: 1, fun, }; // 这里尝试修改箭头函数的 this 指向,但无效。箭头函数都没有this指向,又怎么可能修改呢? fun().call(obj); // window
const fun = () => { console.log(this); }; // 尝试使用 new 来实例化,会直接报错,箭头函数不能作为构造函数使用 new fun(); // Uncaught TypeError: fun is not a constructor
六、修改this指向
call、apply、bind
-
都可以修改this指向
-
call、apply会立即执行,bind返回一个修改this执行后的函数
-
call、bind传递函数参数为多个,apply传递数组
-
多次使用bind,只有第一次有效
let obj = {}; function fun(a, b) { console.log(this); console.log(a, b); } fun.call(obj, 1, 2); // {} 指向 obj fun.apply(obj, [1, 2]); // {} 指向 obj fun.bind(obj)(1, 2); // {} 指向 obj fun.call(1, 1, 2); // Number {1} fun.apply("1", [1, 2]); // String {'1'} fun.bind(true)(1, 2); // Boolean {true} fun.call(Symbol(), 1, 2); // Symbol {Symbol(), description: undefined} fun.apply(BigInt(1), [1, 2]); // BigInt {1n} fun.bind(undefined)(1, 2); // window fun.call(null, 1, 2); // window fun.bind({ name: "第一个" }).bind({ name: "第二个" }, 3, 4)(); // {name: '第一个'}
七、补充
-
数组中
forEach
中传递的函数的thislet obj = {}; let arr = [1, 2, 3]; arr.forEach(function () { console.log(this); // window }); arr.forEach(function () { console.log(this); // {} 指向 obj }, obj); arr.forEach(() => { console.log(this); // window }); arr.forEach(() => { console.log(this); // window }, obj);
八、总结
- this绑定有4种
- 默认绑定:window,独立调用也指向window
- 隐式绑定:对象调用
obj.fun()
,谁调用就指向谁 - 显示绑定:call、apply、bind
- new绑定:new Person()
- 优先级:new > 显示绑定 > 隐式绑定 > 默认绑定
- 箭头函数没有this指向,会通过作用域链往上找