前言
相信被代码中的this
搞得晕头转向的时候,我们一定会好奇为什么要有this
,这个this
就非用不可吗?this
到底传递的是哪一个对象引用?
如果你有上面的疑惑就把文章看完吧,相信你会找到答案!
为什么要有this
下面这段代码是我们都很熟悉的使用构造函数创建对象实例,但如果不用this该怎么写呢?
function Cloth(color,size){
this.color=color;
this.size=size;
}
const obj1=new Cloth("red","M");
console.log(obj1);//Cloth { color: 'red', size: 'M' }
最容易想到是
function Cloth2(color,size){
const instance = {};
instance.color = color;
instance.size = size;
return instance;
}
const obj2=new Cloth2("red","M");
console.log(obj2);//{ color: 'red', size: 'M' }
注意这样上面返回的是一个新对象,而不是Cloth
类的实例
为什么会这样?
JavaScript 的类构造函数有一个特殊行为:
- 如果构造函数返回一个对象,这个对象会替代默认创建的实例
- 如果返回非对象值(或没有
return
),则使用默认创建的实例
所以this为什么存在呢?
this
提供了一种更优雅的方式来隐式的传递一个对象引用,可以让代码更简洁this
是构造函数模式的核心机制,用于为新创建的对象实例绑定属性。...
所以this
不仅有用而且有些地方还没它不行。既然它这么重要,那我们继续学习它的使用规则。
this可以用在哪里
概况的说只有函数作用域和全局作用域中。
全局作用域
在全局作用域中,this
的指向:
- 非严格模式:
this
指向全局对象(浏览器中为window
,Node.js 中为global
)。 - 严格模式:
this
为undefined
。
console.log(this); // 浏览器中输出: Window 对象
函数作用域
除了我们上面提到的构造函数还可以在对象方法等其它函数中。
const person = {
name: 'Alice',
greet() {
console.log(`Hello, ${this.name}!`); // this → person 对象
}
};
person.greet(); // 输出: "Hello, Alice!"
注意:箭头函数没有自己的 this
,它会继承外层作用域的 this
。
const obj = {
value: 42,
getValue: () => {
console.log(this.value); // this → 外层作用域的 this(可能是 window)
}
};
obj.getValue(); // 输出: undefined(严格模式可能报错)
this的绑定规则
终于到我们的重头戏了,这是解决this到底指的是谁的关键。
1. 默认绑定
当函数独立调用时,this
默认绑定到全局对象
function showThis() {
console.log(this);
}
showThis();
// 非严格模式:Window 对象(浏览器)或 global 对象(Node.js)
// 严格模式:undefined
2. 隐式绑定
当函数作为对象的方法调用时,this
绑定到该对象。
const person = {
name: 'Alice',
greet: function() {
console.log(`Hello, ${this.name}`);
}
};
person.greet(); // "Hello, Alice"(this → person 对象)
注意:方法赋值给变量后会丢失 this
绑定:
const greetFunc = person.greet;
greetFunc(); // "Hello, undefined"(默认绑定)
3. 隐式丢失
当一个函数被多层对象调用时,函数的this指向指向最近的那层对象
4. 显示绑定
使用 call()
、apply()
或 bind()
可以显式指定 this
的值。
function introduce(lang) {
console.log(`I speak ${lang}. My name is ${this.name}`);
}
const person = { name: 'Bob' };
// call 和 apply 立即调用
introduce.call(person, 'English'); // "I speak English. My name is Bob"
introduce.apply(person, ['Spanish']); // 参数以数组传递
// bind 返回绑定后的函数
const boundFunc = introduce.bind(person, 'French');
boundFunc(); // "I speak French. My name is Bob"
5.new绑定
使用 new
调用构造函数时,this
绑定到新创建的对象。
绑定规则的优先级
当多个规则同时适用时,优先级从高到低为:
- new 绑定(
new Foo()
) - 显式绑定(
call/apply/bind
) - 隐式绑定(
obj.method()
) - 默认绑定(独立函数调用)
function foo() {
console.log(this.a);
}
const obj1 = { a: 1, foo: foo };
const obj2 = { a: 2 };
obj1.foo.call(obj2); // 2(显式绑定 > 隐式绑定)
new obj1.foo(); // undefined(new 绑定 > 隐式绑定)