最近看了一篇颜大的文章从一道面试题的进阶,到“我可能看了假源码”
看到后面发现有一个不懂的地方:
为了实现红框内的兼容:
其中红框圈出的代码小弟不是很懂,希望有大神能够指点一二
最近看了一篇颜大的文章从一道面试题的进阶,到“我可能看了假源码”
看到后面发现有一个不懂的地方:
为了实现红框内的兼容:
其中红框圈出的代码小弟不是很懂,希望有大神能够指点一二
搞了好久细节,终于搞清楚了跟你说说,也在这里做个笔记,不是很会描述,见谅:
首先,先看bind
文档,经过bind
的方法,如果使用new
的话,会忽略bind
的context
,而是用新生成的实例对象作为this
。
其次,再看看instanceof
的文档,instanceof
返回的结果是: 原型链中是否存在一个构造函数的 prototype 属性
。
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
所以,这里用F
先保存当前的prototype
,然后通过bound.prototype = new F()
让bound
继承this.prototype
里面的属性,而通过new bound()
生成的对象的原形链中就会含有this.prototype
。举个栗子说明继承原形链:
function fn(a,b,c) { console.log(this) };
fn.prototype.test1 = function(){ console.log("test1"); }
var fn1 = fn.bind(1);
var instance = new fn1();
instance.test1(); // 输出:test1,说明fn1继承了fn.prototype上面的属性
最后,由于是通过bound.prototype = new F()
,所以当使用new
的时候,this instanceof F
会返回true
。那么就会把方法内部的this
绑定成当前的实例,就达到了上面第一条说的效果
下面的都是前辈们指出来的,所以我非原创,不拿任何credit。
他的这个栗子其实已经很好地实现了需要,不过吹毛求疵一点,讨论两个问题:
第一个问题:使用context||this
是否合理?作者的目的是在不使用new
的情况下,没有传入context
时,使用自己的this
代替。这个其实有点多此一举,首先fn.apply(undefined)
也是可以的。而且当对fn
使用严格模式的时候,会出现this
指向window
的问题,应该是undefined
。
function fn() { 'use strict'; console.log(this); }
fn.bind()(); // 应该是undefined,但是栗子中的bind会返回window
第二个问题:使用F
来传递原形的属性,而不是直接通过bound.prototype = this.prototype
,我看原作者说的是为了防止污染this
,但是我没有理解怎么污染this
的。反而会造成下面的问题:
function fn(){ console.log(this) };
var fn1 = fn.bind(1);
var instance = new fn1();
console.log(instance.__proto__ === fn.prototype); // 原生的bind应该返回true,而文中bind的栗子返回的是false
建议看看他的第二篇es5-shims
的实现,还是挺有启迪性的。
同时,今天我在讨论这个问题的细节的时候,被前辈们教训了,很多东西不需要考虑得过于全面,在写代码的时候,只要满足你的需要就够了,选择实现我会用的方式,代码最少化
。然而我上面很多分析都有点过了~哈哈~共勉~~
说下后面几个圈的知识点
看看代码:
var F = function(){};
var B = function(){console.log(this instanceof F);};
new B();//false
B.prototype = new F();//将B原型指向F去,那么new出来的实例 instanceof F,也就true了
new B();//true
通过整理原型链来做判断最终的bound是new 调用出来还是直接调用。
至于这块,没咋去理解= =
大概是保证new bound出来的实例能顺着原型链一直链到被绑定函数的原型链上,保证原型链一致吧。
13 回答12.8k 阅读
7 回答1.9k 阅读
5 回答1.4k 阅读
3 回答1.1k 阅读✓ 已解决
5 回答1.1k 阅读✓ 已解决
2 回答1.2k 阅读✓ 已解决
6 回答867 阅读✓ 已解决
其主要原因里面也说了,你可能没有想一下真实调用的场景。
bind除了具有绑定this上下文的作用,其还具有类似于函数柯里化,提前绑定一些参数的作用。
如下场景:
如果我们没有你图中的红圈标注的,就会导致上面的代码报错。即使我们传入了一个已经声明好的对象obj进去,那么只会修改obj上的属性,不符合
new构造函数
实例化返回一个新对象的标准。