了解完函数的调用区域是如何影响this 对象的,还有this 的各种绑定方式以及各种绑定方式的优先级后
最后一部分,来了解一下this 的一些例外情况
1、被忽略的this
例如在使用bind 方法时候进行函数柯里化,如果此时函数并没有打算绑定任何对象在bind() 方法的第一个参数可以传进一个 null充当占位符
例:
function foo(a,b){ console.log("a: " + a + "b: " + b); } var bar = foo.bind(null,3);//在绑定this 对象的同时传入第一个参数 bar(5);//在调用的时候再把第二个参数传进去
tips:
所谓函数柯里化,就是将一堆参数分配内部函数执行,最后再返回所有参数的结果
本人还没对柯里化深入认识只能说一点皮毛
如上例,将函数绑定在一个空对象中 就相等于把函数绑定在了全局环境中
这样做的方法比较危险 于是有了更安全的this 绑定 这一说法
把不需要做任何绑定的函数绑定在一个空对象中(此空对象是我们自己创建的对象)
例如:
通过Object.create(null) 创建一个空对象,这样创建比 {} 这样更空
因为省略了对象的prototype
function foo(a,b){ console.log("a: " + a + "b: " + b); } var empty = Object.create(null);//创建一个安全的 不会影响全局作用域的空对象 //把foo 函数绑定在空对象上执行 foo.apply(empty,[2,5]);//"a: " + 2 + "b: " + 5 var fun = foo.bind(empty,6); fun(8);
这样的执行会更加的安全
2、间接引用
间接引用通常会产生在函数引用的赋值上
例:
function foo(){ console.log(this.a); } var obj1 = { a: 23333, foo: foo } var obj2 = { a: 6666, } var a = "window here"; (obj2.foo = obj1.foo)();
注意这里还是那个问题,obj1 虽然是引用着函数foo
但是引用的内容仅仅是函数foo 的引用而已,this对象的绑定还是要看函数在哪里调用
此时函数 foo的调用位置在全局 因此在非严格模式下函数输出全局变量 a
如需绑定对象可以把上面的引用通过硬绑定的方式去执行
书上还写了一个修改函数原型的软绑定方法
if (!Function.prototype.softBind) { Function.prototype.softBind = function(obj) { // 获取当前调用此方法的函数 var fn = this; // 获取所有 softbind 除第一个以外的所有参数 var curried = [].slice.call( arguments, 1 ); //绑定函数 var bound = function() { //当bound函数 被执行时 返回调用函数在指定对象的执行效果 //判断如下 return fn.apply( //如果调用bound函数时 它的this 是指向了window 或者为false //那么将它绑定在前期调用的绑定对象上 //如果不是 //放在调用它的对象上面执行 (!this || this === (window || global))? obj : this, curried.concat.apply(curried, arguments) ); }; bound.prototype = Object.create(fn.prototype); //修改bound 函数的原型对象为调用函数的原型 return bound;//返回bound 函数 }; }
这个方法意义在于不允许函数引用全局对象 而且比bind() 函数绑定好的一点是,当绑定完了一个对象时下面还可以绑定其他对象而不会永远地绑定在了一开始绑定的对象上
function foo(){ console.log("this.name: " + this.name); } var obj1 = { name: "obj1" } var obj2 = { name: "obj2" } var obj3 = { name: "obj3" } var bar1 = foo.softBind(obj1);//这里通过软绑定 将foo绑定在了obj1 上 bar1();//当全局变量执行时 它的this 便不再指向window而是指向了前期绑定好的obj1 上 //如果通过对象去调用呢? obj2.bar1 = bar1; obj2.bar1();//显示为 obj2 了 //再与原来的硬绑定 bind对比 var bar2 = foo.bind(obj1); bar2();//结果是输出 obj1 obj2.bar2 = bar2; bar2();//这里结果就不一样了 foo永远绑死在了obj1 上不能再改变了
最后介绍最后一个特殊的函数 es6 的箭头函数()=>
这个函数有一个特点就是 它的this 永远指向包含它的函数的this
看实例就懂
function baz(){ //继承自baz return (a)=>{ console.log(this.a);//输出外层函数能访问到的属性名 } } var o1 = { a: "o1 here" } var o2 = { a: "o2 here" } var bat = baz.call(o2); bat.call(o1,"a");//即使箭头函数在o1 内部调用 但是也只会输出baz调用对象的属性
其实在js 高程里面也说过一个问题 匿名函数的this 会指向了window
而es6 的箭头函数正好解决了这个问题 使this 更加完整了
而在es6 语法之前我们还有一个解决方案就是把 外部包含函数的this 对象保存在一个内部函数能够放到的变量上
然后内部函数再通过这个变量调用外部函数能访问的属性即可
this对象的介绍到这里介绍完了 我也要去撸一把特效之类的实际应用了,看太久理论真的会很累