作为一个 js 菜鸡的我而言,在之前讲到过那么多的 js 链式查找机制,比如说原型链,作用域链等等,想当然的把这个机制带入到了 this 指向上边,结果就是这个 this 指向指的我万脸懵逼(标题换字了,担心被河蟹), 在经过漫长的通(gou)俗(pi)易(bu)懂(tong)的 ECMAScript 规范阅读之后,分享一下我所认知的 this 指向
简而言之,js 中 this 的指向不是在函数定义的时候确定的,而是在调用的时候创建阶段确定的,也就是说 this 指向谁,完全取决于函数的调用方式
常见的几种调用方式
- 直接调用,比如说
function a() {
console.log(this);
}a();
这个例子里边 this 指向的是全局对象,在客户端的全局对象是 window 对象,在 node 中的全局对象是 global 对象
(function a() {function b() {console.log(this);
}
b()})()
直接调用指的是直接用函数名称后边加()执行调用的函数,无论是否在全局作用域
-
间接调用
const obj ={
name:'obj 对象', a(){console.log(this) }
}
obj.a()
如图
在图中我们可以看到我们在对象里边调用对象里边的方法的时候,this 指向的是 obj 对象,
或者说外边有一个函数 然后给一个 obj 对象的属性赋值
const obj ={
name:'obj 对象',
a(){console.log(this)
}
}
obj.a()
obj.b=function(){console.log(this,'b')
}
obj.b()
打印的结果都是 obj 对象
- new 调用
当我们他用过 new 创建一个新的对象的时候,new 会调用这个构造函数来创建一个对象,那么这个对象里边的 this 是这个被 new 的函数调用的,那么自然 new 调用的时候,this 就是指向这个新对象的
function A(data) {this.data = data;}
class B{constructor(data){this.data = data}
}
let a = new A("A");
let b = new B("B");
console.log(a.data);
console.log(b.data);
如图
这个 new,在创建对象的时候做了什么,我们会在下一篇博客里边仔细说明
- 箭头函数中的 this
箭头函数可以理解成是是一个语法糖,他没有自己的 this 绑定,箭头函数中使用的 this 是包含他的那个函数的 this
比如说
const obj = {a() {return () => {console.log(this);
};
}
}
上边这段代码被转译成 es5 的时候如下
const obj = {a: function a() {
var _this = this;
return function () {console.log(_this);
};
}
};
综合以上所有的代码,得出一个结论就是,在 js 中 this 的绑定正常来讲是指向调用这个方法的对象来确定的,当然还有一些不正常的方法,可以改变 this 的指向
注意,下边介绍的几种方法,不能改变箭头函数的 this 指向,箭头函数本身是没有 this 绑定的,在介绍完不正常的情况后,再来说一说那些能够改变 this 指向的方法
ECMAScript 5.1 规范的 this 指向
js 中 this 的绑定正常来讲是指向调用这个方法的对象来确定的
这句话在理论上是这么讲,在工作中正常的调用的话,这个理论是没有毛病的,在 ECMAScript 5.1 的规范里边规定,在 js 里边分为语言类型和规范类型
- 语言类型
ECMAScript 里边的语言类型规定的是我们可以直接操作的一些类型,比如 string number,object 等等这些
- 规范类型
规范类型 ECMAScript 里边指的是一种抽象的规范,他们并不是让我们用来进行操作的,二是用来描述一些行为或者逻辑的,比如说 typeof delete 等等
ECMAScript 5.1 里边的 this 规定大概讲就是这样的,每个对象里边有一个 Reference 规范类型,this 会根据 Reference 这个规范类型进行赋值
ECMAScript 5.1
规范奉上 Reference 这个东西大家简单的理解成是()前边的那一块就好了,上边我们讲的那些正常的就是说左边是
- 函数定义表达式
- 属性访问表达式
- 对象创建表达式
- 属性创建表达式
这几种情况,在这几种情况的时候上边那句话是成立的
但是如果不是这上边的那几句话的时候,比如说括号里边是一个和函数相关计算或者一个运算符等等
这个时候 this 会指向 undefined,这个时候在非严格模式的情况下会被隐式转换成 window 对象
var value = 1;
var obj = {
value: 2,
a() {return this.value;}
}
console.log(obj.a());
console.log((obj.a)());
console.log((obj.a = obj.a)());
console.log((false || obj.a)());
console.log((obj.a, obj.a)());
记得之前看到过这个一个例子,运行结果如图
时间关系就说这些,下一篇博客会说 new 在运行时候过程和改变 this 指向的一些方法,
以上是我对 this 指向的一些认识,有不足的地方希望之处