function A () {};
function B () {};
B.prototype = new A();
var a = new A();
var b = new B();
log(a.constructor); // A
log(b.constructor); // A
js中实例是有一个constructor属性指向它的构造函数的。
如上面的A类的实例a,它的constructor属性就指向A。
但是当B继承了A之后,B的实例b的constructor指向的却不是B类,而是父类A。
1
haozhang OP markdown不起作用啊...谁教教我怎么搞。
|
2
haozhang OP 原来还要选择markdown...不能改成默认的么...
|
3
ceoimon 2015-05-31 16:58:30 +08:00 1
constructor 属性是在构造函数的原型对象上的。你这里将 B 的原型对象赋值成一个 A 类实例,此时 B 的原型对象上的就没有 constructor,但继承了 A 的原型链 ,于是 log(b.constructor); 输出的是原型链上 A 的原型对象上的 constructor 即 A 函数。(好像有点乱,我也是个新手,个人是这么理解的。)
|
4
haozhang OP @ceoimon 我去...做了个实验,实例上没有constructor属性...《JS高程》上讲过实例有constructor属性的啊...xd你的理解是对的。
|
5
Septembers 2015-05-31 17:31:39 +08:00 via Android
|
6
Gem 2015-05-31 17:31:53 +08:00 1
@haozhang 看这里,秘密花园 => https://bonsaiden.github.io/JavaScript-Garden/zh/ ==>[对象.原型]
|
7
haozhang OP @Septembers 我讲constructor属性...你给的两个链接连毛的constructor都没见着..
|
8
haozhang OP @Gem 《js高程》的p145讲了实例也有constructor属性...但明显错了,原型对象才有constructor属性...实例的能访问constructor属性是因为原型上有...
|
9
joeyzh 2015-05-31 17:48:02 +08:00
Object.constructor
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/constructor Object.prototype.constructor https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor 但是想知道为什么实例 b.constructor 指向构造函数 A 不是 B 呢? |
10
haozhang OP @joeyzh 看三楼的,因为原型对象是有constructor属性的,而实例没有。b.constructor是沿着原型链搜索到了A.prototype.constructor。
|
13
yangmls 2015-05-31 18:08:48 +08:00
引用一段来自 Backbone 的继承方法
` function A () {}; function B () {}; var Surrogate = function(){ this.constructor = B; }; Surrogate.prototype = A.prototype; B.prototype = new Surrogate; var a = new A(); var b = new B(); console.log(a.constructor); console.log(b.constructor); ` |
15
ibigbug 2015-05-31 18:14:10 +08:00
B.prototype.constructor = A
直接覆盖原型的话,要修正一下这个属性 |
16
joeyzh 2015-05-31 18:14:43 +08:00
可以理解为是引用实例的构造函数的一种方式?
|
17
yangmls 2015-05-31 18:16:52 +08:00
@haozhang 虽然这个属性没什么卵用,但我们还是应该尽量保持它的正确性,万一哪天你想在实例化以后修改原型链,可以用a. constructor.prototype.xxx = ... 来修改
|
21
CoooolChan 2015-05-31 18:45:03 +08:00
函数有prototype属性指向原型对象
原型对象有constructor属性,指向构造函数 实例内部有[[Protype]]指向原型对象 实例的属性访问,先看实例自己有没有,有就返回,没有就沿着原型对象找 A什么都没做,constructor指向A B的protype被重写了,此时指向的是A的实例,b.constructor先查实例,没找到,再查原型对象(A的实例),没找到,继续找A的原型对象,找到了A.constructor=构造函数A |
23
haozhang OP @CoooolChan 是[[Prototype]]...
|
24
Biwood 2015-05-31 22:19:50 +08:00
JavaScript 中的所有对象都可以看作是 Object 对象的实例,因此所有对象都继承了 Object.prototype 上的方法和属性,所以,所有对象都有 constructor 这个属性,《JavaScript 高级程序设计》这本书上的说法是没有问题的,实例也是对象,原型对象也是对象,凡是 JavaScript 中的对象都有 constructor 属性,没有任何问题。
|
25
FrankFang128 2015-05-31 22:25:13 +08:00 via Android
用 console.dir() 既知
|
26
Mutoo 2015-05-31 22:36:32 +08:00
话说原型的 constructor 这个属性有啥用?(然而并没有什么卵用。)
|
27
haozhang OP @Biwood 但是它没有指出这玩意是继承来的,而不是自带的...两个方式产生的结果完全不同,就像我一直以为这个属性是自带的,所以才会问出这个问题。
|
30
Biwood 2015-05-31 22:44:54 +08:00
我用词有误, Object 是构造函数,不是对象,所有的构造函数都有 prototype 属性,prototype 里面存放的是构造函数创建的所有实例的原型对象,所有实例可以共享原型对象的属性 (properties) 和方法 (methods) ,constructor 就是所有实例共享的属性之一。
|
31
Biwood 2015-05-31 22:45:17 +08:00
@haozhang 实例和实例的原型对象是紧密关联的,原型对象所拥有的,相对的实例也必然也有,所以不存在 constructor 属于哪一个的说法。
如果按你的补充中的思路来看,JavaScript 中只有 Object.prototype 有 constructor 属性,其他对象都只是继承而已。 |
32
Biwood 2015-05-31 22:58:26 +08:00
所谓原型就是指一个对象最初始的样子,构造函数就像一台机器(或者说一个加工厂),不断的照着原型对象的样子来生产对象,生产出来的对象都是照着 [原型对象] 的模子做的,当你把 prototype 重写了,那么 [原型对象] 的模子也变了,所以构造函数会照着新的模子来生产对象,只不过这个新的模子也是照着另外的模子被生产出来的,所谓继承,就是这么实现。
|
33
haozhang OP @Biwood 你说了很多...但是这个问题仅仅就是constructor是继承来的还是自带的而已...来个方式带来两个结果...显然《js高程》的叙述并不严谨...
|
34
Biwood 2015-05-31 23:03:12 +08:00
@haozhang 我说了很多是因为我也需要自己理清一下思路,之前我的理解并不算清晰,就着你的问题,我愿意捋一捋之前所学的知识 :)
|
36
joyee 2015-05-31 23:07:15 +08:00
因为
function B () {}; // B.prototype.constructor === B B.prototype = new A(); // B.prototype.__proto__.constructor === A 另外其实想知道每一步执行之后A和B的原型链都是什么模样可以用console啊……Chrome的不太好用,Firefox的可以看得很清楚,执行完之后点击A或者B看右边会列出所有的东西 |
38
joyee 2015-05-31 23:14:33 +08:00
@haozhang 其实我一直觉得在JavaScript的范围里说继承是件挺奇怪的事……就是搭原型链而已,说继承联想到普通的OO反而更迷惑
|
39
Biwood 2015-05-31 23:18:40 +08:00
@haozhang 继承来的也就是自带的不是么,总不能凭空出现吧,打个通俗的比喻,一个男孩继承了他父亲一样的棕色的眼镜,但这双眼睛是男孩自己的不是别人的,只是眼睛的颜色恰好跟他父亲的眼睛的颜色一样叫“棕色”。上面所说的 constructor 就是这个“棕色”一样的东西。
|
41
haozhang OP @Biwood 不是这个意思,自带就像是function A(){},然后A就有prototype这个属性了。是语言设计层面的...
|
42
joyee 2015-05-31 23:26:17 +08:00
@haozhang 其实只要把 JavaScript 的 OO 部分都看成在原型链这个“搜索路径”上做文章,然后知道 new 和创建函数会对这条搜索路径干什么事,各种引用是怎么搜索的,完全不要去联想 C++/Java 那种 OO,就一切都很自然……
|
43
liebesbrief 2015-06-01 01:24:15 +08:00
昂......路過.......表示题主头像是我做的哦............好欣慰~
|
44
haozhang OP @liebesbrief 我在lofter上看到的...直接盗用了...
|
46
andy1987 2015-06-01 16:31:37 +08:00
Class.prototype.constructor
|
47
joyee 2015-06-01 16:56:59 +08:00
@haozhang ES6 的 class 本质还是 prototype,类似于 CoffeeScript 的 class,纯粹的语法糖……而且 TC39 也是倾向于只让它停留在语法糖的层面上,现在在 es-discuss 谈论给 JavaScript 加上“真正的OO”的人基本都会被婊……
|
48
kenshin 2015-06-01 16:59:55 +08:00
JavaScript基于原型链的继承,B.prototype = new A(); 相当于 B.prototype.constructor === a.constructor === A
所以: log(a.constructor); // A log(b.constructor); // A 类似这种情况,需要手动改回B.property.constructor,即:B.prototype.constructor = B 但这种继承方式多了一步 new A(相当于做了2次new A),为了避免内存浪费,可以使用下面的方式: function A () {}; function B () {}; function F () {}; (空函数) F.prototype = A.prototype B.prototype = new F() B.prototype.constructor = B var a = new A(); var b = new B(); log(a.constructor); // A log(b.constructor); // B PS,这种方式也有缺点(B只继承了A.prototype上的属性),如这样就有错误了: function A () { this.foo = "only a"; }; function B () {}; function F () {}; F.prototype = A.prototype B.prototype = new F() B.prototype.constructor = B var a = new A(); var b = new B(); log(b.foo) //undefined 更完美的方案,可以看看 CoffeeScript / TypeScript 生成的JS代码,很清晰。 :) |