乐趣区

call&apply&bind的js实现以及应用

js 实现 call
// example
let obj = {
a: 124,
b: ‘ccc’
};
function fn(c) {
return this.a + this.b + this.c;
}
// 使用 call 是这样转换的
// step 1: 生成新的函数,新的执行上下文 (通过在传入对象中增加调用方法)
const obj = {
a: 124,
b: ‘ccc’,
fn: function(c) {
return this.a + this.b + this.c;
}
}
// step2: 执行 obj.fn(333);
let res = obj.fn(333);
// step3: obj 被改变,得恢复原来的值
delete obj.fn;
Function.prototype.myCall = function(context) {
const newContext = context || window;
newContext.fn = this;
const args = [];
for(let i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
const res = newContext.fn(…args);
delete newContext.fn;
return res;
}
console.log(fn.myCall(obj, ‘cccc’));
js 实现 apply
Function.prototype.myApply = function(context, arr) {
const newContext = context || window;
newContext.fn = this;
const args = [];
let res;
if (!arr) {
res = newContext.fn(…args);
}
else {
if (!(arr instanceof Array)) {
throw new Error(‘params must be array’);
}
result = context.fn(…arr);
}
delete newContext.fn;
return res;

}
console.log(fn.myApply(obj, [‘cccc’]));
call & apply
Math.max.apply(null, [3,5,88,2]) 在这里,我们看到了一个有趣的现象,在 Math.max 中可以传入数组 call&apply 两大作用:
改变 this 借用其他对象的方法
改变 this
如何实现 Function.prototype.bind()
Function.prototype.bind = function(){
var self = this,
context = [].shift.apply(arguments);
args = [].slice.apply(arguments);

return function(){
return self.apply(context, [].concat.apply(args, [].slice.apply(arguments)))
};
}

// 执行
var obj = {
name: ‘yyh’
}
var func = function(a, b, c, d){
console.log(this.name);
}.bind(obj, 1, 2);
func(3, 4);
借用其他对象的方法
继承的实现
var aFn = function(){
this.name = ‘yyh’
}
var bFn = function(){
aFn.apply(this, arguments);
}
bFn.prototype.getName = function(){
return this.name
}
// 执行
var b = new bFn();
console.log(b.getName())
能借用数组的方法,Obj.array.push, 需要满足两个条件

Obj 的属性可存取
length 属性可读写

var a = {c:3};
[].push.apply(a, [3,4,5])
console.log(a)

退出移动版