一、function.prototype.call()javascript
call 方法能够指定this 的指向(即函数执行时所在的的做用域),而后再指定的做用域中,执行函数html
call 方法的参数,应该是对象obj,若是参数为空或null,undefind,则默认传参全局对象 java
var obj = {}; var f = function(){ return this; }; console.log(f() === window); // this 指向window console.log(f.call(obj) === obj) //改变this 指向 obj
若是call 传参不是以上类型,则转化成对应的包装对象,而后传入方法。例如,5 转成number 实例,绑定f 内部 this数组
var f = function () { return this; }; f.call(5) // Number {[[PrimitiveValue]]: 5}
call 能够接受多个参数,第一个参数是this 指向的对象,以后的是函数回调所需的入参app
function add(a, b) { return a + b; } add.call(this, 1, 2) // 3
call
方法的一个应用是调用对象的原生方法。函数
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
上面代码中hasOwnProperty 是 obj 继承来的方法,用来判断对象是否包含自身特色(非继承)属性,可是hasOwnProperty 并非保留字,若是被对象覆盖,会形成结果错误。oop
call
方法能够解决这个问题,它将hasOwnProperty
方法的原始定义放到obj
对象上执行,这样不管obj
上有没有同名方法,都不会影响结果。this
hasOwnProperty 相关应用:https://www.cnblogs.com/weiqinl/p/8683207.htmlspa
二、Function.prototype.apply()prototype
apply 和call 做用相似,也是改变this 指向,而后调用该函数,惟一区别是apply 接收数组做为函数执行时的参数
func.apply(thisValue, [arg1, arg2, ...])
apply
方法的第一个参数也是this
所要指向的那个对象,若是设为null
或undefined
,则等同于指定全局对象。
第二个参数则是一个数组,该数组的全部成员依次做为参数,传入原函数。
原函数的参数,在call
方法中必须一个个添加,可是在apply
方法中,必须以数组形式添加。
function f(x, y){ console.log(x + y); } f.call(null, 1, 1) // 2 f.apply(null, [1, 1]) // 2
利用这一特性,能够实现不少小功能
好比,输出数组的最大值
var a = [24,30,2,33,1] Math.max.apply(null,a) //33
将数组中的空值,转化成undefined,主要应用在数组遍历中,由于数组foreach 遍历会跳过空值,而不会跳过undefined
var a = ['a',,'b']; Array.apply(null,a) //['a',undefind,'b']
将相似于数组的对象转化成数组
另外,利用数组对象的slice
方法,能够将一个相似数组的对象(好比arguments
对象)转为真正的数组。
Array.prototype.slice.apply({0: 1, length: 1}) // [1]
Array.prototype.slice.apply({0: 1}) // []
Array.prototype.slice.apply({0: 1, length: 2}) // [1, undefined]
Array.prototype.slice.apply({length: 1}) // [undefined]
上面代码的apply
方法的参数都是对象,可是返回结果都是数组,这就起到了将对象转成数组的目的。
从上面代码能够看到,这个方法起做用的前提是,被处理的对象必须有length
属性,以及相对应的数字键。
3.Function.prototype.bind()
bind 用于将函数体内的this绑定到某个对象,而后返回一个新函数
var d = new Date(); d.getTime() // 1481869925657 var print = d.getTime; print() // Uncaught TypeError: this is not a Date object.
报错是由于,d.getTime 赋值给 print 后,getTime 内部的this 指向方式变化,已经再也不指向date 对象实例了
解决方法
var print = d.getTime.bind(d); print() // 1481869925657
bind 接收的参数就是所要绑定的对象
ar counter = { count: 0, inc: function () { this.count++; } }; var func = counter.inc.bind(counter); func(); counter.count // 1
绑定到其余对象
var counter = { count: 0, inc: function () { this.count++; } }; var obj = { count: 100 }; var func = counter.inc.bind(obj); func(); obj.count // 101
bind 还能够接收更多的参数,将这些参数绑定到原函数的参数
var add = function (x, y) { return x * this.m + y * this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5); newAdd(5) // 20
上面代码中,bind
方法除了绑定this
对象,还将add
函数的第一个参数x
绑定成5
,而后返回一个新函数newAdd
,这个函数只要再接受一个参数y
就能运行了。
总结:
1. call 、 apply 、bind 均能改变this 指向
2. apply 每次执行产生一个新函数,call、apply 不会
3. call ,bind 接收多个参数绑定到函数,参数单一传入,apply 接收方式为数组
更多详细资料:
http://javascript.ruanyifeng.com/oop/this.html#toc7