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也不行!)
箭头函数最常用于回调函数中,例如事件处理器或者定时器。
- JS-this小解析(2)
- JS-this小解析(1)
- js中的this解析
- 解析JS中this关键字
- 通过实例全面解析JS中的This
- 全面解析JS中的this机制
- 解析js 中的 this.initialize.apply(this, arguments)
- javascript深度解析2--this
- js中this的全面解析之绑定规则(一)
- 小试 Node.JS 之 解析html
- jquery&js $(this) & this
- js this
- JS this
- JS this
- js this
- js this
- js this
- js this
- 什么是IPSec认证与加密?
- Hello Spring Boot应用程序
- 3台机器部署storm-1.1.0集群
- 排序算法 (二)
- Jade模板
- JS-this小解析(2)
- 线性代数知识点梳理(更新中)---还什么都没有。。。
- jsp 对象
- 电商的时代已经来临,您是否想出航,? 海川电商为你起航护驾。
- C++第5次作业
- c++实验5
- Find a way (广搜(水))
- js正则表达式匹配特殊字符
- 快速排序java并行实现