You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
functionA(){}A.prototype.constructor// AA.constructor// FunctionfunctionB(){}B.constructor// FunctionB.prototype.constructor// BB.prototype// Function 这里是函数B.prototype=newA()// A {} 这里是对象B.prototype.constructor// AB.constructor// Functionvarc=newB()// B {}c.__proto__// A {} 这里就有问题了,c明明是由B构造的,却直接跳过了B找到了Ac.constructor===B.prototype.constructor// A 这里也有问题,不符合规范了B.prototype.constructor=B// 强行赋值,改变指向
functionFoo(who){this.me=who}Foo.prototype.identify=function(){return"I am "+this.me}functionBar(who){Foo.call(this,who)}Bar.prototype=Object.create(Foo.prototype)Bar.prototype.speak=function(){alert("Hello, "+this.identify()+".")}varb1=newBar("b1")varb2=newBar("b2")b1.speak()b2.speak()
面向委托:
varFoo={init: function(who){this.me=who},identify: function(){return"I am "+this.me}}varBar=Object.create(Foo)Bar.speak=function(){alert("Hello, "+this.identify()+".")}varb1=Object.create(Bar)b1.init("b1")varb2=Object.create(Bar)b2.init("b2")b1.speak()b2.speak()
前言
最近一段时间没怎么登github,公司内部走代理访问github打开特别慢,排版布局又很乱,据悉是公司内部防火墙的缘故。
晚上回来也迟,就没有打开电脑去看搜藏的博客。不过不要紧,毕竟也买了不少技术书,那就静下心来看看书吧。
PS:《你不知道的javascript》上中两卷买回来起码半年了,昨天才看完上卷,太懒了!!!得逼自己一把,不然怎么快速进步!!!
看书之前以为我都会,看完之后才发现我还不够!
尤其看完这两章,我对原型链以及js继承又有了全新的认识,这里特地把自己以前没有学习到的新知识记录下来,做个总结。
建议大家去看该系列书籍,github上有英文版:《你不知道的javascript》
get到的新点
1.属性设置和屏蔽
这里主要讲了当对象(例如myObj)与它的原型对象(例如obj)上都存在同名属性(例如foo)时,myObj.foo会屏蔽掉它原型对象上的同名
foo
属性(这里指obj.foo)。即当进行get操作时得到的是myObj.foo,这点大家都清楚。但是!如果
myObj
中没有foo
属性,而它的原型对象obj
上有foo
属性,那么当进行myObj.foo=
赋值时,情况可能并不是我们想当然的那样,只在myObj
中新增一个foo
属性!这里有个专业术语:屏蔽!
这里涉及到三种情况:
[[Prototype]]
链上层存在名为foo
的普通数据访问属性并且没有被标记为只读(writable: false),那就会直接在myObj
中添加一个名为foo
的新属性,它是屏蔽属性。(PS:原型链上有同名属性,但是可以修改的情况下)示例代码:
[[Prototype]]
链上层存在foo
,但是它被标记为只读(writable: false),那么无法修改已有属性或者在myObj
上创建屏蔽属性。如果运行在严格模式下,代码会抛出错误。否则,这条赋值语句会被忽略。总之,不会发生屏蔽。示例代码:
[[Prototype]]
链上层存在foo
并且它是一个setter,那就一定会调用这个setter。foo
不会被添加到myObj
,也不会重新定义这个setter。代码示例:
如果希望在第二、三种情况下也能对
myObj
设置foo
属性,那么请使用Object.defineProperty()
,避免使用=
隐式屏蔽
摘抄自书上代码:
上述代码关键点在
myObject.a++
这一步!myObject.a++
相当于myObject.a = myObject.a + 1
!!!myObject
的原型对象anotherObject
上的a
属性不是只读也没有固定死setter
,所以这里相当于对myObject
增加了一个a
属性!!!2.constructor属性
实例本身并没有
constructor
属性,constructor
属性存在于它的原型对象上!!!示例代码:
之前学习原型链时知道了上述代码的关系,但是,其实这里我不是很懂。直到看了书我才知道,上述代码中
f
对象其实本身并没有constructor属性,它的原型对象Foo.prototype
上才有,f.constructor
本质上是去原型链上找到constructor
属性即Foo.prototype.constructor
!!!这就是为什么当我们使用
=
操作符去进行原型继承时,需要对constructor
重新赋值。代码示例:
按照规范来说,
B.prototype.constructor
应该指向B自身,但是上述代码如果不手动改变指向,则会造成constructor
属性指向错误!3.面向委托的设计思想
个人理解,面向委托的设计模式需要避免使用prototype以及constructor属性,主要通过this关键字来把控,配合
Object.create()
来实现。典型的原型风格 与 面向委托两种不同设计模式实现对比:
类:
面向委托:
面向委托的写法看起来更简洁也更容易理解。而且,b1.constructor === Object; Foo.constructor === Object; Bar.constructor === Object!避免了原型继承模式下的constructor指向混乱的问题。
总结
面向委托的思想是重点,以前从来都没接触过。但是需要不断实践才能真正深入了解。
接下来时间里继续看《你不知道的javascript》
The text was updated successfully, but these errors were encountered: