|
前言
我相信对于call,applay,bind三者之前的用法与区别,小伙伴们肯定都很清楚了,毕竟这也是面试的高频试题,之前面试的时候,当面试官提到call的时候我可是心花怒放,正准备侃侃而谈的时候,面试官说请用js模拟call的用法,限时5分钟。当时就懵了,脑子里只有它的各种用法,但内部究竟如何实现的,还真没有研究过,当时就唱了一首凉凉给自己。失败不可怕,所以今天特写文一篇,纪念自己逝去的面试。
Call
改变函数的执行上下文,相当于将某个函数的指定于特定的对象下执行
Function.prototype.call = function (context) {
let context = context || window;
context.fn = this;
let args = [];
for(let i = 1, len = arguments.length; i < len; i++) {
let temp = 'arguments['+ i +']';
args.push(temp);
}
let result = eval('context.fn(' + args +')'); // 这里会主动调用Arrary.toString()方法
delete context.fn;
return result;
}
Apply
Function.prototype.apply = function (context, arr) {
let context = Object(context) || window;
context.fn = this;
let result;
if (!arr) {
result = context.fn();
} else {
let args = [];
for (let i = 0, len = arr.length; i < len; i++) {
args.push('arr['+ i +']');
}
result = eval('context.fn(' + args + ')')
}
delete context.fn;
return result;
}
bind
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。即bind函数的特点是:返回一个函数,可以传入参数。而且一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
Function.prototype.bind2 = function (context) {
if (typeof this !== "function") {
throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
var fNOP = function () {};
fNOP.prototype = this.prototype;
var fBound = function () {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
}
fBound.prototype = new fNOP();
return fBound;
}
function objectFactory() {
var obj = new Object(),
Constructor = [].shift.call(arguments); // 取出第一个参数,即是我们要传入的构造函数。此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数
obj.__proto__ = Constructor.prototype; // Object.setPrototypeOf(obj, Constructor.prototype)
// 上述步骤是为了指向正确的原型,还可以使用空函数来中转实现
// var Fn = new Function();
// Fn.prototype = Constructor.prototype;
// obj = new Fn();
var ret = Constructor.apply(obj, arguments);
return typeof ret === 'object' ? ret||obj : obj; //确保构造器总是返回一个对象
};
【注意】参考文档:https://github.com/mqyqingfeng/Blog/issues/11
|