js-challenges
js-challenges copied to clipboard
call apply bind
Function.prototype.call2 = function(context, ...args) {
context = (context === undefined || context === null) ? window : context
context.__fn = this
let result = context.__fn(...args)
delete context.__fn
return result
}
Function.prototype.apply2 = function(context, args) {
context = (context === undefined || context === null) ? window : context
context.__fn = this
let result = context.__fn(...args)
delete context.__fn
return result
}
Function.prototype.bind2 = function(context, ...args1) {
context = (context === undefined || context === null) ? window : context
let _this = this
return function(...args2) {
context.__fn = _this
let result = context.__fn(...[...args1, ...args2])
delete context.__fn
return result
}
}
Function.prototype._call = function (obj, ...args) {
!obj && (obj = globalThis);
// this代表要执行的函数
obj._fn = this;
const res = obj._fn(...args);
delete obj._fn;
return res;
};
Function.prototype._apply = function (obj, args) {
// 第二个参数必须为数组或类数组对象, 否则初始化为空对象
const arr = [];
for (let i = 0; i < args?.length; ++i) {
arr.push(args[i]);
}
return this._call(obj, ...arr);
};
Function.prototype._bind = function (obj, ...args1) {
!obj && (obj = globalThis);
return (...args2) => {
obj._fn = this;
const res = obj._fn(...[...args1, ...args2]);
delete obj._fn;
return res;
};
};
Function.prototype._myCall = function(thisArg, ...args) {
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
let fn = Symbol();
thisArg[fn] = this;
const res = thisArg[fn](...args);
delete thisArg[fn];
return res;
};
Function.prototype._myapply = function(thisArg, args = []) {
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
let fn = Symbol();
thisArg[fn] = this;
const res = thisArg[fn](...args);
delete thisArg[fn];
return res;
};
Function.prototype._mybind = function(thisArg, ...args) {
let fn = this;
return (...args) => {
return fn._myCall(thisArg, ...args);
};
};
//最好使用symbol进行处理一下,以及对于apply传递的数组考虑一下为空的情况
// 该代码为上面同学提交的,虽然考虑到了边界条件,更加严谨,但是是有问题的,会使始终指向全局对象window
// 问题就出在这个箭头函数,因为箭头函数的特性,会无法获得到正确的this,即调用call的函数
// !!!处理方式:更改为function(){}即可
Function.prototype._myCall = (thisArg, ...args) => {
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
let fn = Symbol();
thisArg[fn] = this;
const res = thisArg[fn](...args);
delete thisArg[fn];
return res;
};
// 同理
Function.prototype._myapply = (thisArg, args = []) => {
thisArg =
thisArg !== null && thisArg !== undefined ? Object(thisArg) : window;
let fn = Symbol();
thisArg[fn] = this;
const res = thisArg[fn](...args);
delete thisArg[fn];
return res;
};
// 同理
Function.prototype._mybind = (thisArg, ...args) => {
let fn = this;
return (...args) => {
return fn._myCall(thisArg, ...args);
};
};
//最好使用symbol进行处理一下,以及对于apply传递的数组考虑一下为空的情况
// 该代码为上面同学提交的,虽然考虑到了边界条件,更加严谨,但是是有问题的,会使始终指向全局对象window // 问题就出在这个箭头函数,因为箭头函数的特性,会无法获得到正确的this,即调用call的函数 // !!!处理方式:更改为function(){}即可 Function.prototype._myCall = (thisArg, ...args) => { thisArg = thisArg !== null && thisArg !== undefined ? Object(thisArg) : window; let fn = Symbol(); thisArg[fn] = this; const res = thisArg[fn](...args); delete thisArg[fn]; return res; }; // 同理 Function.prototype._myapply = (thisArg, args = []) => { thisArg = thisArg !== null && thisArg !== undefined ? Object(thisArg) : window; let fn = Symbol(); thisArg[fn] = this; const res = thisArg[fn](...args); delete thisArg[fn]; return res; }; // 同理 Function.prototype._mybind = (thisArg, ...args) => { let fn = this; return (...args) => { return fn._myCall(thisArg, ...args); }; }; //最好使用symbol进行处理一下,以及对于apply传递的数组考虑一下为空的情况
收到,已改正,感谢
Function.prototype.myCall = function(context, ...args) {
context = context || window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
}
Function.prototype.myApply = function(context, args) {
context = context || window;
const fn = Symbol();
context[fn] = this;
const result = context[fn](...args);
delete context[fn];
return result;
}
Function.prototype.myBind = function(context, ...args) {
const self = this;
return function(...args2) {
return self.apply(context, args.concat(args2));
}
}
用Object.create继承context也许可以避免污染原来的context
Function.prototype.myapply = function (context, args) {
context = context || window;
args = args || [];
const key = Symbol();
context[key] = this;
const res = context[key](...args); //扩展运算符对参数进行深拷贝的浅层拷贝
delete context[key];
return res;
};
Function.prototype.mycall = function (context, ...args) {
context = context || window;
args = args || [];
const key = Symbol();
context[key] = this;
const res = context[key](...args);
delete context[key];
return res;
};
Function.prototype.mybind = function (context, ...args) {
let self = this;
args = args || [];
return function (...newargs) {
const key = Symbol();
context[key] = self;
const res = context[key](...args, ...newargs);
delete context[key];
return res;
};
};
Function.prototype.myCall = function (context, ...args) {
context = context || window
args = args || []
const key = new Symbol()
context[key] = this
const res = context[key](...args)
delete context[key]
return res
}
Function.prototype.myApply = function (context, args) {
context = context || window
args = args || []
const key = new Symbol()
context[key] = this
const res = context[key](...args)
delete context[key]
return res
}
Function.prototype.myBind = function (context, ...args) {
let self = this
args = args || []
return function (...newargs) {
const key = Symbol()
context[key] = self
const res = context[key](...args, ...newargs)
delete context[key]
return res
}
}
Function.prototype.call = function (context, ...args) {
context.fn = this;
return context.fn(...args);
};
Function.prototype.apply = function (context, args) {
context.fn = this;
return context.fn(...args);
};
Function.prototype.bind = function (context, ...args) {
context.fn = this;
return function (...args1) {
return context.fn(...args, ...args1);
};
};
前面有一个bind写错了 Function.prototype._mybind = (thisArg, ...args) => { let fn = this; return (...args) => { return fn._myCall(thisArg, ...args); }; }; ======================================> Function.prototype._mybind = function (thisArg, ...arg1) { let fn = this return function (...arg2) { return fn._myCall(thisArg, ...arg1, ...arg2) } }
💯 仍然是不太严谨,原始类型值作为 context时,需要转为对象
Function.prototype.myCall = function(context, ...args) {
context = (context === undefined || context === null) ? window : context
if (Object(context) !== context) {
context = Object(context)
}
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
function add(params) {
return this.a + params
}
console.log(add.myCall(0, 2))
console.log(add.call(0, 2, 3, 4))
apply的话,第二个参数要求类数组,为 null 的话要不报错,边界条件比较多 😢
Function.prototype.myApply = function(context, args = []) {
context = (context === undefined || context === null) ? globalThis : context
if (Object(context) !== context) {
context = Object(context)
}
args = args === null ? [] : args
if (!Array.isArray(args)) {
args = Array.from(args)
}
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
// test case
const array = ["a", "b"];
const elements = [0, 1, 2];
array.push.myApply(array, 0);
console.log('myApply', array);
console.log('myApply', Math.max.myApply(null, null))
console.log('apply', Math.max.apply(null, null))
这个更复杂点,只因规范要求 如果使用 new 运算符构造绑定函数,则忽略该值(指context参数)。
参考 core-js 的实现,并用 es6 语法简化
Function.prototype.myBind = function (that, ...partArgs) {
var F = this
var Prototype = F.prototype
var boundFunction = function bound(...newArgs) {
var args = [...partArgs, ...newArgs]
/**
* 若被 new 调用时,this 为即将生成的实例 bound,走 new F(...)
*/
return this instanceof boundFunction ? new F(...args) : F.myApply(that, args)
}
if (Prototype && typeof Prototype === 'object') boundFunction.prototype = Prototype
return boundFunction
}
// es6中globalThis代指当前环境全局对象
Function.prototype._call = function (context, ...args) {
if (!context) context = globalThis;
context._fn = this;
const result = context._fn(...args);
delete context._fn;
return result;
};
Function.prototype._apply = function (context, args) {
if (!context) context = globalThis;
context._fn = this;
const result = context._fn(...args);
delete context._fn;
return result;
};
Function.prototype._bind = function (context, ...args1) {
if (!context) context = globalThis;
let _this = this;
return function (...args2) {
context._fn = _this;
let result = context._fn(context, ...args1, ...args2);
delete context._fn;
return result;
};
};
Function.prototype.Mycall = function (ctx, ...args) {
ctx = (ctx === undefined || ctx === null) ? (window || global) : Object(ctx);
const fn = this;
const key = Symbol('fn');
Object.defineProperty(ctx, key, {
enumerable: false,
value: fn
})
const result = ctx[key](...args);
delete ctx[key];
return result;
}
Function.prototype.MyBind = function (ctx, args) {
ctx = (ctx === undefined || ctx === null) ? (window || global) : Object(ctx);
const fn = this;
const key = Symbol('fn');
Object.defineProperty(ctx, key, {
enumerable: false,
value: fn
})
const result = ctx[key](...args);
delete ctx[key];
return result;
}
Function.prototype.MyBind = function (ctx, ...args) {
ctx = (ctx === undefined || ctx === null) ? (window || global) : Object(ctx);
const fn = this;
const key = Symbol('fn');
return function (...args2) {
let result = null;
Object.defineProperty(ctx, key, {
enumerable: false,
value: fn
})
if (new.target) {
result = new ctx[key](...args, ...args2)
}
else {
result = ctx[key](...args, ...args2)
}
delete ctx[key];
return result;
}
}