// 使用原生的ES3语法实现的call
Function.prototype._call = function() {
var context = context || window;
context.fn = this;
var args = [];
for (var i = 1, len = arguments.length; i < len; i++) {
args.push('arguments['+ i +']')
}
var res = eval('context.fn('+ args +')');
delete context.fn;
return res;
}
// 使用ES6语法实现一个call
Function.prototype._call = function() {
let context = arguments[0];
context.fn = this;
let args = [];
for (let i = 0, len = arguments.length; i < len; i++) {
args.push(arguments[i]);
}
// 把数组转换为一个伪数组
let res = context.fn({...args});
delete context.fn;
return res;
}
// 原生JS实现
Function.prototype._apply = function(context, arr) {
var context = Object(context) || window;
context.fn = this;
let res;
if (!arr) {
res = context.fn();
}
else {
var args = [];
for (var i = 0, len = arr.length; i < len; i++) {
args.push('arr['+i+']');
}
res = eval('context.fn('+args+')');
}
delete context.fn;
return res;
}
// 使用ES6语法实现的apply
Function.prototype._apply = function(context) {
context = context || window;
context.fn = this;
let res;
if (arguments[1]) {
// array
res = context.fn(...arguments[1]);
}
else {
// none args
res = context.fn();
}
delete context.fn;
return res;
}
// 原生JS 的实现
Function.prototype._bind = function(context) {
if (typeof this !== 'function') {
throw new Error('error callback');
}
var self = this;
var args = Array.prototype.slice.call(arguments, 1);
// 注意:这里如果直接将 fBound.prototype = this.prototype
// ,我们直接修改 fBound.prototype 的时候,也会直接修改绑定函数的 prototype。
// 解决方案:这个时候,我们可以通过一个空函数来进行中转
var fnOP = function() {};
var fnBind = function() {
var bindArgs = Array.prototype.slice.call(arguments);
return self.apply(this instanceof fnOP
? this
: context
, args.concat(bindArgs));
}
// 通过间接地去修改这个中间函数的原型对象,new 的方式来避免直接修改原型上面的属性和对象参数信息
fnOP.prototype = this.prototype;
// 这里不就是原型链继承的实现吗?
fnBind.prototype = new fnOP();
return fnBind;
}
// ES6的写法一
Function.prototype._bind = function(context, ...args) {
let self = this;
return function() {
self.apply(context, args.concat(Array.prototype.slice.call(arguments)));
}
}
// ES6的写法二
Function.prototype._bind = function(context) {
context = context || window;
let args = Array.prototype.slice.call(arguments, 1);
let self = this;
// 构建一个中间的函数,维护原型之间的关系
let temp = function(){};
let F = function() {
self.apply(this instanceof temp
? this
: context
, args.concat(Array.prototype.slice.call(arguments)))
}
// 通过中间函数维护原型关系
temp.prototype = this.prototype;
F.prototype = new temp();
return F;
}