Web_Design 板


LINE

前面文章的内容、推文、回文有诸多错误。但在解释之前,原 PO 有必要先了解 何为 __proto__、函式的 .prototype 属性又是什麽。 JavaScript 的任何物件,包括函式(函式也是物件),有一个特殊的属性 "__proto__",用来达成类似「继承」的功能。它和其它使用 class 的语言 不同,这里的继承是「继承另一个物件的属性」而非「延伸一个介面」 当对一个物件进行 property lookup 时,若是在当前的物件中没有找到该属性, 就会往 __proto__ 找。例如︰ obj = { a: 1 }; obj2 = { b: 2, __proto__: obj }; console.log(obj2.a); // 1 // 这个属性其实是长在 obj 身上,但因为 __proto__ // 的关系从 obj2 也找得到。 寻找的过程大约是这样 def lookupProperty(obj, name): if hasOwnProperty(obj, name): return getOwnProperty(obj, name) return lookupProperty(obj.__proto__, name) 由此可以看到,若是很多物件用 __proto__ 连在一起,寻找属性时就会一个个地 往下找。这功能称为 prototype 链,或原型链。 同时,为了区分一个属性是长在自己身上呢?还是从原型链里找出来(继承)的呢? 有一个 hasOwnProperty 的函式可以用。以上方的程式码为例︰ obj2.hasOwnProperty('a'); // false obj2.hasOwnProperty('b'); // true 再来是函式的 prototype。 当以 function 关键字来定义一个函式时,该函式会有一个 prototype 属性 (函式也是物件!)。 function Test() {} Test.hasOwnProperty('prototype'); // true 这个属性平时一点用都没有,只有在使用 new 关键字的时候有用。 使用 new 关键字的时候,会建立一个新物件,并且把该物件的 __proto__ 属性设为 该函式的 prototype。然後再以这个物件为 this context,执行该函式︰ // new Test(); newObj = { __proto__: Test.prototype }; Test.call(newObj) 你可以看到,所有 new 出来的物件,都拥有相同的 __proto__,也就是 Test.prototype。如果你在 Test.prototype 上新增属性,所有 new 出 来的物件都能延着原型链找到该属性。用这样的功能就可以为这些物件 建立共用的 method。也因为这个原因,这些函式会被叫作 class 或 constructor。 原 PO 的问题来了,两个 "class",使其中一个继承另一个,又是怎麽回事? util.inherits 又做了什麽?其实就是这样︰ function Test() {} Test.prototype.a = 1; function Test2() {} Test2.prototype.b = 2; Test2.prototype.__proto__ = Test.prototype; t2 = new Test2; console.log(t2.a); // 1 观察一下原型链的状况︰ * t2.__proto__ 指向 Test2.prototype,原因在「函式的 prototype」那段有解释。 * Test2.prototype.__proto__ 指向 Test.prototype,是我们指定的(亮色那行)。 从 t2 延着原型链寻找 a 属性的结果,就是︰ 1. t2 没有 a 属性,看 t2.__proto__ (Test2.prototype) 2. Test2.prototype 没有 a 属性,看 Test2.prototype.__proto__ (Test.prototype) 3. Test.prototype 有 a 属性,返回值 这样一来,就达成了「继承另一个 class 的 method」的功能。 最後,「console.log 不会显示继承的属性」是正确的。但「console.log 不会显示 继承的属性,所以没有继承」是错误的。如果你是用浏览器的 console,它不只会显 示继承的 __proto__,还可以把它点开看里面有什麽东西。以原 PO 的例子来看︰ console.log(ChildObject.prototype) // console.log 不会显示继承的属性,而 // hit 是长在 BaseObject.prototype 上的 console.log(ChildObject.prototype.__proto__) // 这大概是原 PO 要的结果 下面是一些和原文无关的东西。 > inherits 会设定 enumerable:false 不会!inherits 就是在做上面亮白色那行。原始码在这︰ https://github.com/nodejs/node/blob/1403d28e7ded280e7582daa6e999164588d2234e/lib/util.js#L966-L980 (缩︰https://goo.gl/iSMTDh> class extends只是语法糖,做的事情基本上是一样的 不一样!class 和 extends 关键字是语言层的继承,constructor 也不等效於 function︰ class Test {} Test(); // error Test.call(); // error 建立物件的时机甚至相反︰ class A {} class B extends A { constructor() { console.log(this); // reference error super(); // 物件是由 A 建立的 console.log(this); // super 後才能使用 this } } new B; vs. function A() {} function B() { console.log(this); // 物件在 B 执行前已建立 A.call(this); } B.prototype.__proto__ = A.prototype; new B; > enumerable 当一个属性被称为 enumerable(可列举),一般是在说 Object.getOwnPropertyDescriptor() 所回传的 enumerable === true。 而其它的列举方法如 in, for...in, Object.keys, JSON, ... 的处理各有不同。 详细可以参考这个表︰ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties#Detection_Table (缩︰https://goo.gl/X7LtwT> Object.create 会把继承来的属性设为 no enumerable 不会。Object.create 用来建立一个新物件,并指定 __proto__。 Object.create(null) 还可以建立一个完全空的物件(无继承)。 > Object.create 就是 js 的继承。 > 只是和 new 不相容 我不太清楚这指的是什麽,不过想同时使用︰ function Test() {} Test.prototype.a = 1; (new Test).a; // 1 Object.create(Test.prototype).a; // 1 > 书上写说javascript没有继承 所以node.js才用 > prototype的概念弄出继承 如果书上这麽写,建议换一本书。关於继承的功能上面提过了,而 prototype 也不是 Node.js 发明的。Node.js 只是一个平台,和浏览器一样。 -- ▆▄   --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 118.166.130.128
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/Web_Design/M.1504710463.A.725.html
1F:推 Hevak: 推详细 09/07 01:39
2F:推 ian90911: 推 09/07 09:40
3F:推 tino1991: 推! 09/07 10:32
4F:推 kisha024: 很详细 09/07 21:42
5F:推 hijkxyzuw: 呃,我的意思是 c = Object.create(p) 後, 09/07 23:46
6F:→ hijkxyzuw: 原本 p 的 enumerable 属性,在 c 变成 no enumerable 09/07 23:47
7F:→ hijkxyzuw: 和 function.prototype 与 instance 的行为不同。 09/07 23:48
8F:→ hijkxyzuw: 虽然在 p 里的 descriptor 还是 enumerable , 09/07 23:50
9F:→ hijkxyzuw: 但用 for..in 在 c 里会找不到。 09/07 23:51
10F:推 hijkxyzuw: 找得到欸,我之前弄错了。 09/07 23:55
11F:→ hijkxyzuw: 和 new 不相容是那篇文章讲的,我回在自己那篇好了 09/08 00:08
12F:推 Kenqr: 推 09/09 17:01







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:iOS站内搜寻

TOP