相关概念
bind 是返回对应函数,便于稍后调用;
apply 、call 则是立即调用。
在 javascript 中,call 和 apply、bind 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向。
JavaScript 的一大特点是,函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
call
第一个参数: 设置this的指向,如果指定了 null 或者 undefined 则内部 this 指向 window
其他参数: 对应函数的参数- call的返回值就是函数的返回值
let obj = {
name: '小刚',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj1 = {
name: '小虽',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj2 = {
name: '小华',
say: function (...args) {
console.log(this.name + 'say',args);
},
};
obj.say(1,2); // 小刚say [1, 2]
obj.say.call(obj1, 1, 2); // 小虽say [1, 2]
obj.say.call(obj2, 1, 2); // 小华say [1, 2]
apply
-
第一个参数 : 设置函数内部this的指向
第二个参数 : 是数组
-
call的返回值就是函数的返回值
let obj = {
name: '小刚',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj1 = {
name: '小虽',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj2 = {
name: '小华',
say: function (...args) {
console.log(this.name + 'say',args);
},
};
function fn(...args){
obj.say(...args); // 小刚say [1, 2]
obj.say.apply(obj1, args); // 小虽say [1, 2]
obj.say.apply(obj2, args); // 小华say [1, 2]
}
fn(1,2);
bind
-
bind() 函数会创建一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。
-
当目标函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。
-
一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
let obj = {
name: '小刚',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj1 = {
name: '小虽',
say: function (...args) {
console.log(this.name + 'say', args);
},
};
let obj2 = {
name: '小华',
say: function (...args) {
console.log(this.name + 'say',args);
},
};
function bindFn(...args){
obj.say(...args); // 小刚say [1, 2]
obj.say.bind(obj1, ...args)(); // 小虽say [1, 2]
obj.say.bind(obj2, ...args)(); // 小华say [1, 2]
}
bindFn(1,2);
自定义实现
call
function myCall(context) {
//判断一下
if (typeof this !== 'function'){
throw new TypeError('error')
}
//this指向,谁去执行去这个函数
context = context || window;
//要执行的函数
context.fn = this;
//取出参数
const args = [...arguments].slice(1);
//执行函数
const result = context.fn(...args);
//删除fn
delete context.fn;
return result;
}
apply
function myApply(context) {
if (typeof this !== 'function') {
throw new TypeError('Error');
}
context = context || window;
context.fn = this;
var result;
if (arguments[1]) {
result = context.fn(...arguments[1]);
} else {
result = context.fn();
}
delete context.fn;
return result;
}
bind
function myBind(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
const _this = this
const args = [...arguments].slice(1)
// 返回函数
return function F() {
// 1 判断是否用作构造函数
if (this instanceof F) {
return new _this(...args, ...arguments)
}
// 2 用作普通函数
return _this.apply(context, args.concat(...arguments))
}
}
var f1 = test.myBind(obj, 1)
var f= new f1(2)