this的动态切换虽然为js创造了巨大的灵活性,也使编程变得困难和模糊
。利用call、apply、bind这三个方法,能够改变this的指向,使它指向咱们指望的对象。编程
var f = function() {}; f.call(o);
在全局环境运行函数时,this指向全局环境,利用call方法,将this指向了对象o,在o的做用域中运行函数f。数组
var n = 123; var o ={n: 234}; function a() {console.log(this.n)}; a.call() //123 a.call(null) //123 a.call(undefined) //123 a.call(window) //123 a.call(o) //234
能够看到,若是call方法没有参数,或者参数为null或undefined,则等同于指向全局对象app
call方法的完整使用格式:函数
func.call(thisValue, arg1, arg2, ...)
第一个参数是this要指向的那个对象,后面的参数是调用时所须要的参数this
function add(a,b) { return a+b; } add.call(this, 1, 2) //3
call方法的一个应用是调用对象的原生方法prototype
var obj = {}; obj.hasOwnProperty('toString') //false obj.hasOwnProperty = function() {return true;} obj.hasOwnProperty('toString') //true Object.prototype.hasOwnProperty.call(obj, 'toString')
上述代码中,hasOwnProperty是obj对象继承的方法,一旦被覆盖从新定义,就得不到正确结果,利用call方法,将hasOwnProperty方法的原始定义放到obj对象上执行,这样不管Obj上有没有同名方法,都不会影响结果。code
apply方法与call方法相似,使用格式以下:对象
func.apply(thisValue, [arg1, arg2, ...])
apply方法的第一个参数也是this所要指向的那个对象,若是设为null或undefined,则等同于指定全局对象。第二个参数则是一个数组,该数组的全部成员依次做为参数,传入原函数。
一些有趣的应用
1)找出数组最大元素继承
var a = [12, 2, 45, 4, 9]; Math.max.apply(null, a); //45
2)将数组的空元素变为undefined事件
Array.apply(null, ["a",,"b"]) // ['a', undefined, 'b']
空元素和undefined的差异在于,数组的foreach方法会跳过空元素,可是不会跳过undefined,所以遍历内部元素的时候,会获得不一样的结果
var a = ["a",,"b"]; function print(i) { console.log(i); } a.forEach(print) //a //b Array.apply(null, a).forEach(print) //a //undefined //b
3)转换相似数组的对象
Array.prototype.slice.apply({0:1,length:1}) // [1] Array.prototype.slice.apply({0:1}) // [] Array.prototype.slice.apply({0:1,lengt:2}) // [1, undefined] Array.prototype.slice.apply({length:1}) // []
利用数组的slice方法,能够将一个相似数组的对象,好比上面代码的apply方法的参数都是对象,可是反悔结果都是数组,这就起到了将对象转成数组的目的。
这个方法起做用的前提是,被处理的对象必须有length属性,以及相对应的数字键
4)绑定回调函数的对象
这个采用bind方法更好
var o1 = new Object(); o1.p = 123; o1.m = function() {console.log(this.p);}; o1.m(); //123 var o2 = new Object(); o2.p = 345; o2.m = o1.m; o2.m(); //345 o2.m = o1.m.bind(o1); o2.m() //123
bind方法除了绑定this之外,还能够绑定原函数的参数
var add = function (x,y) { return x*this.m + y*this.n; } var obj = { m: 2, n: 2 }; var newAdd = add.bind(obj, 5);//add()函数的第一次参数x绑定为5,若是给了两个参数,则同时给定了x、y的值 newAdd(5); //20
若是bind方法的第一个参数是null或undefined,等于将this绑定到全局
bind方法的使用注意点:
1)每一次返回一个新函数
element.addEventListener('click', o.m.bind(o));
click事件绑定到了o.m使用bind方法生成的一个匿名函数上,这样会致使没法取消。所以下面代码是无效的。
element.removeEventListener('click', o.m.bind(o));
正确的写法是下面这样:
var listener = o.m.bind(o); element.addEventListener('click', listener); //... element.removeEventListener('click', listener);