咱们都知道call,apply,bind函数都是为了改变this的指向,那么对于三种函数有什么相同点有什么不太点或者有什么应用呢?下面咱们来进行介绍javascript
在javascript种,call,apply的出现是为了改变函数体内部this的指向,下面咱们来看一个栗子,并从中进行分析。java
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的第二个参数只能传入参数数组,不能传入多个参数。数组
对于上述输出结果的小总结为:app
根据call和apply的特色,咱们能够有如下应用。函数
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)
输出结果:this
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)来判断数据类型。spa
<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>
输入结果:prototype
对于咱们调用的一些方法例如document.getElementsByName()、document.getElementsByTagName() ,childNodes/children 等返回的均为伪数组,此时不能使用数组的方法,咱们可使用call函数使其转换为真正数组所带有真正数组方法的对象,这个时候咱们就可以调用数组的全部方法啦。code
var arr1 = [1,"xixi",{age:17},34] var arr2 = [3,"haha",{age:44},21] Array.prototype.push.apply(arr1,arr2)//进行数组的链接 console.log(arr1)
var arr1 = [1,3,4,5,93] //实际为向Math.max中传入参数arr1,等同于Math.max(arr1) var max = Math.max.apply(Math.max,arr1) console.log(max)
与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绑定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()
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(),cal(),apply()的介绍就到这里啦,有帮助的话就点个赞呗,欢迎评论区指正!