this的四种绑定规则总结
一、默认绑定
1、全局环境中,this默认绑定到window
2、函数独立调用时,this默认绑定到window
console.log(this === window);//true
function foo(){
console.log(this === window);
}
foo(); //true
3、被嵌套的函数独立调用时,this默认绑定到window
var a = ;
var obj = {
a : ,
foo:function(){
function test(){
console.log(this.a);
}
test(); //虽然test()函数被嵌套在obj.foo()函数中,但test()函数是独立调用,而不是方法调用。所以this默认绑定到window
}
}
obj.foo();//
4、IIFE立即执行函数实际上是函数声明后直接调用执行
var a = ;
function foo(){
(function test(){
console.log(this.a);
})()
};
var obj = {
a : ,
foo:foo
}
obj.foo();//0 //等价于上例3
var a = ;
var obj = {
a : ,
foo:function(){
function test(){
console.log(this.a);
}
test();
}
}
obj.foo();//
5、【闭包】类似地,test()函数是独立调用,而不是方法调用,所以this默认绑定到window
var a = ;
function foo(){
function test(){
console.log(this.a);
}
return test;
};
var obj = {
a : ,
foo:foo
}
obj.foo()();//0,实际上就是test()方法独立调用,所以this是window
闭包里面this重定向:由于闭包的this默认绑定到window对象,但又常常需要访问嵌套函数的this,所以常常在嵌套函数中使用var that = this,然后在闭包中使用that替代this,使用作用域查找的方法来找到嵌套函数的this值
var a = ;
function foo(){
var that = this;
function test(){
console.log(that.a);
}
return test;
};
var obj = {
a : ,
foo:foo
}
obj.foo()();//
obj.foo()是obj对象的foo方法的调用,所以里面的this指向obj,用that来重定向this使that指向obj,然后obj.foo()()实际上就是test()方法独立调用,但是是that.a,此时that已经指向了obj,所以是2
二、隐式绑定
一般地,被直接对象所包含的函数调用时,也称为方法调用,this隐式绑定到该直接对象
function foo(){
console.log(this.a);
};
var obj1 = {
a:,
foo:foo,
obj2:{
a:,
foo:foo
}
}
//foo()函数的直接对象是obj1,this隐式绑定到obj1
obj1.foo();//1
//foo()函数的直接对象是obj2,this隐式绑定到obj2
obj1.obj2.foo();//
隐式丢失
隐式丢失是指被隐式绑定的函数丢失绑定对象,从而默认绑定到window。这种情况容易出错却又常见
1、【函数别名】
var a = ;
function foo(){
console.log(this.a);
};
var obj = {
a : ,
foo:foo
}
//把obj.foo赋予别名bar,造成了隐式丢失,因为只是把foo()函数赋给了bar,而bar与obj对象则毫无关系
var bar = obj.foo;
bar();//0 //等价于
var a = ;
var bar = function foo(){
console.log(this.a);
}
bar();//
2、【参数传递】
var a = ;
function foo(){
console.log(this.a);
};
function bar(fn){
fn();
}
var obj = {
a : ,
foo:foo
}
//把obj.foo当作参数传递给bar函数时,有隐式的函数赋值fn=obj.foo。与上例类似,只是把foo函数赋给了fn,而fn与obj对象则毫无关系
bar(obj.foo);//
//等价于
var a = ;
function bar(fn){
fn();
}
bar(function foo(){
console.log(this.a);
});
3、【内置函数】内置函数与上例类似,也会造成隐式丢失
var a = ;
function foo(){
console.log(this.a);
};
var obj = {
a : ,
foo:foo
}
setTimeout(obj.foo,);//0 //等价于
var a = ;
setTimeout(function foo(){
console.log(this.a);
},);//
因此,内置函数里也常常需要 this 重定向
4、【间接引用】函数的"间接引用"一般都在无意间创建,最容易在赋值时发生,会造成隐式丢失
function foo() {
console.log( this.a );
}
var a = ;
var o = { a: , foo: foo };
var p = { a: };
o.foo(); // 3
//将o.foo函数赋值给p.foo函数,然后立即执行。相当于仅仅是foo()函数的立即执行
(p.foo = o.foo)(); //
要与下面这种情况进行区分:
function foo() {
console.log( this.a );
}
var a = ;
var o = { a: , foo: foo };
var p = { a: };
o.foo(); // 3
//将o.foo函数赋值给p.foo函数,之后p.foo函数再执行,是属于p对象的foo函数的执行
p.foo = o.foo;
p.foo();//
5、【其他情况】
在javascript引擎内部,obj和obj.foo储存在两个内存地址,简称为M1和M2。只有obj.foo()这样调用时,是从M1调用M2,因此this指向obj。但是,下面三种情况,都是直接取出M2进行运算,然后就在全局环境执行运算结果(还是M2),因此this指向全局环境
var a = ;
var obj = {
a : ,
foo:foo
};
function foo() {
console.log( this.a );
}; (obj.foo = obj.foo)();// (false || obj.foo)();// (, obj.foo)();//
三、显式绑定
通过call()、apply()、bind()方法把对象绑定到this上,叫做显式绑定。对于被调用的函数来说,叫做间接调用
var a = ;
function foo(){
console.log(this.a);
}
var obj = {
a:
};
foo();//
foo.call(obj);//
普通的显式绑定无法解决隐式丢失问题
1、【硬绑定】硬绑定是显式绑定的一个变种,使this不能再被修改
var a = ;
function foo(){
console.log(this.a);
}
var obj = {
a:
};
var bar= function(){
foo.call(obj);
}
//在bar函数内部手动调用foo.call(obj)。因此,无论之后如何调用函数bar,它总会手动在obj上调用foo
bar();//
setTimeout(bar,);//
bar.call(window);//
2、【API】javascript中新增了许多内置函数,具有显式绑定的功能,如数组的:map()、forEach()、filter()、some()、every()
var id = 'window';
function foo(el){
console.log(el,this.id);
}
var obj = {
id: 'fn'
};
[,,].forEach(foo);//1 "window" 2 "window" 3 "window"
[,,].forEach(foo,obj);//1 "fn" 2 "fn" 3 "fn"
四、new绑定
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。对于this绑定来说,称为new绑定
1、构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回。在这种情况下,构造函数调用表达式的计算结果就是这个新对象的值
function fn(){
this.a = ;
}
var test = new fn();
console.log(test);//{a:2}
2、如果构造函数使用return语句但没有指定返回值,或者返回一个原始值,那么这时将忽略返回值,同时使用这个新对象作为调用结果
function fn(){
this.a = ;
return ;
}
var test = new fn();
console.log(test);//{a:2}
3、如果构造函数显式地使用return语句返回一个对象,那么调用表达式的值就是这个对象
var obj = {a:};
function fn(){
this.a = ;
return obj;
}
var test = new fn();
console.log(test);//{a:1}
【注意】尽管有时候构造函数看起来像一个方法调用,它依然会使用这个新对象作为this。也就是说,在表达式new o.m()中,this并不是o,而是新对象
var o = {
m: function(){
return this;
}
}
var obj = new o.m();
console.log(obj,obj === o);//{} false
console.log(obj.constructor === o.m);//true
var o = {
m: function(){
this.a = ;
return this;
}
}
var obj = new o.m();
console.log(obj,obj === o);//o.m {a: 2} false
console.log(obj.constructor === o.m);//true
五、严格模式
1、严格模式下,独立调用的函数的this指向undefined
function fn(){
'use strict';
console.log(this);//undefined
}
fn();
function fn(){
console.log(this);//window
}
fn();
2、在非严格模式下,使用函数的call()或apply()方法时,null或undefined值会被转换为全局对象。而在严格模式下,函数的this值始终是指定的值
var color = 'red';
function displayColor(){
console.log(this.color);
}
displayColor.call(null);//red var color = 'red';
function displayColor(){
'use strict';
console.log(this.color);
}
displayColor.call(null);//TypeError: Cannot read property 'color' of null
this的四种绑定规则:默认绑定、隐式绑定、显式绑定和new绑定,分别对应函数的四种调用方式:独立调用、方法调用、间接调用和构造函数调用。分清这四种绑定规则不算难,比较麻烦的是需要练就火眼金睛,识别出隐式丢失的情况。
说到底,javascript如此复杂的原因是因为函数过于强大。因为,函数是对象,所以原型链比较复杂;因为函数可以作为值被传递,所以执行环境栈比较复杂;同样地,因为函数具有多种调用方式,所以this的绑定规则也比较复杂。只有理解了函数,才算理解了javascript。
this的四种绑定规则总结的更多相关文章
- 深入理解this机制系列第一篇——this的4种绑定规则
× 目录 [1]默认绑定 [2]隐式绑定 [3]隐式丢失[4]显式绑定[5]new绑定[6]严格模式 前面的话 如果要问javascript中哪两个知识点容易混淆,作用域查询和this机制绝对名列前茅 ...
- JS中this的4种绑定规则
this ES6中的箭头函数采用的是词法作用域. 为什么要使用this:使API设计得更简洁且易于复用. this即不指向自身,也不指向函数的词法作用域. this的指向只取决于函数的调用方式 thi ...
- this的四种绑定形式
一 , this的默认绑定 当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象. 一个例子 function fire ...
- this四种绑定方式之间的奇淫技巧
写在前面 上一篇中,我们对于JavaScript中原始值.复杂值以及内存空间进行了一个深入浅出的总结,这次我们来聊一聊JavaScript中this关键字的深入浅出的用法. 在 JavaScript ...
- ASP.NET Eval四种绑定方式
1.1.x中的数据绑定语法 <asp:Literal id="litEval2" runat="server" Text='<%#DataBinde ...
- 【javascript】函数中的this的四种绑定形式
目录 this的默认绑定 this的隐式绑定 隐式绑定下,作为对象属性的函数,对于对象来说是独立的 在一串对象属性链中,this绑定的是最内层的对象 this的显式绑定:(call和bind方法) n ...
- 【javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~
javascript中的this和函数息息相关,所以今天,我就给大家详细地讲述一番:javascript函数中的this 一谈到this,很多让人晕晕乎乎的抽象概念就跑出来了,这里我就只说最 ...
- Android studio button 按钮 四种绑定事件的方法
package com.geli_2.sujie.sujiegeili2testbutton; import android.os.Bundle; import android.support.v7. ...
- ASP.NET Eval四种绑定方式 及详解
1.1.x中的数据绑定语法 <asp:Literal id="litEval2" runat="server" Text='<%#DataBinde ...
随机推荐
- hdu 3717 二分+队列维护
思路:已知当前的总长度和为len,当前的伤害为sum,伤害次数为 num.那么对下一个点的伤害值sum=sum+2*len+num: 这个是通过(x+1)^2展开化简就能得到. #include< ...
- BZOJ1877 [SDOI2009]晨跑 【费用流】
题目 Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他 坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十字路口和M条街道 ...
- bzoj 3160 万径人踪灭 FFT
万径人踪灭 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1936 Solved: 1076[Submit][Status][Discuss] De ...
- Springboot-plus 安装使用的一些问题
最近在研究一些springboot的框架,然后看到了这个款 springboot plus ,下载下来研究下. 将安装部署的一些问题记录下来了. 第一个,就是部署的时候,我使用的MySQL数据库,导 ...
- glance总结
Openstack将glance独立出来的一个原因是尽可能将镜像存储至多种存储上,由glance提供一个完整的适配框架.现在支持亚马逊对象存储S3.openstack自有的swift对象存储,以及常用 ...
- 全自动google检索后台
是不是每天为了找后台,伤破了蛋,每次在google输入”site:www.xxx.com intitle:登陆”.是不是手都累麻了,无聊又浪费时间.有了它,你的蛋就不用在碎了 直接上源码 1 2 3 ...
- 理想中的SQL语句条件拼接方式
背景 Orm用过一些,但处理增删改上面做的都不错.但是查询上跟我想要的效果总是差了一点.我想要的效果则是这样,基于某种命名规则进行传参,后台解析器知道命名规则即可知道它要查询什么样的数据. 谈谈我之前 ...
- mysql server5.7 找不到my.ini,只有my-default.ini【mysql全局配置文件】
起因是在尝试将csv文件导入mysql的table时,出现如下错误: “The MySQL server is running with the --secure-file-priv option s ...
- WPF中的URI
在 Windows Presentation Foundation (WPF) 中,使用统一资源标识符 (URI) 标识和加载文件的方式有很多,包括: 指定当应用程序第一次启动时显示的用户界面 (UI ...
- Use NSArray to specify otherButtonTitles?
http://stackoverflow.com/questions/1602214/use-nsarray-to-specify-otherbuttontitles UIAlertSheet's c ...