this在js中作为函数中的关键字,在运行期间被绑定且不可被赋值,在严格模式和非严格模式下也有一些差别
this的值:
是当前执行上下文(global、function 或 eval)的一个属性,在非严格模式下,总是指向一个对象,在严格模式下可以是任意值。
描述:
1.全局上下文:
无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。
2.函数上下文:
在函数内部,this的值取决于函数被调用的方式。
不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window,然而,在严格模式下,如果进入执行环境时没有设置 this 的值,this 会保持为 undefined
3.类上下文:
在类的构造函数中,this 是一个常规对象。类中所有非静态的方法都会被添加到 this 的原型中:
class Example {
constructor() {
const proto = Object.getPrototypeOf(this);
console.log(Object.getOwnPropertyNames(proto));
}
first(){}
second(){}
static third(){}
}
new Example(); // ['constructor', 'first', 'second']
- 静态方法不是 this 的属性,它们只是类自身的属性。
4.派生类
不像基类的构造函数,派生类的构造函数没有初始的 this 绑定。在构造函数中调用 super() 会生成一个 this 绑定,并相当于执行如下代码,Base 为基类:
this = new Base();
派生类不能在调用 super() 之前返回,除非其构造函数返回的是一个对象,或者根本没有构造函数。
class Base {}
class Good extends Base {}
class AlsoGood extends Base {
constructor() {
return {a: 5};
}
}
class Bad extends Base {
constructor() {}
}
new Good();
new AlsoGood();
new Bad(); // ReferenceError
2.常见绑定规则:
1. 函数上下文中的 this
// 对象可以作为 bind 或 apply 的第一个参数传递,并且该参数将绑定到该对象。
var obj = { a: "Custom" };
// 声明一个变量,并将该变量作为全局对象 window 的属性。
var a = "Global";
function whatsThis() {
return this.a; // this 的值取决于函数被调用的方式
}
whatsThis(); // 'Global' 因为在这个函数中 this 没有被设定,所以它默认为 全局/ window 对象
whatsThis.call(obj); // 'Custom' 因为函数中的 this 被设置为 obj
whatsThis.apply(obj); // 'Custom' 因为函数中的 this 被设置为 obj
2.this 和对象转换
function add(c, d) {
return this.a + this.b + c + d;
}
var o = {a: 1, b: 3};
// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16
// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34
在非严格模式下使用 call 和 apply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。null 和 undefined 被转换为全局对象。原始值如 7 或 'foo' 会使用相应构造函数转换为对象。因此 7 会被转换为 new Number(7) 生成的对象,字符串 'foo' 会转换为 new String('foo') 生成的对象。
function bar() {
console.log(Object.prototype.toString.call(this));
}
bar.call(7); // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]
3.箭头函数
在箭头函数中,this与封闭词法环境的this保持一致(箭头函数的this指向它的外部)。在全局代码中,它将被设置为全局对象:
var globalObject = this;
var foo = () => this;
console.log(foo() === globalObject); // true
备注: 如果将this传递给call、bind、或者apply来调用箭头函数,它将被忽略。不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null。
// 接着上面的代码
// 作为对象的一个方法调用
var obj = { foo: foo };
console.log(obj.foo() === globalObject); // true
// 尝试使用 call 来设定 this
console.log(foo.call(obj) === globalObject); // true
// 尝试使用 bind 来设定 this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
4.对象方法中的this
- 当函数作为对象的方法调用时,
this将绑定到该对象。例如:
const obj = {
name: 'John',
greet: function() {
console.log('Hello, ' + this.name);
}
};
obj.greet(); // this 指向 obj,输出 "Hello, John"
5.构造函数中的this
- 当使用
new关键字创建对象实例时,构造函数中的this会指向新创建的对象。
function Person(name) {
this.name = name;
}
const person1 = new Person('Alice');
console.log(person1.name); // 输出 "Alice"
6.事件处理函数中的 this
- 在事件处理函数中,
this通常指向触发事件的元素。例如,当点击按钮时,按钮的事件处理函数中的this指向按钮元素。
7.显示绑定:
使用call(),apply(),bind()显示的绑定函数的this
.this丢失问题
- 有时,
this可能会在函数传递、嵌套函数中被“丢失”。在这种情况下,可以通过保存this的引用(通常使用self或that)来避免丢失。
const obj = {
name: 'David',
func: function() {
const self = this; // 保存 this 的引用
setTimeout(function() {
console.log('Hello, ' + self.name); // 正确引用 this
}, 1000);
}
};
obj.func(); // 输出 "Hello, David"