JS-this小解析(2)

来源:互联网 发布:linux下打开文件命令 编辑:程序博客网 时间:2024/06/06 03:43

绑定例外

被忽略的this

如果把null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则:

function foo() {    console.log(this.a );}var a = 2;foo.call(null);// 2

如果需要传入null,则需要使用apply(..)来“展开”一个数组,并当做参数传入一个函数。bind(..)可以对参数进行柯里化(预先设置一些参数)。

更安全的this

总是使用null来忽略this绑定可能产生一些副作用。如果某个函数确实使用了this(比如第三方库中的一个函数),那默认绑定规则会把this绑定到全局对象(在浏览器中这个对象是window),这将导致不可预计的后果(比如修改全局对象)。

一种“更安全”的做法是传入一个特殊的对象,把this绑定到这个对象不会对你的程序产生任何副作用。由于这个对象完全是一个空对象,可以用变量名ø(这是数学中表示空集合符号的小写形式)来表示它,或者其他任何名字。

在JavaScript中创建一个空对象最简单的方法都是Object.create(null)。Object.create(null)和{}很像,但是并不会创建Object.prototype这个委托,所以它比 {}“更空”。

间接引用

有时候可能(有意或者无意地)创建一个函数的“间接引用”,在这种情况下,调用这个函数会应用默认绑定规则。
间接引用最容易在赋值时发生:

function foo() {    console.log(this.a );}var a = 2;var o = {    a:3,};var p = {    a:4};o.foo();// 3(p.foo =o.foo)();// 2

赋值表达式p.foo = o.foo的返回值是目标函数的引用,因此调用位置是foo()而不是p.foo()或者o.foo(),所以这里会应用默认绑定。注意:对于默认绑定来说,决定this绑定对象的并不是调用位置是否处于严格模式,而是函数体是否处于严格模式。如果函数体处于严格模式,this会被绑定到undefined,否则this会被绑定到全局对象。

软绑定

之前我们已经看到过,硬绑定这种方式可以把this强制绑定到指定的对象(除了使用new时),防止函数调用应用默认绑定规则。问题在于,硬绑定会大大降低函数的灵活性,使用硬绑定之后就无法使用隐式绑定或者显式绑定来修改this。

如果可以给默认绑定指定一个全局对象和undefined以外的值,那就可以实现和硬绑定相同的效果,同时保留隐式绑定或者显式绑定修改this的能力。

可以通过一种被称为软绑定的方法来实现我们想要的效果:

if (!Function.prototype.softBind) {    Function.prototype.softBind =function (obj) {        var fn = this;// 捕获所有curried 参数        var curried = [].slice.call(arguments,1);        var bound = function () {            return fn.apply ((!this||this===(window  || global))                 ? obj :this            curried.concat.apply(curried,arguments)            );        };        bound.prototype =Object.create(fn.prototype );          return bound;    };}

除了软绑定之外,softBind(..)的其他原理和ES5内置的bind(..)类似。它会对指定的函数进行封装,首先检查调用时的this,如果this绑定到全局对象或者undefined,那就把指定的默认对象obj绑定到this,否则不会修改this。此外,这段代码还支持可选的柯里化(详情请查看之前和bind(..)相关的介绍)。

下面我们看看softBind是否实现了软绑定功能:

function  foo() {    console.log("name: "+this.name);}var obj = {name:"obj"},    obj2 = {name:"obj2"},    obj3 = {name:"obj3"};var fooOBJ = foo.softBind(obj );fooOBJ();// name: objobj2.foo =foo.softBind(obj);obj2.foo();// name: obj2 <---- 看!fooOBJ.call(obj3 );// name: obj3 <---- 看!setTimeout(obj2.foo,10);// name: obj <---- 应用了软绑定

可以看到,软绑定版本的foo()可以手动将this绑定到obj2或者obj3上,但如果应用默认绑定,则会将this绑定到obj。

this词法

ES6中介绍了一种无法使用这些规则的特殊函数类型:箭头函数。(由“胖箭头”操作符 =>定义)箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。

function foo(){    // 返回一个箭头函数    return(a)=>{        //this继承自foo()                console.log(this.a );    };}var obj1 = {    a:2};var obj2 = {    a:3};var bar = foo.call( obj1 );bar.call( obj2 );// 2, 不是3!

foo()内部创建的箭头函数会捕获调用时foo()的this。由于foo()的this绑定到obj1,bar(引用箭头函数)的this也会绑定到obj1,箭头函数的绑定无法被修改。(new也不行!)

箭头函数最常用于回调函数中,例如事件处理器或者定时器。

1 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 狗链条上锈了怎么办 思维迟钝反应慢嘴笨怎么办 小孩思维慢反应迟钝怎么办 苹果4g网络慢怎么办 医院没有号了怎么办啊 fgo宝具动画卡顿怎么办 死刑犯在执行前死亡怎么办 汕头交警 违章扣分怎么办办理 幼儿园家长不保险应该怎么办 csgo掉白银坑了怎么办 错过教资认定现场确认怎么办 乡村建设导致民房开裂怎么办 项目部公章丢了怎么办 手机掉了没有卡怎么办 苹果系统软件删了还是出现怎么办 钉钉检测到作弊怎么办 电脑麦说话声音小怎么办 穿越火线麦克风有杂音怎么办 手闲不住就抠东西怎么办 大便堵在肛门口怎么办 在外地流量不够用怎么办 电脑键盘数字键没反应怎么办 音响音量键坏了怎么办 摩托罗拉移动电话通话没声音怎么办 摩托罗拉对讲机充电座坏了怎么办 手机导航键太灵敏怎么办 经侦大队不立案怎么办 槐茂酱菜太咸怎么办 法院执法局执法不公怎么办 搞养殖卖不出去怎么办 孔雀吃了蚯蚓该怎么办 多肉幼苗长徒了怎么办 小鸵鸟嘴断了怎么办 武汉早谢怎么办博大直上 威猛先生伤手了怎么办 嗓子眼边条线下边长块肉怎么办 线长在肉里怎么办 北京买车没有号怎么办 租的车处理违章怎么办 以租代购车不要怎么办 订车的合同掉了怎么办