JavaScript中的每一个function对象的原型上都会有call,apply和bind方法.都是用于改变函数运行时上下文,最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。
call()的理解 B.call(A, args1,args2)
call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法. 上代码
let cat = {
name: 'cat',
}
let dog = {
name: 'dog',
eat(a,b){
console.log(this.name+`在吃${a}在喝${b}`);
}
}
两种动物都有吃这个行为,要用cat调用dog上的方法.
dog.eat.call(cat,'猫粮','水');
Math.max.call(null,1,2,3,4,5);
此时我们就cat对象调用dog对象上的方法完成了. 实现一个自己封装的call.
Function.prototype.myCall = function(context){
console.log(context) // 相当于传进来的 cat对象
context = context || window; // 有可能传进来null
// 这里的this相当于dog.eat,相当于在cat对象上创建了一个方法
context.fn = this; //
var args = []; // 接收其余的参数
var res; // 返回结果
// 通过arguments接收其余传进来的参数
for (var i = 1;i<arguments.length;i++){
args.push(arguments[i])
}
res = context.fn(...args); // 执行函数
delete context.fn;
return res;
}
dog.eat.myCall(cat,'猫粮','水');
apply()的理解 B.apply(A,[args1,args2]);
apply()本质上跟call()的区别不大,只是传参的时候,call()可以多个传参,而apply()的第二个参数为数组或类数组. 直接来封装的源码解析
Function.prototype.myApply = function(context,argsArr){
context || context || window;
context.fn = this;
var args = [];
var res;
for(var i = 0;i<argsArr.length;i++){
args.push(argsArr[i])
}
res = context.fn(...args)
delete context.fn
return res;
}
dog.eat.myApply(cat,'猫粮','水');
apply和call的区别:
在于将参数传递给函数。 call():使用其自有的实参列表作为函数的参数; apply():要求以数组的形式传入参数
bind B.bind(A, args1,args2)(args3)
let catEat = dog.eat.bind(cat,"猫粮","水")
catEat("哈哈哈 哈");
bind的不是立即执行,bind会返回一个函数,(柯理化函数思想)
Function.prototype.myBind = function(context,...args){
// =>THIS: FN(当前需要处理的函数)
// => CONTEXT: OBJ(需要把FN中的THIS改为谁就传递谁);
// => ARG: 传递哥FN的实参(数组); ["猫粮","水"]
// 返回一个匿名函数
/*
* 每次执行BIND,都形成一个不销毁的私有栈内存,返回一个新的匿名函数(每一次返回的不一样:不是相同的堆内存)
* 存储内容
* =>THIS: FN(当前需要处理的函数)
* => CONTEXT: OBJ(需要把FN中的THIS改为谁就传递谁);
* => ARG: 传递哥FN的实参(数组); [ev]
*
* dog.eat = function anonymous(){ }
*/
let that = this; // 此时的this相当于是当前需要处理的函数
return function anonymous(...innerArg){
that.apply(context,args.concat(innerArg))
}
}
bind()和apply(),call()的区别
bind()返回一个函数,不会立即执行
apply(),call()会立即执行.