修改this指向(bindcall 和 apply)

炒沙作縻终不饱,缕冰文章费工巧。这篇文章主要讲述修改this指向(bindcall 和 apply)相关的知识,希望能为你提供帮助。
一、bind首先:

var alertWrite = document.write; alertWrite(\'who am I?\');

这两行代码的运行结果是什么呢?不要急着回答,看完下面的内容再回答。
bind 的其中一个用法就是:绑定函数,使其无论怎么样调用都用相同的 this
看下面的例子:
var obj = { getThis: function() { console.log(this); } };
obj.getThis(); var getThisCopy = obj.getThis; getThisCopy();

运行结果如下:
修改this指向(bindcall 和 apply)

文章图片

修改this指向(bindcall 和 apply)

文章图片

通过上述例子我们会发现,虽然是 getThisCopy 是复制了 obj 的 getThis 方法,但是他们所属的对象却不一样。在对象里面,所有的 this 都指向对象本身,而在全局作用域定义的变量的 this 指向 Window。
  所以,下面这段代码的运行结果,能猜的出来结果吗?
1 var obj = { 2num: 100, 3numFun: function() { 4console.log(this.num); 5} 6 }; 7 var numFunCopy = obj.numFun; 8 numFunCopy();

bind 的存在就是 为了解决 this 不能够指向原来的问题。
所以,试试这段代码:
1 var alertWrite = document.write; 2 alertWrite.bind(document)(\'hello\');

4 var obj = { 5getThis: function(){ 6console.log(this); 7} 8 } 9 var getThisCopy = obj.getThis; 10 getThisCopy.bind(obj)(); 11 12


13 var obj = { 14num: 100, 15numFun: function(){ 16console.log(this.num); 17} 18 } 19 var numFunCopy = obj.numFun; 20 numFunCopy.bind(obj)();

总结bind使用方法:
fun.bind(thisArgument, argument1, argument2, ...)
thisArgument:在 fun 函数运行时指定的 this 值,如果绑定函数时使用 new 运算符构造的,则该值将被忽略。
argument1, argument2, ...:指定的参数列表。
返回值:具有指定 this 值和初始参数的给定函数的副本
使用1:创建绑定函数,使函数无论怎么样调用,都有相同的 this 值
1 this.x = 9; 2 var module = { 3x: 81, 4getX: function() { return this.x; } 5 }; 6 7 module.getX(); // 返回 81 8 9 var retrieveX = module.getX; 10 retrieveX(); // 返回 9, 在这种情况下,"this"指向全局作用域 11 12 // 创建一个新函数,将"this"绑定到module对象 13 // 新手可能会被全局的x变量和module里的属性x所迷惑 14 var boundGetX = retrieveX.bind(module); 15 boundGetX(); // 返回 81

修改this指向(bindcall 和 apply)

文章图片

修改this指向(bindcall 和 apply)

文章图片

使用2:偏函数,使一个函数拥有预设值。
修改this指向(bindcall 和 apply)

文章图片

 
但是 bind 是 ES5 的内容,有一定的兼容性问题。
解决bind兼容性方案(1)
1 //解决IE10以下不支持Function.bind 2 if (!Function.prototype.bind) { 3Function.prototype.bind = function(oThis) { 4if (typeof this !== "function") { 5throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); 6} 7var aArgs = Array.prototype.slice.call(arguments, 1), 8fToBind = this, 9fNOP = function() {}, 10fBound = function() { 11return fToBind.apply(this instanceof fNOP & & oThis ? this : oThis, 12aArgs.concat(Array.prototype.slice.call(arguments))); 13}; 14fNOP.prototype = this.prototype; 15fBound.prototype = new fNOP(); 16return fBound; 17}; 18 }

解决bind兼容性方案(2)
1 if (!function() {}.bind) { 2Function.prototype.bind = function(context) { 3var self = this 4, args = Array.prototype.slice.call(arguments); 5return function() { 6return self.apply(context, args.slice(1)); 7} 8}; 9 }

 
二、call语法:fun.call(thisArgument, argument1, argument2, ...)
thisArgument:在 fun 函数运行时指定的 this 值。在非严格模式下,该函数 this 指定为 null 和 undefined ,则 this 值会自动只想全局对象,同时只为原始值的 this 会指向该原始值的自动包装对象。
argument*:指定的参数列表。
返回值:调用该方法的返回值,如果没有,则返回undefined。
使用1:使用 call 方法来实现继承
修改this指向(bindcall 和 apply)

文章图片

使用2:使用 call 调用匿名函数,方法为for循环传入不同的对象
修改this指向(bindcall 和 apply)

文章图片

使用3:指定上下文 this
修改this指向(bindcall 和 apply)

文章图片

 
三、apply语法:fun.apply(thisArg [, argsArray])
thisArg:可选,在非严格模式下,如果 this 值设置为 null/undefined,则 this 指向去全局对象(浏览器中就是 window 对象),同时为原始值(数字,字符串,布尔值)的 this 会指向该原始的包装对象。
argsArray:可选。数组或者类数组对象(从ES5开始可以使用类数组对象)。
返回值:调用有指定this值和参数的函数的结果。
使用:其使用跟 call() 非常相似,只是提供参数的方式不同。
【修改this指向(bindcall 和 apply)】 

    推荐阅读