咱们都晓得call,apply,bind函数都是为了扭转this的指向,那么对于三种函数有什么相同点有什么不太点或者有什么利用呢?上面咱们来进行介绍
call与apply函数
在javascript种,call,apply的呈现是为了扭转函数体外部this的指向,上面咱们来看一个栗子,并从中进行剖析。
var a = "我是window的小a";
var obj = {
a:"我是obj的小a",
foo:function (...arg) {
console.log(this.a,this,...arg)
}
}
obj.foo() //此时的this为obj
var f2 = obj.foo
f2() //此时的this为window
f2.call(obj,1,2,3) //call扭转了this的指向,此时的this为obj,并传入参数
f2.call(obj,[1,2,3]) //输入obj中的a
f2.apply(obj,[1,2,3],3,4,5) //apply扭转了this的指向为obj,传入参数数组,在参数数组之后传递参数,并不能传入该参数
f2.apply(obj,1,2,3) //报错!apply第二个参数必须为参数数组
咱们来看一下输入后果。
由上述输入后果来看,应用call和apply可能扭转this的指向。函数f2本来的指向为window,应用call和apply函数绑定obj后this的指向为obj。对于上述的输入后果还有一个报错?立马不淡定了。原来apply的第二个参数只能传入参数数组,不能传入多个参数。
对于上述输入后果的小总结为:
- call和apply都用于去扭转this的指向问题,第一个参数为this所指向的对象
- call和apply都为间接调用函数,返回值就为调用函数的返回值。
- call的第二个地位和之后传递参数列表,当向call中传递数组时,则视为只传递了一个参数(这个参数为数组)
- apply的第二个地位只能传递参数数组,在参数数组之后传递参数,均生效。
依据call和apply的特点,咱们能够有以下利用。
应用call进行继承
function father(name,age,hometown,hobby) {
this.name = name;
this.age = age;
this.hometown = "中国"
this.hobby = hobby;
}
function son(name,age,hobby,hometown) {
father.call(this,name,age,hometown)//继承父类中的多个属性
this.hobby = hobby;
}
let f = new father("小头爸爸",38,"中国","钓鱼");
let s = new son("大头儿子",16,"打球");
console.log(f)
console.log(s)
输入后果:
应用call判断数据类型
console.log(Object.prototype.toString.call("pp"))
console.log(Object.prototype.toString.call({age:15}))
console.log(Object.prototype.toString.call(23))
console.log(Object.prototype.toString.call([1,2,3]))
在这我就不一一列举对于数据的数据类型了,此时必定有人产生纳闷,为什么平时咱们用的obj.toString和object.prototype.toString.call(obj)的后果为什么不一样了呢?因为咱们应用的obj.toString()在一些数据类型中都重写了toString的办法,对于函数和数组来讲,应用obj.toString都会间接输入字符串,故应用obj.toString()不能输入数据类型。但为什么Object.prototype.toString.call(obj)可能输入数据类型的值呢?因为toString为Object的原型办法,并没有像obj.toString()一样重写该办法。应用Object上的原型中的toString办法的返回值为数据类型。故咱们能够通过Object.prototype.toString.call(obj)来判断数据类型。
应用call使伪数组应用数组办法
<div class="xixi"></div>
<div class="xixi"></div>
<div class="xixi"></div>
<div class="xixi"></div>
<script>
//将伪数组转换为数组,使其能够调用数组所具备的办法
var realArr = Array.prototype.slice.call(document.getElementsByTagName("div"));
realArr.push(1)
console.log(realArr)
//伪数组
var div = document.getElementsByTagName("div")
div.push(1) //报错为伪数组中没有数组具备的办法
</script>
输出后果:
对于咱们调用的一些办法例如document.getElementsByName()、document.getElementsByTagName() ,childNodes/children 等返回的均为伪数组,此时不能应用数组的办法,咱们能够应用call函数使其转换为真正数组所带有真正数组办法的对象,这个时候咱们就可能调用数组的所有办法啦。
应用apply进行数组的连贯
var arr1 = [1,"xixi",{age:17},34]
var arr2 = [3,"haha",{age:44},21]
Array.prototype.push.apply(arr1,arr2)//进行数组的连贯
console.log(arr1)
应用apply获取数组中的最大值
var arr1 = [1,3,4,5,93]
//理论为向Math.max中传入参数arr1,等同于Math.max(arr1)
var max = Math.max.apply(Math.max,arr1)
console.log(max)
bind函数
与call和apply类似,其作用都是用于扭转函数外部this的指向。但第二个参数开始是传入参数列表,这点与call类似,但与其有什么不同的中央呢?call与apply是立刻执行函数而bind函数是将函数返回。
绑定函数
应用bind办法会返回一个函数,使其函数无论怎么调用,其this都会指向原来所绑定的那个对象
var a = "我是window的小a";
var obj = {
a:"我是obj的小a",
foo:function (...arg) {
console.log(this.a,this,...arg)
}
}
obj.foo() //此时的this为obj
var f1 = obj.foo() //此时的this为window
var f2 = f1.bind(obj) //绑定this为obj,并返回一个新函数
f2() //输入我是obj的小a
配合应用setTimeout
在咱们没有给setTimeout绑定this的状况下,当咱们在setTimeout中应用this,this关键字会指向window对象,咱们能够利用bind函数绑定this,使其可能利用this调用想要绑定的函数。
function foo() {
this.age = 20
}
//函数f1
foo.prototype.f1 = function () {
console.log(this) //此时的this为foo
setTimeout(this.f2,1000) //然而此时的this为window,而不是foo,因而无奈调用f2
var _this = this //获取到以后的this
setTimeout(this.f2.bind(_this),1000) //将this.f2的this绑定给foo
}
//函数f2
foo.prototype.f2 = function () {
console.log("我的年龄为:" + this.age)
}
var foo = new foo() //发明实例
foo.f1()
应用bind将类数组转换为数组
function foo() {
var TempSlice = Array.prototype.slice;
// 把函数的call办法绑定在数组slice办法上,之后再给call办法传递参数
var slice = Function.prototype.call.bind(TempSlice);
return slice(arguments);
}
console.log(foo(1,2,3)) //[1,2,3]
区别bind()、call()、apply()
- 都能指定函数中的this
- call()和apply是立刻调用函数
- bind()是将函数返回
对于bind(),cal(),apply()的介绍就到这里啦,有帮忙的话就点个赞呗,欢送评论区斧正!