JavaScript 中的 this 指向是一个重要且复杂的概念,每次记了忘忘了记,自己实操下整个文档加深下印象
- 全局环境中的this
js
// 在浏览器中
console.log(this); // Window 对象
// 在 Node.js中
console.log(this); // {} 空对象
- 函数中的this
js
// 普通函数调用
function test() {
console.log(this); // 严格模式下是 undefined,非严格模式下是 Window
}
test();
// 对象方法调用
const obj = {
name: 'obj',
test: function() {
console.log(this); // 指向 obj 对象
}
};
obj.test();
// 箭头函数
const obj = {
name: 'obj',
test: () => {
console.log(this); // 指向定义时的上下文,这里是 Window
}
};
obj.test();
- 构造函数中的this
js
function Person(name) {
this.name = name; // this 指向新创建的对象
console.log(this);
}
const p = new Person('John'); // Person { name: 'John' }
- 事件处理函数中的this
js
<body>
<button id="btn">点击</button>
<script>
const button = document.getElementById('btn');
// DOM 事件
button.addEventListener('click', function () {
console.log(this); // 指向触发事件的dom元素
});
// 箭头函数作为事件处理函数
button.addEventListener('click', () => {
console.log(this); // 指向定义时的上下文,这里指向window
});
</script>
</body>
- call、apply、bind改变this
js
function test() {
console.log(this.name);
}
const obj1 = { name: 'obj1' };
const obj2 = { name: 'obj2' };
// call
test.call(obj1); // 'obj1'
// apply
test.apply(obj2); // 'obj2'
// bind
const boundTest = test.bind(obj1);
boundTest(); // 'obj1'
- 类中的this
js
class Person {
constructor(name) {
this.name = name; // this 指向实例
}
sayName() {
console.log(this.name); // 'john'
}
// 箭头函数方法
sayNameArrow = () => {
console.log(this.name); // 'john'
};
}
const p = new Person('John');
p.sayNameArrow(); // 'John'
- 定时器中的this
js
const obj = {
name: 'obj',
test: function () {
setTimeout(function () {
console.log(this); // Window
}, 1000);
setTimeout(() => {
console.log(this); // obj
}, 1000);
},
};
obj.test();
js
//如果example是箭头函数,下面不论是否严格模式都指向window
function example() {
console.log(this); // 严格模式下是undefined 非严格模式Window
setTimeout(() => {
console.log(this); // 严格模式下是undefined 非严格模式Window
}, 0);
setTimeout(function () {
console.log(this); // Window
}, 0);
}
example();
- promise中的this
js
new Promise(function (resolve) {
console.log(this); // 严格模式下是undefined,非严格模式下是Window
resolve();
});
new Promise((resolve) => {
console.log(this); // Window
resolve();
});
js
const obj = {
name: 'obj',
test: function() {
new Promise(function(resolve) {
console.log(this); // 严格模式下是undefined,非严格模式下是Window
resolve();
});
new Promise((resolve) => {
console.log(this); // obj
resolve();
});
}
};
obj.test();
js
const example = () => {
new Promise(function (resolve) {
console.log(this); // 严格模式下是undefined,非严格模式下是Window
resolve();
});
new Promise((resolve) => {
console.log(this); // Window
resolve();
});
};
example();
- this的优先级规则
- 优先级从高到底
- new 绑定
- 显式绑定 (call, apply, bind)
- 隐式绑定 (对象方法调用)
- 默认绑定 (普通函数调用)
- 优先级从高到底
js
function test() {
console.log(this.name);
}
const obj = { name: 'obj' };
// 1. new 绑定
new test(); // test {}
// 2. 显式绑定
test.call(obj); // 'obj'
// 3. 隐式绑定
obj.test = test;
obj.test(); // 'obj'
// 4. 默认绑定
test(); // undefined (严格模式) 或 Window (非严格模式)
- 常见this指向问题及解决方案
js
const obj = {
data: [1, 2, 3],
process: function () {
this.data.forEach(function (item) {
console.log(this); // 严格模式undefined;非严格模式Window
});
},
};
obj.process();
//解决方案1
const obj = {
data: [1, 2, 3],
process: function() {
this.data.forEach(item => {
console.log(this); // obj
});
}
};
//解决方案2
const obj = {
data: [1, 2, 3],
process: function() {
this.data.forEach(function(item) {
console.log(this); // obj
}.bind(this));
}
};
//解决方案3
const obj = {
data: [1, 2, 3],
process: function() {
const self = this;
this.data.forEach(function(item) {
console.log(self); // obj
});
}
};
- 特殊情况的this
js
// 1. 链式调用
const calculator = {
value: 0,
add(num) {
this.value += num;
return this; // 返回 this 实现链式调用
},
multiply(num) {
this.value *= num;
return this;
}
};
calculator.add(5).multiply(2).add(3); // value = 13
// 2. 工厂函数
function createPerson(name) {
return {
name,
sayName() {
console.log(this.name);
}
};
}
// 3. 类继承
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Dog extends Animal {
speak() {
super.speak(); // 调用父类方法
console.log(this.name + ' barks.');
}
}
记住 this 指向的关键点:
- 箭头函数没有自己的 this,继承自外层作用域
- 普通函数的 this 在调用时确定
- 严格模式会影响 this 的默认值
- 可以通过 call、apply、bind 改变 this 指向
- 对象方法中的 this 指向调用该方法的对象
- 构造函数中的 this 指向新创建的对象
上面每个打印都亲自真机打印的,说实话人麻了,太复杂了,这个记住关键点的情况下还得多练,否则碰到实际情况还是一脸懵