2.2 .this的绑定规则

2.this的绑定规则

1.默认绑定

1 function foo(  )
2 {
3    console.log(this.a);
4 }
5 var a=1;
6 foo();  //1

在代码中,foo()函数不带任何修饰的引用进行调用的,那么只能使用默认绑定。


2.隐式绑定

1 function foo1()
2 {
3    console.log( this.a );
4 }
5 var obj = {
6    a: 1,
7    foo: foo1
8 };
9 obj.foo();  //1


调用位置使用obj上下文来引用函数foo2,故可以说函数被调用时obj对象“拥有”或“包含”该函数foo2()。
那么foo2函数被调用时,确实加上了对obj的引用。当函数引用有上下文对象时,
隐式绑定规则会把函数调用中的this绑定到这个上下文对象。
故上文中的this.a等同于obj.a。


PS1:对象属性引用链中只有上一层或者最后一层在调用位置中起作用。

 1 function foo2()
 2 {
 3    console.log( this.a );
 4 }
 5 var obj2 = {
 6    a: 2,
 7    foo: foo2
 8 };
 9 var obj1 = {
10    a: 3,
11    obj2: obj2
12 };
13 obj1.obj2.foo();    //2


距离this最近的对象上下文时obj2,故this.a等同与obj2.a,同时等同于obj1.obj2.a。


PS2:隐式丢失

 1 function foo3()
 2 {
 3    console.log( this.a );
 4 }
 5 var obj3 = {
 6    a: 33,
 7    foo: foo3
 8 };
 9 var bar=obj3.foo;
10 var a=3;
11 bar();  //3


这里的要点就是关注var bar=obj3.foo;
虽然bar只是obj3.foo的一个引用,但bar实际引用的时foo3()函数本身。
因此此时的bar()其实是一个不带任何修饰的函数调用,所以应用默认绑定。


PS2:隐式丢失(发生在函数调用时)。

 1 function foo4(  )
 2 {
 3    console.log(this.b);
 4 }
 5 function doFOO( fn )
 6 {
 7    var b=44;
 8    fn();
 9 }
10 var obj4={
11    b:10,
12    foo:foo4
13 };
14 var b=4;
15 doFOO(obj4.foo);    //4


参数传递其实就是一个隐式赋值,故传入函数也会被隐式赋值。
所以结果与上面例子一致。
同理,这里传入的是自定义函数。即使传入的是内置函数,结果也是一样的。


PS3:如上所见,回调函数丢失this绑定是很常见的。
与此同时,另一种丢失情况更加出人意料:调用回调函数可能会修改this。
在一些流行的js库中,事件处理器经常会把回调函数的this绑定到DOM元素上。



3.显式绑定
显式绑定,即是通过call,apply等方法来强制绑定。
call与apply的第一个参数都是thisObj,表示this的指向。第二个参数,call是输入单个参数,apply是输入参数数组。多个参数时,后者性能更优。

1 function foo()
2 {
3    console.log( this.a );
4 }
5 var obj = {
6    a: 3
7 };
8 foo.call( obj );   //2     函数没有参数输入时,call只需要一个参数thisObj输入。


通过foo.call(),可以在调用foo时强制把它的this绑定到obj上。

PS1:“装箱”
如果thisObj参数传入的是一个原始值(简单数据类型),这个原始值会被转换成它的对象形式(如new String(..),new Boolean(..),或者new Number(..))。这通常称为“装箱”。

PS2:解决之前提出的丢失绑定问题。
1.硬绑定(显式绑定的一个变种)

 1 function foo2()
 2 {
 3    console.log( this.a );
 4 }
 5 var obj2 = {
 6    a: 3
 7 };
 8 var bar = function()
 9 {
10    foo2.call( obj );
11 };
12 bar();  //3
13 setTimeout( bar, 100 ); //3
14 
15 //切记,硬绑定的bar不可能在修改它的this。
16 bar.call( window );   //3


硬绑定的典型应用场景就是创建一个包裹函数,负责接收参数并返回值;
另一个使用方法就是创建一个可以重复应用的辅助函数:

 1 function foo3( something )
 2 {
 3    console.log( this.d, something );
 4    return this.d   something;
 5 }
 6 function bind( fn, obj )
 7 {
 8    return function()
 9    {
10       return fn.apply( obj, arguments );
11    };
12 }
13 var obj3 = {
14    d: 2
15 };
16 var bar3 = bind( foo3, obj3 );
17 var e = bar3( 3 );  //2 3
18 console.log( e ); //5


由于硬绑定是一个非常常用的模式,故ES5提供了一个内置方法bind,和上述用法类似。

 1 function foo4( something )
 2 {
 3    console.log( this.a4, something );
 4    return this.a4   something;
 5 }
 6 var obj4 = {
 7    a4: 2
 8 };
 9 var bar4 = foo4.bind( obj4 );
10 var b4 = bar4( 5 ); //2 5
11 console.log( b4 );    //7


bind(..)会返回一个硬编码的新函数(切记,新函数),这会将指定的参数设置为this的上下文并调用原始函数。

2.API调用的“上下文”
第三方库的许多函数,以及JS语言和宿主环境(如浏览器环境)中许多内置函数,都提供了一个可选参数,通常称为“上下文(context)。
其作用与bind(..)类似,确保回调函数使用指定的this。

 1 function foo5( el )
 2 {
 3    console.log( el, this.id );
 4 }
 5 var obj5 = {
 6    id: "awesome"
 7 };
 8 
 9 //调用foo5(..)函数是将this绑定到obj。
10 [ "1", 2, 3 ].forEach( foo5, obj5 );    //console.log输出数字和字符串时,数字在前,字符串会有双引号;反之则没有。
11 // 1 awesome; 2 awesome; 3 awesome

 

4.new绑定
在此先纠正js中new与其他语言中new的区别。
在其它面向类语言中,”构造函数“是类中的一些特殊方法,使用new 初始化类时调用类中的构造函数。
在JS中,构造函数只是一些使用new操作符时被调用的函数。它们不属于某个类,也不会实例化一个类。

JS中使用new来调用函数,或者说发生构造函数调用时,会自动执行以下操作。
  1.创建(或者说构造)一个全新的对象。
  2.这个新对象会被执行[[Prototype]]链接。
  3.这个新对象会绑定到函数调用的this。
  4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

1 function foo( a )
2 {
3    this.a = a;
4 }
5 var bar = new foo( 4 );
6 console.log( bar.a );
7 
8 //使用new来调用foo(..)时,会构建一个新对象并将它绑定到foo(..)调用的this上,并将该对象返回给bar。

 







更多专业前端知识,请上 【猿2048】www.mk2048.com

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363285.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flink学习(二)Flink中的时间

摘自Apache Flink官网 最早的streaming 架构是storm的lambda架构 分为三个layer batch layerserving layerspeed layer一、在streaming中Flink支持的通知时间 Flink官网写了个了解streaming和各种时间的博客 https://www.oreilly.com/ideas/the-world-beyond-batch-streaming-1…

RSS阅读器使用:ROME,Spring MVC,嵌入式Jetty

在这篇文章中,我将展示一些创建Spring Web应用程序的准则,使用Jetty以及使用名为ROME的外部库运行RSS来运行它。 一般 我最近创建了一个示例Web应用程序,充当RSS阅读器。 我想检查ROME以阅读RSS。 我还想使用Spring容器和MVC创建最简单的视图…

HZOJ string

正解炸了…… 考试的时候想到了正解,非常高兴的打出来了线段树,又调了好长时间,对拍了一下发现除了非常大的点跑的有点慢外其他还行。因为复杂度算着有点高…… 最后正解死于常数太大……旁边的lyl用同样的算法拿了90分我却拿了个暴力的分40……

Unity3D入门其实很简单

在上次发布拙作后,有不少童鞋询问本人如何学习Unity3D。本人自知作为一名刚入门的菜鸟,实在没有资格谈论这么高大上的话题,生怕误导了各位。不过思来想去,决定还是写一些自己的经验,如果能给想要入门U3D的您一些启发&a…

4. HTML表单标签

表单是网页中最常见的元素,也是用户和我们交互的重要手段,在网站中的登录、注册、信息更新这些功能都是依赖表单实现的。在HTML中对于表单提供了一系列的标签,即输入框、下拉框、按钮、文本域,如下是一个最常见的表单结构内容&…

Java 8默认方法可能会破坏您的(用户)代码

乍一看, 默认方法为Java虚拟机的指令集带来了一个很棒的新功能。 最后,库开发人员能够开发已建立的API,而不会对其用户代码造成不兼容性。 使用默认方法,当将新方法引入该接口时,任何实现库接口的用户类都会自动采用默…

ADO.NET之使用DataSet类更新数据库

1.首先从数据库获得数据填充到DataSet类,该类中的表和数据库中的表相互映射。 2.对DataSet类中的表进行修改(插入,更新,删除等) 3.同步到数据库中:使用SqlDataAdapter实例名.Update(DataSet实例名&#xff…

CSS完美兼容IE6/IE7/FF的通用方法

关于CSS对各个浏览器兼容已经是老生常谈的问题了, 网络上的教程遍地都是.以下内容没有太多新颖, 希望能对初学者有一定的帮助.一、CSS HACK 以下两种方法几乎能解决现今所有HACK. 1, !important 随着IE7对!important的支持, !important 方法现在只针对IE6的HACK.(注意写法.记得…

学习进度

这一周学习了第四章登录,第五章系统业务逻辑没有完成上周规定的四五六章,因为发现有些以前看的东西现在没印象了,又看了一些之前的。 在代码上完成了老师布置的代码,第一个是判断AB和C的关系 ,第二个是成绩排名&#x…

为Lucene选择快速唯一标识符(UUID)

大多数使用Apache Lucene的搜索应用程序都会为每个索引文档分配唯一的ID(即主键)。 尽管Lucene本身不需要这样做(它可能不太在乎!),但应用程序通常需要它以后通过其外部ID替换,删除或检索该文档…

ubuntu16.04设置静态ip

最近在课堂上,有很多同学反映在搭建环境的时候,虚拟机ip经常变,那么我们配置好的web服务可能就不能用了。下面讲一下如何在ubuntu上面设置静态ip 1:首先我们确认一下ubuntu的版本 cat /etc/issue 或者sudo lsb_release -a或者unam…

css布局:块级元素的居中

一.定宽&#xff1a; 1.定位居中(absolute) 方法一&#xff1a; html:<div class"main"></main>css:.main{width:400px;height:200px;background:#eee;position:absolute;left:50%;top:50%;margin-left:-200px;margin-top:-100px;} 方法二&#xff1a;…

精准客户数据服务

详情请点击&#xff1a;http://www.rulingtech.com 客户数据&#xff08;名录&#xff09;是市场营销活动不可或缺的重要资料。目前企业采用的客户名录数据主要通过订购黄页、购买第三方名录、自行搜集等途径。这些方式面临的问题是&#xff1a;数据重复度高、有效性差、准确率…

Maven常用的构建命令

Maven常用命令&#xff1a; Maven库&#xff1a; http://repo2.maven.org/maven2/ Maven依赖查询&#xff1a; http://mvnrepository.com/ 一&#xff0c;Maven常用命令&#xff1a; 1. 创建Maven的普通Java项目&#xff1a; mvn archetype:create-DgroupIdpackageName-Dartifa…

JPA 2.1实体图–第1部分:命名实体图

延迟加载通常是JPA 2.0的问题。 如果要使用FetchType.LAZY&#xff08;默认&#xff09;或FetchType.EAGER来加载关系&#xff0c;则必须在实体上进行定义&#xff0c;并且始终使用此模式。 仅当我们要始终加载关系时才使用FetchType.EAGER。 FetchType.LAZY几乎在所有情况下都…

课时85.层叠性(掌握)

1.什么是层叠性&#xff1f; 层叠性就是CSS处理冲突的一种能力。 这个字体最终会变为红色 注意点&#xff1a; 层叠性只有在多个选择器选中“同一个标签”,然后又设置了“相同的属性”&#xff0c;才会发生层叠性。 CSS全称&#xff1a;Cascading StyleSheet 层叠样式表&am…

ABZ职业规划

关于职业规划&#xff0c;LinkedIn&#xff08;领英&#xff09;创始人里德霍夫曼&#xff08;Reid Hoffman&#xff09;提出著名的“ABZ理论”&#xff0c;教我们应对变化莫测的职场人生。 德霍父曼建议每个职场人应有A计划&#xff0c;B计划&#xff0c;C计划。 A计划&#x…

SetProcessWorkingSetSize减少内存占用

系统启动起来以后&#xff0c;内存占用越来越大&#xff0c;使用析构函数、GC.Collect什么的也不见效果&#xff0c;后来查了好久&#xff0c;找到了个办法&#xff0c;就是使用 SetProcessWorkingSetSize函数。这个函数是Windows API 函数。下面是使用的方法&#xff1a;[Syst…

Spring Boot 与消息 (JMS、AMQP、RabbitMQ)

RabbitMQ教程 - 鸟哥的专栏 - CSDN博客 一、概述 大多应用中&#xff0c;可通过消息服务中间件来提升系统异步通信、扩展解耦能力消息服务中两个重要概念&#xff1a;消息代理&#xff08;message broker)和目的地&#xff08;destination) 当消息发送者发送消息以后&#xff0…

使用Apache Camel通过soap添加WS-Security

WS-Security&#xff08;Web服务安全性&#xff09;是一种协议&#xff0c;可让您保护自己的soap Web服务。 发出Soap请求的客户端必须在Soap标头中提供登录名和密码。 服务器接收到肥皂请求&#xff0c;检查凭据并验证请求是否正确。 使用Apache Camel&#xff0c;可以很容易…