前言
Javascript提供的内置函数Function.prototype.call(),Function.prototype.apply(),Function.prototype.bind()允许我们显示的绑定函数执行时的this,其原理使用了元编程技术,这种技术的背后是JS引擎根据变量,函数,对象的内置属性和元属性来决定执行方式。而模拟实现只是近似模拟与内置函数相同的行为,但远没有内置函数精妙,也不可作为解释内置函数的理论依据。能让Javascript跑起来的是JS引擎,只有懂JS引擎的工作原理才能让我们探视到内置函数的真面目,这也是我们深入了解后要检视的领域。
我们入门时需要学习什么?我们能够学习到什么?任何知识的学习像一个爬楼梯的过程,爬的越高,越心旷神怡,醍醐灌顶。我们入门时需要学会的是一种推导能力,用已学知识推导新知识;一种想象能力,想象那些可能性,然后大胆尝试,找到答案。
1. bind()原理
一个函数执行需要具备3个已知条件:函数引用(必须),this绑定(可选),arguments(可选)。而内置函数bind恰恰使用3个属性记录这3个东西。baz是bind()返回的硬绑定函数,baz.name记录了目标函数的名字,[[TargetFunction]]属性记录目标函数,[[BoundThis]]记录目标函数执行时绑定的this,[[BoundArgs]]记录目标函数执行时绑定的实参。
2. 自定义myBind模拟Bind()功能
Function.prototype.myBind = function (oThis){
//debugger;
if(typeof this!=="function") {
throw new TypeError("Function.prototype.myBind-what" + "is trying to be bound is not callable")
};
//局部变量aArgs存储myBind函数的实参
var aArgs = Array.prototype.slice.call(arguments,1),
fToBind = this,
fNOP = function (){},//圣杯模式,用于创建fBound函数原型的中间函数
fBound = function () {
return fToBind.apply(
(
//fNOP.prototype在New fBound()构造的实例的原型链上
this instanceof fNOP && oThis ? this: oThis),
//拼接myBind函数的实参和硬绑定函数fBound的实参后,传递给目标函数fToBind
aArgs.concat(Array.prototype.slice.call(arguments)
));
};
//圣杯模式
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
//fBound.prototype.constructor = fBound;
//fBound.prototype.uber = this.prototype;
return fBound;
};
debugger;
function foo(a,b) {
this.a = a;
this.b = b;
}
var obj1 = {};
var baz = foo.myBind(obj1,2);
baz(3);
console.log(obj1);//{a:2,b:3}
var obj2 = new baz(4);//fBound {a:2,b:4}
console.log(obj2);
允许new进行覆盖的部分是这里:
this instanceof fNOP && oThis ? this : oThis
// .....和
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();