# apply bind call 用法
call、apply和bind是 Function对象 自带的三个方法,都是为了 改变函数体内部this指向 。三者第一个参数都是 this 要指向的对象,也就是想指定的上下文;apply 、 call 、bind 三者都可以利用后续参数传参;bind是返回对应函数,便于调用;apply 、call 则是立即调用 。
# bind
function.bind(thisArg[, arg1[, arg2[, ...]]])
thisArg:调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用bind在setTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。
# call apply
var name="wang",age=17;
var obj={
name:"zhang",
objage:this.age,
myFun:function(){
console.log(this.name+"年齡"+this.age)
}
}
console.log(obj.objage) // 17
console.log(obj.myFun()) //zhang年齡undefined 需要办法改变this指向
var name="wang",age=17;
var obj={
name:"zhang",
objage:this.age,
myFun:function(from,go){
console.log(this.name+"年齡"+this.age,"来自"+from+"去"+go)
}
}
var k1={
name:"k1",
age:18
}
console.log(obj.myFun.bind(k1)('上海','芜湖')) //k1年齡18 来自上海去芜湖
console.log(obj.myFun.call(k1,'上海','芜湖')) //k1年齡18 来自上海去芜湖
console.log(obj.myFun.apply(k1,['上海','芜湖'])) //k1年齡18 来自上海去芜湖
| - | 描述 |
|---|---|
| call | 立即调用;后面第一个参数为对应指向的对象;随后的参数均为调用函数的参数。 |
| apply | 立即调用;第一个参数同上,随后的参数均写入一个数组作为参数。 |
| bind | 给出函数,需另外调用,第一个参数同上。 |
# 手写apply,call,bind
call/apply/bind的核心理念:借。
借助已实现的方法,改变方法中数据的this指向,减少重复代码,节省内存。
Function.prototype.myCall = function(context) {
console.log(this) //fn a()
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
console.log(context)//obj
context.fn = this
console.log(typeof context.fn)//function
const args = [...arguments].slice(1)
console.log(args)
//通过隐式绑定的方式调用函数
const result = context.fn(...args)
//删除添加的属性
delete context.fn
//返回函数调用的返回值
return result
}
let obj ={
name:333
}
function a(){
console.log(this.name)
}
a.myCall(obj)
Function.prototype.myApply = function(context) {
if (typeof this !== 'function') {
throw new TypeError('Error')
}
context = context || window
context.fn = this
let result
// 处理参数和 call 有区别
if (arguments[1]) {
result = context.fn(...arguments[1])
} else {
result = context.fn()
}
delete context.fn
return result
}
如果怕重复key值(fn),可以使用Symbol
/**
* 自定义call实现
* @param context 上下文this对象
* @param args 动态参数
*/
Function.prototype.ownCall = function(context, ...args) {
context = (typeof context === 'object' ? context : window)
// 防止覆盖掉原有属性
const key = Symbol()
// 这里的this为需要执行的方法
context[key] = this
// 方法执行
const result = context[key](...args)
delete context[key]
return result
}
注意bind的用法,bind可以分批添加参数,所以需要拼接,而且bind返回的是函数,考虑兼容new的情形。
Function.prototype.myBind = function(context, ...args) {
const originalFunction = this;
// 返回一个新函数
return function F(...boundArgs) {
// 如果通过 new 调用,则忽略 context,使用新创建的实例
if (this instanceof F) {
// 相当于执行 new originalFunction(...args, ...boundArgs)
return new originalFunction(...args, ...boundArgs);
}
// 否则,使用提供的 context 和合并的参数调用原函数
return originalFunction.apply(context, args.concat(boundArgs));
};
};
// 使用示例
function MyConstructor(a, b) {
this.a = a;
this.b = b;
}
MyConstructor.prototype.getValue = function() {
return this.a + this.b;
};
const boundConstructor = MyConstructor.myBind(null, 1);
// 使用 new 调用 boundConstructor
const instance = new boundConstructor(2);
console.log(instance.getValue()); // 输出 3
// 普通函数调用
const result = boundConstructor(3);
console.log(result); // 输出 MyConstructor 的返回值,如果没有显式返回,则为 undefined