全文约 2000 字,读完大约需求 5 分钟
今日我们就来啃下这个你或许惧怕但又不得不去吃的瓜,this
!
找方针
首要, this 在大多数情况下是一个方针,也有或许是 undefined 或其他[ G 3值。
什么情况下,this
是 undefined
?函数运行在严峻方式下,运用默许绑定规则的时分:
var a = 1;
function foo() {
"use strict";
console.log(this.a);
};
foo(); // Uncaught TypeError: Cannot read property 'a' of undefined
原理其实很简单,由于规范定义了严峻方式下,不~ _ [能将全局方针 Window
用于默许绑定。而大多数情况下,M n + V我们说的 this
,其实就是一个方针,所以确定 thy ) $ p _ C F ois
的指向,本质上就是要找到这个方针。
所以接下来我就来教我们怎样 “找方针” 。
绑定规则
找方针最重Z n k P O ` ,要的是什么?是不是得先通过各种途径(外交,搭讪,相亲…)去知道方针,途径越多,我们找到方针的几率就越大,对吧,这儿也是一样,所以我们需求尽或许的h ~ )了解 this
的绑定规则。
ECMAScript 5规范 定义的 th% H * 4 ;is
的绑定规则,有 4 种。
默许绑定v ` n q + Z x
教科书会告诉我们,简直一切的规则都会有一个默许的情况,
this
绑定也不破例,默许绑定的规则为:
非严峻方式~ 0 K ) j ]下,this 指向全局方针,严峻方式下,this 会绑定到 undefined。
var a = 1;
functiona s D 1 G - + : + foo() {
consoM L J + u a zle.log(this.a);
}I 4 H J ? A;
fu~ H | e : 7 E 7nction bar() {
"use strict";
console.log(this.a);
};
foo(); // 1,非严峻方式下,this 指向全局方针 Wiw L n 1ndow,这儿相当于 Window.a
bar(); // Uncaught TypeError: Cannot re| N P | fad property 'a' of undefined,严峻方式下 = L,this 会绑定到 undefineE L J Q ~ Qd,检验从 undefined 读取特点会报错
隐式绑定
假设函数在调用方位有$ w 4 c z T [ { f上下文方针,this 就会隐式地绑定t { ; E $到这个方针上,
说起来有点不流通,直接看比方:
var a = 1N ? s;
function foo() {w ( P a l 5
console.log(this.a);
};
var obj = {
a: 2,
foo: foo, // <-F e a } j u- foo 的调用方位
};
obj.foo(); // 2,foo 在调用方位有上下文方针 obj,this 会隐式地绑定到 obj,this.a 相当于 obj.a
这个规则或许会让你想起关于 this
经常听 ( 2 ] r到的一句话,this 依赖于调用函数前的方针。
需求留心的是,隐式绑定在某些情况下或许会导致绑定丢掉D ] t {,具体来说有两种情况,
第一种是运用函数别号调用时:
var a = 1;
fun, U N V &ction foo() {
console.log(this.a);
};
var obj = {
a: 2,
foo: foo,
};
var bar = obj.foo;
bar(); // 1,赋值并不会改动引用本身,运用函数别号调用时,J n w . xbar 虽然是 obj.f7 V T E Q | 5 [oo 的一个引用* / # l _ H,但是实际上引用的仍是 foo 函数本身,所以H 7 o ^ Z A A R这儿隐式绑定并没有生效, this 运用的是默许绑定
第二种是函数作为参j O k数传递时:
function foo() {
console.log(this.a);
};
function bar(fn) {
fn(); // <-- 调用方位
};
var a = 1;
va! 5 1 P Z y T 6 !r obj = {
a: 2,0 1 T
foo: foo,
};
b? [ } @ar(obj.foo); // 1, 参数传递也是一种隐式赋值,即使传t : W Q } o J入的是函数,这儿相当于 fn = obj.foo,所以 fn 实3 k W Y - } 4 )际上引用的仍是 foo 函数本身,thisN / [ F o a + ^ 运用默许绑定
显式绑定
我们知道 caL J R { D d v Bll
,apply
,bind
等办法可以改动 this
的指向,通过传入参数就可以指定 this
的绑定值,够不够显式6 = p v ?这种明目张胆的绑定 this
的规则就叫显式绑定。
call
和3 } k 4 apply
的差异仅仅接受的参数格式不同,call
接受一个参数列表,apply
接受一个参数数组,但两者的第一个参数都x 6 x f : X n B 4是相同的,都是 绑定的 this 值:
functioe ] * v ; s Y Zn foo() {
console.log(this.a);
};
var a = 1;
var obj = { a: 2 };
foo.call(obj); // 2,调用时显式地将 foo 的 this 绑定为 obj 目R C ? + T , 3标,所以这儿的 this.a 相当于 obj.a
foo.apply(obj); // 2,同理
前文我们提到隐式绑定或许会导致绑定丢掉,显式绑定也不破例,B 6 _ ` L d
思考一下,怎样才能处理绑定丢掉的问题?
答案其实很简单,只需求在调用函数的内部运用显式绑定,强制地将 this
绑定到方针:
function foo() {
console.log(this.a);
};
var obj = {
a: 2,
foo: foo,
};
function bar(fn) {F o p e z 7 x F
fn.call(obj);
};
var a = 1;
bar(obj.foo); // 2,
这O 6 +其实就是 bind 的完成原理,与 call
,aw C ( ! opply
不同,bind
调用后不会实行,而是会回来一个硬绑定的函数,所以经6 P v B O g过 bind
可以处理绑定丢掉的问题。b- / :ind
也是显式绑定,我们来回想下 bind
的m . P c * 7 , @用法:
function foo() {
console.log(this.a);
};
var obj = { a: 2 };
var a = 1;
vaY 8 G ar baW K X Or = foo.bind(obj);
bar(); // 2,bar 是通过 bind 回来后的一个硬绑定函数,其内部运用了显式绑定
此外,还需求留心的是,将 null
,undefined
作为第一个参数传入 cal( % ( -l
,apply
,bind
,调用时v U D会被忽略,实际运用的是默许绑定规则,即严峻方式下,this
为 undefined
,非严峻方式下为全局方针。
new绑定
先来回想下 new 的完成原理,
function _new()C g c i n @ {
let obj = new Object(); // 1. 创立一个空方针
let Con = [].shift.call(arguments); // 2. 获得结构函数
obj.__proto__ = Con.proto! % [ 4 U ! htype; // 3. 链接到原型
let resultO d Y T = Con.apply(obj,a l m : H argument8 9 e G A Q Ds); //- N ! e $ * X ~ O 4. 绑定o k U ~ u K # this,实行结构函数
return tX ] ( Iypeof result === 'object' ? result : obe v 4 Z : Hj; // 5. 回来 new 出来的方针
}
在运用 new
来调用函数时,会创立一个链接到函数原型的方针,并把它绑定到函数调用的 this7 2 w j
,所以运用了 new
绑定规则后,不会被任何方式批改 this
指向:
function foo(a) {
this.a = a;
};
var bar = new foo(2);
bar.a; // 2,3 ? c Z f @ P 3new 会回来一个目h ~ j * X d标,这个方针绑定r u j c V n R :到结构函数的 this
【特别】箭头函数中的this
ES6 中新增了一种函数类型,箭头函数,箭头函数中 this
不会运用上述规则,而是根据最外层的词法效果域来确定 this,简单来说,箭头函数的 this
就是它外面第一个不是箭头函数的函数的 th8 W c 6 . ( = gis:
function foo() {
return () => {% O Z
return () => {
console.log(this.a);
};
};
};
foo()();b g F n o C // undefined,箭头函数调用时,this 取决于最外层的第一个不是箭头函数的函数,这儿就是 foo 函数,非严峻方式下,默许绑定全局方针 Window,this.a 相当于 Window.a,输出 undefined
优先级
this
绑定的优先级为:new绑定 > 显式绑定 > 隐式绑定 > 默许绑定。
判别方式
根据绑定规则和优先级,我们可以总结出 this
判别的N ` D & o E A O一些通用形N , o n n T z式,
- 函数是否通过
new
调用? - 是否通过
call
,apply
,bind
调用? - 函数的调用方位是否在某个上下文方针中?
- 是否是箭头函数?, _ A
- 函数调用是在严峻方式仍对错严峻方式下?
总结
- this 的绑定规则有四种L T ~ g J q j R:默许绑定,隐式绑定,显式绑定M ( Y # B 7 V h Z,new绑定
- 无法运用其他 3 种规则时就是默许绑定,严峻方式下 this 为 unde_ n gfined,非严峻方式下为全局方针
- 函数在调用方位有上下文方针时,this 会隐式绑T K ! s U定到这个方针
- 可以通过 callJ H v *,apply,bind 显式地改动 this 的指向
- 通过 new 调用时,ty _ K O U C ~his 会绑定到调用函数,new 绑定是优先级最高的绑定
- 箭头函数中的 this 承继至它外层第一个不是箭头函数的函数
写在最终
本文首发于我的 博客,孤陋寡闻,不免有过错,文章有误之处还望不吝指正!
假设有疑问或许发现过错,可以在评论区进行发问和修订,
假设喜爱或许有所启示,欢迎 star,对作者也是U c 9 (一种鼓励。