之前写了关于bind(..) polyfill 代码的理解,记录了自己的你不知道的JavaScript(上卷)93页提及的bind() polyfill 代码的一些理解,书中提到
由于 polyfill 并不是内置函数, 所以无法创建一个不包含 .prototype的函数, 因此会具有一些副作用。
关于这一点,我是不明所以的。而在阅读到书中的156页时才发现了二者的一些区别:
- 内置函数没有 .prototype 属性的。 在这样的函数上使用 instanceof 的话,目标函数的 .prototype 会代替硬绑定函数的 .prototype。而自定义的bind()是有 .prototype
- 利用new创建使用了硬绑定(bind)的函数时,虽然不管是内置函数还是polyfill 代码,其构造的对象均指向硬绑定(bind)的函数的点prototype,但是new 的函数是不一样的,使用内置函数相当于new的是目标函数,而polyfill 代码new的是fBound对象。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
// 强制使用自定义的bind
// 通过注释或者不注释这段代码可以看到使用内置函数和自定义的bind的区别
// 本来这一句是if (!Function.prototype.bind) { ,在浏览器不兼容bind时添加自定义的bind方法,为了测试,强制浏览器使用自定义的bind
if (true) {
Function.prototype.bind = function(oThis) { // oThis在本例中就是obj
// 做的事:判断调用bind方法的对象是不是一个函数function,若不是则报错
// 也就是说此方法只能是函数调用吗?这部分没太理解为什么要这样做
if (typeof this !== "function") {
// 与 ECMAScript 5 最接近的
// 内部 IsCallable 函数
throw new TypeError( "Function.prototype.bind - what is trying " + "to be bound is not callable" );
}
// Array.prototype.slice.call将类数组转换为数组,同时剔除了传入的第一个参数,即对象,而如果除了对象,还传入了其他参数,则参数会保留
// 把除了第一个参数(第一个参数用于绑定 this) 之外的其他参数都传给下层的函数(这种技术称为“部分应用”, 是“柯里化” 的一种)
var aArgs = Array.prototype.slice.call( arguments, 1 ),
fToBind = this, // 本例中this就是foo
fNOP = function(){},
fBound = function(){
debugger;
return fToBind.apply(
// 如果this的原型链上有fNOP并且oThis转换为布尔值是true才用本来指向的this,否则将它转成oThis
// 这里就是判断是否要修改绑定的对象了
// 这里我的理解是如果this instanceof fNOP并且oThis是undefined或null等,就认为开发者是特意这样设置的,按照开发者的意愿绑定对象,
// 但是this instanceof fNOP 这句又是什么意思呢
// this 的原型链上有fNOP的原型才会是true,什么情况下它会是true呢?
// 我认为这里是为了保持绑定的优先级(p94页)
// 优先级: new > 显示绑定 > 隐式绑定 > 默认绑定
// 原文说:这段代码会判断硬绑定函数是否是被 new 调用, 如果是的话就会使用新创建的 this 替换硬绑定的 this。
// 回忆一下,fBound的原型是fNOP构造的对象,那么当fBound作为构造函数,也就是说new调用时this指向的就是fNOP构造的对象,此时this 的原型链上有fNOP的原型,此时会返回true
// 也就是说这句话的意思是开发者用了new调用同时开发者传入的显示绑定对象不是null或者undefined这种值时,使用新创建的 this
// 否则显式调用都会生效
(this instanceof fNOP && oThis ? this : oThis ),
// 将之前的参数和新传入的参数拼接起来
aArgs.concat( Array.prototype.slice.call( arguments ) )
);
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
};
function Person(name){
this.name = name;
}
var obj = {name:"obj的name"};
var tmp = Person.bind(obj);
var one = new Person('one');
console.log( one instanceof tmp); // 使用自定义的bind返回false,原生是true,因为内置函数没有 .prototype 属性的。 在这样的函数上使用 instanceof 的话,目标函数的 .prototype 会代替硬绑定函数的 .prototype。
// 另外,
var two = new tmp('two');
console.log(two); // 内置:Person {name: "two"} 自定义:fBound {name: "two"}
console.log(two instanceof tmp) // 内置的返回true 自定义:true
</script>
</body>
</html>