this 作为JavaScript中的一个关键字,它的复杂度很高,主要原因是它所处不同场景的代表的指向是不一样的。这里先做一个结论,重要事情说三遍:
this的指向是由上下文环境动态决定的
this的指向是由上下文环境动态决定的
this的指向是由上下文环境动态决定的
我自己是一名从事了多年开发的web前端老程序员,前段时间我花了一个月整理了一份最适合学习的web前端学习干货,各种框架都有整理,送给每一位前端小伙伴,想要获取的可以添加下面的QQ群,即可免费获取。
this指向实例场景
关于this的指向的不确定性,主要体现在如下几个应用场景中:
全局环境
普通函数调用
由call/apply/bind函数调用
对象属性方法调用
构造函数调用
箭头函数
全局环境
在全局环境中无论是否是严格模式,this 均指向全局对象,例如浏览器端的 window
// 在浏览器中, window 对象同时也是全局对象:
```javascript
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
普通函数调用
当普通的函数,直接调用的时候,一般来说分两种情况:
严格模式绑定到 undefined
非严格模式绑定到全局对象 window
```javascript
function foo(){
console.log(this);
}
function bar(){
"use strict";
console.log(this);
}
foo() // window
bar() // undefined
call/apply/bind函数调用
call/apply 这两个函数对象到方法能立即执行某个函数,并且讲函数中的this绑定到你提供到对象上去
bind 方法永久的绑定函数中的this到指定对象上,并返回一个新函数,将来这个函数无论怎么调用都可以
function foo(){
console.log(this);
}
function bar(){
console.log(this);
}
foo.call({
name:'小米'}); // {name: "小米"}
const bar1 = bar.bind({
num:123})
bar1() // {num: 123}
对象属性方法调用
作为对象属性方法调用,都指向前面调用函数都那个对象。当然有的时候会出现各种变种或者干扰的面试题
const student = {
name: "tom",
fn: function () {
return this;
},
};
console.log(student.fn() === student);
构造函数调用或者类上下文
构造函数作为JavaScript创建对象的那只大母鸡(实际上类是构造函数的语法糖),通常程序界有个段子叫做new 一个对象,谁还敢说程序员(媛)没有对象的,这种方式调用this指向的是你new出来的那个对象实例本身:
function Person(name){
console.log(this);
this.name = name
}
const p = new Person('tom')
console.log(p);
箭头函数中的this
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
var obj = {
name: "tom",
foo() {
setTimeout(() => {
console.log(this);
}, 1000);
},
};
obj.foo() // obj
面试题
常见面试题有: 1、手写bind函数
Function.prototype.mybind = function (ctx, ...args) {
const fn = this;
return function () {
fn.apply(ctx, args);
};
};
function foo(x, y) {
console.log(this, x, y);
}
const foo1 = foo.mybind({
name: "zhangsan" }, 10, 20);
foo1();
2、new 操作符调用构造函数,具体做了什么?
创建一个新的对象;
将构造函数的 this 指向这个新对象;
为这个对象添加属性、方法等;
最终返回新对象。