版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
call,apply,bind是Function.prototype原型上的方法
任何函数都可以访问call,apply,bind方法(原因:任何函数的原型链上都有Function.prototype原型)
bind,apply,call的区别 | ||||
---|---|---|---|---|
方法 | 语法 | 第一个参数 | 其余参数 | |
call | call(对象,参数1,参数2...) | 修改this指向 | 作为函数的形参 | |
apply | apply(对象,[参数1,参数2...]) | 修改this指向 | 作为函数的形参 | |
bind | bind(对象,参数1,参数2...) | 固定this指向 | 作为函数的形参 |
call,apply的作用
- 调用函数
//除了使用函数名() 来调用函数外,还可以使用call,apply来调用函数
function fn(){
console.log(123);
}
fn.call();//123
fn.apply();//123
- 传参数
function sum(x, y) {
console.log(x + y);//5
}
var arr = [2, 3]
//传入null/undefined的时候将执行js全局对象,浏览器中是window
sum.apply(null, arr)
sum.call(null, 2, 3)
var arr = [18, 29, 89, 73, 5, 10, 8, 99, 105, 52];
//用Math对象上max()方法求最大值
Math.max.apply(null,arr)//105
Math.max.call(null, 18, 29, 89, 73, 5, 10, 8, 99, 105, 52)//105
- 修改this指向
var dog = {
name: '小黄',
age: 3
}
function animal (a,b) {
console.log(a + b);//3
console.log(this);//window
console.log(this.name);//'' 全局变量有name属性,所以不为undefined
console.log(this.age);//undefined
}
animal(1, 2)//函数调用模式,this指向window
var dog = {
name: '小黄',
age: 3
}
function animal (a,b) {
console.log(a+b);//3
console.log(this);//对象dog
console.log(this.name);//'小黄'
console.log(this.age);//3
}
animal.call(dog, 1, 2)//修改this指向为对象dog
-
借用对象方法
伪数组与数组
-
伪数组也叫类数组伪数组其实就是一个对象,但是跟数组一样,伪数组也会有
length
属性,也有0,1,2,3
等属性。 -
伪数组并没有数组的方法,不能使用
push/pop
等方法。 -
伪数组可以跟数组一样进行遍历,通过下标操作。
-
常见的伪数组:
arguments
、document.querySelectorAll
的返回值、jQuery对象
//创建一个伪数组
var obj = {
0: "卡卡西",
1: "佐助",
2: "鸣人",
length: 3
};//分号
//借用数组的方法,往伪数组最后添加一项
//Array.prototype.push.call(obj, "小樱");
[].push.call(obj, "小樱");//注意这种写法必须在对象后面添加分号,不然会被浏览器当做点语法解析
var obj = {
0: "卡卡西",
1: "佐助",
2: "鸣人",
length: 3
};
//通过silice截取数组可以将伪数组转换成真数组
var arr = [].slice.call(obj);
console.log(arr);//["卡卡西", "佐助", "鸣人"]
//数组借用Math对象方法求最大值
var arr = [18, 29, 89, 73, 5, 10, 8, 99, 105, 52];
var ret = Math.max.apply( arr, arr);//借用Math对象中max求最大值的方法
console.log(ret);//105
call,apply使用场景:
如果参数比较少,使用call会更加简洁
如果参数存放在数组中,此时需要使用apply
bind的作用
bind()方法创建一个新的函数, 可以绑定新的函数的this指向
var fn = function () {
console.log(this);//window
}
fn(); //函数调用模式,this指向window
//fn和fn2长的一样,但是在内存中是两份函数,地址是不一样。
var fn = function () {
console.log(this);//[10, 20, 30]
}
var fn2 = fn.bind( [10, 20, 30] ); // fn2 是创建的新函数,新函数和fn长的一样。
console.log(fn === fn2); // false
//fn和fn2长的一样,但是在内存中是两份函数,地址是不一样。
fn2();
//fn2函数是由bind创建出来的, fn2函数内的this指向被固定了,所以this指向了[10, 20, 30]
//固定的理解: 不论fn2 函数的调用模式是何种,fn2内的this指向被固定写死了。
bind修改定时器this指向
var obj = {
name: '吕布',
sex: '男',
age: 18,
hi: function () {
setTimeout(function () {
console.log(this);//window
//定时器中的this指向了window,window上没有age属性
console.log('我的年龄是' + this.age);//我的年龄是undefined
}, 1000)
}
}
obj.hi()
解决方法:
var obj = {
name: '吕布',
sex: '男',
age: 18,
hi: function () {
setTimeout(function () {
console.log(this);//obj
console.log('我的年龄是' + this.age);//我的年龄是18
}.bind(this), 1000)//注意这个this不在定时器函数内部,指向的是obj
}
}
obj.hi()
拓展:
以下两种方法同样可以解决定时器指向window的问题
方法一:var that = this;
var obj = {
name: '吕布',
sex: '男',
age: 18,
hi: function () {
//把想要的this指向使用变量that存储了起来。
var that = this;
setTimeout(function () {
console.log(this);//window
//把this的指向赋值给变量that,that也就指向了obj
console.log('我的年龄是' + that.age);//我的年龄是18
}, 1000)
}
}
obj.hi()
方法二:箭头函数;
var obj = {
name: '吕布',
sex: '男',
age: 18,
hi: function () {
setTimeout(() => {
// 箭头函数内部没有自己的this, 使用的是外部函数的this
console.log(this);//obj
console.log('我的年龄是' + this.age);//我的年龄是18
}, 1000)
}
}
obj.hi()
小结:
- call apply 作用是一样 ,唯一不同的是,call需要一个一个传参,apply可以传数组或伪数组。
- apply有平铺性: 将apply的第二个参数数组里面的每一项取出来作为函数的实参。
- bind 创建并返回新函数,不会来调用函数的。