前言
this是JavaScript中最令人困惑的概念之一,但也是最重要的概念之一。本文将通过30个题目帮助你消除对this指向问题的恐惧心理,废话不多说了,直接发车🫏🫏🫏
基础篇
题目1:全局环境中的this
javascript
console.log(this);
答案 :在浏览器中指向window
对象,在Node.js中指向global
对象
题目2:函数中的this(非严格模式)
javascript
function showThis() {
console.log(this);
}
showThis();
答案 :在非严格模式下指向window
(浏览器)或global
(Node.js)
题目3:函数中的this(严格模式)
javascript
'use strict';
function showThis() {
console.log(this);
}
showThis();
答案 :undefined
题目4:对象方法中的this
javascript
const obj = {
name: 'jjq',
greet() {
console.log(this.name);
}
};
obj.greet();
答案 :'jjq'
(指向调用方法的对象obj)
题目5:嵌套对象中的this
javascript
const obj = {
name: 'jjq',
inner: {
name: 'jiangjianqing',
greet() {
console.log(this.name);
}
}
};
obj.inner.greet();
答案 :'jiangjianqing'
(指向直接调用方法的对象inner)
进阶篇
题目6:解构方法后的this
javascript
const obj = {
name: 'jjq',
greet() {
console.log(this.name);
}
};
const { greet } = obj;
greet();
答案 :undefined
(解构后相当于普通函数调用)
题目7:回调函数中的this
javascript
const obj = {
name: 'jjq',
greet() {
setTimeout(function() {
console.log(this.name);
}, 100);
}
};
obj.greet();
答案 :undefined
(回调函数的this默认指向全局对象)
题目8:箭头函数中的this
javascript
const obj = {
name: 'jjq',
greet() {
setTimeout(() => {
console.log(this.name);
}, 100);
}
};
obj.greet();
答案 :'jjq'
(箭头函数继承外层作用域的this)
题目9:构造函数中的this
javascript
function Person(name) {
this.name = name;
}
const jjq = new Person('jjq');
console.log(jjq.name);
答案 :'jjq'
(构造函数中的this指向新创建的实例)
题目10:构造函数return对象时的this
javascript
function Person(name) {
this.name = name;
return { name: 'jiangjianqing' };
}
const jjq = new Person('jjq');
console.log(jjq.name);
答案 :'jiangjianqing'
(构造函数返回对象时,this指向被覆盖)
改变this指向篇
题目11:call方法改变this
javascript
const obj1 = { name: 'jjq' };
const obj2 = { name: 'jiangjianqing' };
function greet() {
console.log(this.name);
}
greet.call(obj1);
greet.call(obj2);
答案 :'jjq'
然后 'jiangjianqing'
(call立即调用函数并改变this)
题目12:apply方法改变this
javascript
const obj = { name: 'jjq' };
function greet(greeting) {
console.log(`${greeting}, ${this.name}`);
}
greet.apply(obj, ['Hello']);
答案 :'Hello, jjq'
(apply与call类似,但参数是数组)
题目13:bind方法改变this
javascript
const obj = { name: 'jjq' };
function greet() {
console.log(this.name);
}
const boundGreet = greet.bind(obj);
boundGreet();
答案 :'jjq'
(bind返回一个绑定this的新函数)
题目14:多次bind的this
javascript
const obj1 = { name: 'jjq' };
const obj2 = { name: 'jiangjianqing' };
function greet() {
console.log(this.name);
}
const boundGreet = greet.bind(obj1).bind(obj2);
boundGreet();
答案 :'jjq'
(bind只能绑定一次,后续bind无效)
题目15:箭头函数与bind
javascript
const obj = { name: 'jjq' };
const greet = () => {
console.log(this.name);
};
const boundGreet = greet.bind(obj);
boundGreet();
答案 :undefined
(箭头函数的this无法被bind改变)
特殊场景篇
题目16:DOM事件处理函数中的this
html
<button id="btn">Click me</button>
<script>
document.getElementById('btn').addEventListener('click', function() {
console.log(this);
});
</script>
答案:指向触发事件的DOM元素(button元素)
题目17:箭头函数作为DOM事件处理函数
html
<button id="btn">Click me</button>
<script>
document.getElementById('btn').addEventListener('click', () => {
console.log(this);
});
</script>
答案:指向外层作用域的this(通常是window)
题目18:setTimeout中的this
javascript
const obj = {
name: 'jjq',
greet() {
setTimeout(function() {
console.log(this.name);
}, 100);
}
};
obj.greet();
答案 :undefined
(回调函数中的this默认指向全局对象)
题目19:setInterval中的this
javascript
const obj = {
count: 0,
start() {
setInterval(function() {
this.count++;
console.log(this.count);
}, 1000);
}
};
obj.start();
答案 :NaN
(this指向全局对象,全局count为undefined,undefined++为NaN)
题目20:class中的this
javascript
class Person {
constructor(name) {
this.name = name;
}
greet() {
console.log(this.name);
}
}
const jjq = new Person('jjq');
jjq.greet();
答案 :'jjq'
(类方法中的this指向实例)
综合挑战篇
题目21:多层嵌套中的this
javascript
const obj = {
name: 'jjq',
outer() {
function inner() {
console.log(this.name);
}
inner();
}
};
obj.outer();
答案 :undefined
(inner作为普通函数调用,this指向全局)
题目22:方法赋值后的this
javascript
const obj1 = {
name: 'jjq',
greet() {
console.log(this.name);
}
};
const obj2 = {
name: 'jiangjianqing'
};
obj2.greet = obj1.greet;
obj2.greet();
答案 :'jiangjianqing'
(this指向调用方法的对象obj2)
题目23:立即执行函数中的this
javascript
const obj = {
name: 'jjq',
greet() {
(function() {
console.log(this.name);
})();
}
};
obj.greet();
答案 :undefined
(IIFE中的this指向全局对象)
题目24:链式调用中的this
javascript
const calculator = {
value: 0,
add(num) {
this.value += num;
return this;
},
multiply(num) {
this.value *= num;
return this;
},
getValue() {
return this.value;
}
};
const result = calculator.add(5).multiply(2).getValue();
console.log(result);
答案 :10
(每个方法都返回this,实现链式调用)
题目25:原型链中的this
javascript
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
console.log(this.name);
};
const jjq = new Person('jjq');
jjq.greet();
答案 :'jjq'
(原型方法中的this指向调用该方法的实例)
终极挑战篇
题目26:this与闭包结合
javascript
const obj = {
name: 'jjq',
tasks: ['task1', 'task2', 'task3'],
showTasks() {
this.tasks.forEach(function(task) {
console.log(`${this.name} has ${task}`);
});
}
};
obj.showTasks();
答案 :三次'undefined has taskX'
(回调函数中的this指向全局)
题目27:解决题目26的问题
javascript
const obj = {
name: 'jjq',
tasks: ['task1', 'task2', 'task3'],
showTasks() {
this.tasks.forEach(function(task) {
console.log(`${this.name} has ${task}`);
}, this); // 使用forEach的第二个参数
}
};
obj.showTasks();
答案 :三次'jjq has taskX'
(通过forEach的第二个参数绑定this)
题目28:箭头函数作为类字段
javascript
class Counter {
count = 0;
increment = () => {
this.count++;
console.log(this.count);
};
}
const counter = new Counter();
const increment = counter.increment;
increment();
答案 :1
(箭头函数类字段绑定实例this)
题目29:this与扩展运算符
javascript
const obj = {
name: 'jjq',
greet(...args) {
console.log(this.name, args);
}
};
const greet = obj.greet;
greet.call(obj, 1, 2, 3);
答案 :'jjq' [1, 2, 3]
(扩展运算符不影响this)
题目30:最复杂的this综合题
javascript
const obj1 = {
name: 'jjq',
greet() {
return () => {
console.log(this.name);
};
}
};
const obj2 = {
name: 'jiangjianqing'
};
const greet = obj1.greet();
greet.call(obj2);
答案 :'jjq'
(箭头函数的this在创建时确定,无法被call改变)
总结
好了 我先收摊