绑定this的方法
call
Function.prototype.call()
单个参数
函数实例的call
方法可以改变函数体内this
的指向。
var x="in window";
var obj={
x:"in obj",
fun:function(){
console.log(this.x);
}
};
obj.fun(); //"in obj"
obj.fun.call(window);//"in window"
上面代码表示,函数call
接受指定参数作为函数内this
的执行环境(指向)。
call
接受的参数应该是一个对象,如果该参数是原始类型的值,那么这个原始值会自动转化为对应的包装对象,再传入call
方法。
var f = function () {
return this;
};
f.call(5)
// Number {[[PrimitiveValue]]: 5}
上面代码中,call
的参数为5,不是对象,会被自动转成包装对象(Number
的实例),绑定f
内部的this
。
多个参数
call
方法可以接受多个参数
func.call(thisValue, arg1, arg2, ...)
call
方法第一个参数为this
要指向的对象,后面的参数则是函数执行时所需要的实参。
function add(a, b) {
return a + b;
}
add.call(this, 1, 2) // 3
上述代码表示,call
方法指定函数add
为this
的执行环境,并且传入参数1,2,返回结果3.
应用
call
方法的一个应用是调用对象的原生方法
下面代码是利用call
解决函数重名问题的一个例子。
var obj = {};
obj.hasOwnProperty('toString') // false
// 覆盖掉继承的 hasOwnProperty 方法
obj.hasOwnProperty = function () {
return true;
};
obj.hasOwnProperty('toString') // true
Object.prototype.hasOwnProperty.call(obj, 'toString') // false
开始时,对象obj
的hasOwnProperty
方法是继承自Object
对象的,当被不小心覆盖时,会导致不必要的错误。所以可以使用call
,将hasOwnProperty
方法的原始定义放到obj
对象上执行,这样无论obj
上有没有同名方法,都不会影响结果。
apply
Function.prototype.apply()
apply
方法与call
方法作用基本相似,唯一的区别就是,它以数组的形式接收函数执行时的参数
func.apply(thisValue, [arg1, arg2, ...])
apply
方法的第一个参数也是this
所要指向的那个对象,如果设为null
或undefined
,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。
应用
(1) 找出数组最大元素
结合apply方法和Math.max方法可以返回数组中的最大元素
var arr=[12,421,43,123,42];
Math.max.apply(null,arr); //421
(2) 将数组的空元素变为undefined
通过apply
方法,利用Array
构造函数将数组的空元素变成undefined
。
var arr=[12,,43];
Array.apply(null,arr);[12,undefined,43];
空元素与undefined
的区别在于,数组的forEach
方法会跳过空元素,而不会跳过undefined
;
var arr=[12,,13];
arr.forEach(item=>console.log(item));//12 13
Array.apply(null,arr).forEach(item=>console.log(item))
//12 undefined 13
(3) 转换类似数组的对象
另外,利用数组对象的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
属性,以及相对应的数字键。
(4)绑定回调函数的对象
var o = new Object();
o.f = function () {
console.log(this === o);
}
var f = function (){
o.f.apply(o);
// 或者 o.f.call(o);
};
// jQuery 的写法
$('#button').on('click', f);
上面代码中,页面中有一个按钮,点击以后,控制台将会显示true
。使用了apply()
方法(或者call()
方法)不仅绑定函数执行时所在的对象,还会立即执行函数,因此不得不把绑定语句写在一个函数体内。更简洁的写法是采用下面介绍的bind()
方法。
bind
Function.prototype.bind()
bind()
方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
var d=new Date();
d.getTime(); 1606483094579
var print=d.getTime;
print();//Uncaught TypeError: this is not a Date object.
使用bind
可以将d.getTime
方法里的this绑定到某个对象上
var d=new Date();
d.getTime(); 1606483094579
var print=d.getTime.bind(d);
print(); //1606483094579
上面代码中,bind()
方法将getTime()
方法内部的this
绑定到d
对象,这时就可以安全地将这个方法赋值给其他变量了。
使用其他对象的方法
var obj1={
name:"obj1",
show:function(){
console.log(this.name);
}
};
var obj2={
name:"obj2"
};
obj1.show(); //obj1
var showobj=obj1.show.bind(obj2);
show(); //obj2
注意
(1)每次都返回一个新函数
bind()
方法每次运行,都会产生一个新函数,所以在写监听事件时,不能写成以下形式。
element.addEventListener('click', o.m.bind(o));
上面代码表示,该click
事件绑定bind()方法生成的一个匿名函数,,这样会导致无法取消绑定(removeEventListener)。
可参考写成如下形式
var listener = o.m.bind(o);
element.addEventListener('click', listener);
// ...
element.removeEventListener('click', listener);
给函数一个名字,就能解决这个问题。
(2)结合call()
方法
利用bind()
可以改写一些JavaScript原生方法的使用形式。
var arr=[1,2,3,4,5];
arr.slice(0,3); //[1,2,3];
//等同于
Array.prototype.slice.call(arr,0,3);
通过改写后
var slice=Function.prototype.call.bind(Array.prototype.slice);
slice(arr,0,3); //[1,2,3]
上面代码的含义就是,将Array.prototype.slice
变成Function.prototype.call
方法所在的对象,调用时就变成了Array.prototype.slice.call
对pop
和push
的改写
var arr=[1,2,3,4];
var pop=Function.prototype.call.bind(Array.prototype.pop);
var push=Function.prototype.call.bind(Array.prototype.push);
pop(arr); //[1,2,3]
push(arr,9,8,7); //[1,2,3,9,8,7]
改写bind使用形式
如果再进一步,将Function.prototype.call
方法绑定到Function.prototype.bind
对象,就意味着bind
的调用形式也可以被改写。
function f() {
console.log(this.v);
}
var o = { v: 123 };
var bind = Function.prototype.call.bind(Function.prototype.bind);
bind(f, o)() // 123
上面代码的含义就是,将Function.prototype.bind
方法绑定在Function.prototype.call
上面,所以bind
方法就可以直接使用,不需要在函数实例上使用。
上一篇 this关键字详解一
最后,希望能和大家一起进步! |
---|
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!