2.new、apply、bind、call的模拟实现
2020-07-03 本文已影响0人
原来哥哥是万家灯火
1.new的模拟实现
function mockNew(constructor, argsArr) {
var obj = {};
obj.__proto__ = constructor.prototype;
let result = constructor.apply(obj, argsArr);
if (result instanceof Object) {
return result;
}
return obj;
}
2.apply的模拟实现
原理很简单,将函数赋值成context的方法,调用函数,删除方法,返回值
Function.prototype.mockApply = function(context, argsArr) {
var fn = this;
var argReferenceArr = [];
var globalContext = (typeof window === 'undefined')? global: window;
context = (context instanceof Object)? context: globalContext;
for (var i=0,len = argsArr.length; i<len; i++) {
argReferenceArr.push('argsArr[' + i + ']')
}
context.f = fn;
var result = eval('context.f(' + argReferenceArr.toString() + ')');
delete context.f;
return result;
}
3.call的模拟实现
Function.prototype.mockCall = function(context) {
var fn = this;
var argReferenceArr = [];
var globalContext = (typeof window === 'undefined')? global: window;
context = (context instanceof Object)? context: globalContext;
for (var i=1,len = arguments.length; i<len; i++) {
argReferenceArr.push('arguments[' + i + ']')
}
context.f = fn;
console.log(argReferenceArr)
var result = eval('context.f(' + argReferenceArr.toString() + ')');
delete context.f;
return result;
}
4.bind的模拟实现
bind相对复杂点,其参数可以分两次传递,如:f.bind(o, arg1)(arg2)
另还可以当做构造函数调用,生成的实例的构造函数是f,如:
function Human(name, age) {
this.name = name;
this.age = age;
}
let f = Human.bind(null, '张三');
let man = new f(20);
console.log(man.contructor);
打印结果:构造函数是Human
模拟实现如下:
Function.prototype.mockBind = function (context) {
var fn = this;
var outerArgs = [];
var outerArgsReference = [];
var globalContext = (typeof window === 'undefined') ? global : window;
context = (context instanceof Object) ? context : globalContext;
for (var i = 1, len = arguments.length; i < len; i++) {
outerArgs[i-1] = arguments[i];
outerArgsReference[i-1] = 'outerArgs[' + (i-1) + ']';
}
function bound () {
var innerArgsReference = [];
for (var i = 0, len = arguments.length; i < len; i++) {
innerArgsReference[i] = 'arguments[' + i + ']';
}
var args = outerArgsReference.concat(innerArgsReference).toString();
context = this instanceof fn? this: context;
context.fn = fn;
var result = eval('context.fn(' + args +')');
delete context.fn;
return result;
}
function F() {}
F.prototype = fn.prototype;
bound.prototype = new F();
return bound;
}
调用apply简化版:
Function.prototype.mockBind = function (context) {
var fn = this;
var outerArgs = Array.prototype.slice.apply(arguments, [1]);
function bound () {
var innerArgs = [].slice.apply(arguments, [0]);
return fn.apply(this instanceof fn? this: context, outerArgs.concat(innerArgs));
}
function F() {}
F.prototype = fn.prototype;
bound.prototype = new F();
return bound;
}