下一篇:《你不知道的javascript》笔记_对象&原型javascript
上一篇博客咱们知道词法做用域是由变量书写的位置决定的,那this
又是在哪里肯定的呢?如何可以精准的判断this
的指向?这篇博客会逐条阐述java
书中有这样几句话:segmentfault
this
是在运行时进行绑定的,并非在编写时绑定,它的上下文取决于函数调用时的各类条件
this
的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式当一个函数被调用时,会建立一个活动记录(有时候也称为执行上下文)。这个记录会包含函数在哪里被调用(调用栈)、函数的调用方法、传入的参数等信息。this 就是记录的其中一个属性,会在函数执行的过程当中用到。闭包
关于执行上下文,能够参考《javascript高级程序设计》笔记:内存与执行环境app
最经常使用的函数调用类型——独立函数调用,使用的即为默认绑定规则,在非
strict mode
下,this指向全局对象
function foo1() { console.log(this.a); } var a = 10; foo1(); // 10 // 即便函数嵌套比较深 function foo2() { foo1(); } function foo3() { foo2(); } foo3();
固然,咱们实际使用中,难以判别的并非直接型的默认绑定模式,而是隐式绑定丢失型的默认绑定(下面会着重说明)函数
调用的位置是否有上下文对象,或者说被某个对象拥有或包含
// 基本形式 function foo() { console.log(this.a); } var obj = { a: 10, foo }; obj.foo(); // 10
隐式绑定中的几个雷区:oop
1. 多个对象嵌套引用时,只有最后一层在调用位置中起做用this
function foo() { console.log(this.a); } var obj2 = { a: 42, foo }; var obj1 = { a: 10, obj2 }; obj1.obj2.foo(); // 42
2.【隐式丢失】当调用函数被从新赋值为新变量,调用新变量时this
指向会有不一样prototype
// 共用部分 function foo(){ console.log(this.a); } var obj = { a: 10, foo }; var a = 'opps, global'; // 直接赋值 var bar = obj.foo; bar(); // 'oops, global' // 回调间接赋值1 function doFoo(fn) { fn(); } doFoo(obj.foo); // 'oops, global' 至关于间接赋值 // 回调间接赋值2 setTimeout(obj.foo, 100); // 'oops, global' 内置的setTimeout也至关于间接赋值
经典综合案例:设计
var length = 10; function fn(){ console.log(this.length); } var obj = { length: 5, method: function (fn) { fn(); arguments[0](); } }; obj.method(fn, 123);
分析:fn()
为函数fn
的引用,默认绑定,指向全局;arguments[0]();
至关于下面的引用,数据隐式绑定,绑定对象为arguments
,其属性length
值为参数数量2
arguments: { '0': function fn(){ console.log(this.length); } }
答案:10 2
call()
/apply()
/bind()
可以显式修改this
指向
经过上述方法调用的方式为显示绑定,它们第一个参数是一个对象,在调用函数时,绑定在this
中。
关于三者的基本用法和说明在以前博客《javascript高级程序设计》函数调用模式 & this深度理解中已做说明,在此不作唠述
两点注意:
1. 经过显式绑定的不能再修改它的this
指向
function foo() { console.log(this.a); } var obj = { a: 2 }; var bar = function() { foo.call(obj); } bar(); // 2 setTimeout(bar, 200); // 2 bar.call(window); // 2
2. 将null
/undefined
做为第一个参数时,调用会忽略这些值,采用默认绑定规则
function foo() { console.log(this.a); } var a = 2; foo.call(null); // 2
new
绑定使用关键字new
执行函数,当函数无返回值或返回值非对象时,this
指向为实例对象
new
关键字执行函数流程:
this
上须知:构造函数与普通函数无异,做为区分,咱们通常讲经过new
调用的函数称为构造函数,并大写第一个单词。全部函数都可由关键字new
调用
function foo(a) { this.a = a; } var bar = new foo(2); console.log(bar.a); // 2
new
绑定 --> 显式绑定 --> 隐式绑定 --> 默认绑定
new
绑定】函数是否在new
中调用?若是是,this
绑定的是新建立的对象call
/aplly
/bind
中调用?若是是,this
绑定的是指定对象this
绑定到那个上下文对象this
绑定严格模式下为undefined
,非严格模式下为全局对象this
ES6中箭头函数不使用上面this
的四种标准规格,而是根据外层(函数或者全局)做用域来决定this
指向
下面是一个普通函数和箭头函数的对比:
function foo1() { setTimeout(() => { console.log(this.a) }, 100) } function foo2() { setTimeout(function() { console.log(this.a) }, 100) } var a = 10; var obj = { a: 2 }; foo1.call(obj); // 2 箭头函数this指向外层(obj) foo2.call(obj); // 10 隐式丢失,默认绑定
【利用闭包】理解箭头函数中的this
:
// 上例中的箭头函数至关于 function foo1() { var self = this; setTimeout(function() { console.log(self.a) }, 100) }