js 的 new 和原型链一个问题请教,感谢!!!!

2018-01-26 14:11:35 +08:00
 xuecat
function Super() {
    this.val = 1;
    this.arr = [1];
}
function Sub() {...}

Sub.prototype = new Super();
var sub1 = new Sub();
var sub2 = new Sub();

sub1.val = 2;//不会影响 sub2
sub1.arr.push(2);//会影响 sub2

上面的代码有点我无法理解,想请教下!!!

先讲下我的理解:

new Super后,导致Sub.prototype通过call得到了valarr
new Sub后的实质变化也只是sub1__proto__指向了Sub.prototype

也就是说,sub1.val,sub1.arr这都是访问Sub.prototype上的。
这特么访问就都是一个链上的东西了。
为何sub1.arr能影响,而sub1.val却不影响呢?
不能因为一个是值类型,一个是引用类型就有区别吧!!!!

是 new 的时候对值类型复制了吗?可是我翻了下没这描述。。。。。求解答

4140 次点击
所在节点    JavaScript
22 条回复
zzuieliyaoli
2018-01-26 14:23:47 +08:00
"new Sub 后的实质变化也只是 sub1 的 __proto__ 指向了 Sub.prototype" 不对,
应该为 “ sub1、sub2 的__proto__指向了 Sup.prototype ”

sub1.__proto__.arr === sub2.__proto__.arr // true
mskf
2018-01-26 14:24:18 +08:00
先不管继承,根据你的描述,你的问题应该是这个

function Super() {
this.val = 1;
this.arr = [1];
}

var a = new Super(),b= new Super()

a.arr.push(2)
b.arr//1,2 为什么这里受影响了

---
首先你要知道
function Super(){
this.publicProperty = 1 //公有属性,所有实例公有的
this.publicProperty = 1 //公有属性,所有实例公有的
}

Super.staticProperty =
zzuieliyaoli
2018-01-26 14:26:39 +08:00
#1 我的回复是错,请忽略
Egg
2018-01-26 14:27:10 +08:00
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Inheritance_and_the_prototype_chain<br/>
在这个最下面的地方讲了一下 prototype 说到 new Super() 实际用的是 call 这个方法 也就是说 <br/>
Super 下 this.val 给 call 到了 sub1 sub2 两个重新定义的变量当中<br/>
Super 下 this.arr 因为是数组 所以 sub1 sub2 中的 arr 指向依旧是 Super 中的 arr<br/>
mskf
2018-01-26 14:27:15 +08:00
@mskf 妈蛋还没写完,敲 TAB 敲到回车了,继续
---
首先你要知道
function Super(){
this.publicProperty = 1 //公有属性,所有实例公有的
this.publicPropertyArr = [] //公有属性,所有实例公有的
}

Super.staticProperty = 2//静态属性,不能用 this 调用

Super.prototype.prototypeProperty = 3 // 原型属性,实例化时赋予对象

---

你的问题在于 publicProperty 这个属性为什么看上去不是公用的
因为它是值对象。。。
xuecat
2018-01-26 14:32:21 +08:00
@zzuieliyaoli @mskf <br/>
我先修正俩句
“ sub1、sub2 的__proto__指向了 Sup.prototype ””
"也就是说,sub1.val,sub1.arr,sub2.val,sub2.arr 这都是访问 Sub.prototype 上的。"

我能理解 sub1.arr.push(2)会影响 sub2,不能理解 sub1.val 不影响 sub2

我认为它们访问的 arr 和 val 来源就是 Sup.prototype 上的,所以都是一样的。

我如此认为的依据:

new 的定义:
```js
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
```

也就是说 new Sub 后,实质也就只是让__proto__指向了 prototype,和 call 换上下文。
bramblex
2018-01-26 14:33:14 +08:00
sub => { __prop__: {val: 1, arr: [1] } }
sub2 => { __prop__:{val:1, arr:[1] }}
sub.val => 1
sub.__prop__ === sub2.__prop__ => true

sub.val = 2
sub => { val: 1, __prop__: {val:1, arr:[1] }}
sub2 => { __prop__:{val:1, arr:[1] }}


sub.arr.push(2)
sub => { val: 1, __prop__: {val:1, arr:[1,2] }}
sub2 => { __prop__:{val:1, arr:[1,2] }}

你需要知道的是, 这个 val / arr 到底在什么位置
mskf
2018-01-26 14:33:28 +08:00
@xuecat
嗯。。。这样说把,如果 sub1.val 影响了 sub2.val ,是不是可以说明 sub1 和 sub2 的指针指向了同一个地址
gogo81745
2018-01-26 14:33:56 +08:00
sub1.var = 2
这里赋值了,sub1 多了一个叫 var 的私有属性,并不是修改了原型链上的 var
因此原型链上的 var 没有改变,而下次访问 sub1.var 时直接读私有属性不读原型链上的了

而对数组的并不是赋值,修改的就是原型链上的数组。
如果你改成 sub1.arr = [1, 2],那就不会影响 sub2
Egg
2018-01-26 14:39:53 +08:00
@gogo81745 如果一定要用到 push 这个方法的话有什么解决方案吗
mskf
2018-01-26 14:40:53 +08:00
@Egg Super.prototype.arr = [1]
xuecat
2018-01-26 14:42:01 +08:00
@gogo81745 果然是这样的,确实是多了一个属性。万谢!!!

他们也确实都访问到原型链上了
Egg
2018-01-26 14:47:19 +08:00
@mskf 谢谢
gogo81745
2018-01-26 14:50:03 +08:00
@Egg
你是指使用 push,并且不影响原型链上的数组吗?
sub1.arr = sub1.arr.slice()
sub1.arr.push(2)
我想到的最简单的方法就这种,不知道有没有什么奇技淫巧
Egg
2018-01-26 14:54:19 +08:00
@gogo81745 这个也可以 都好神奇 又学到一点新东西
不过感觉还是在刚开始定义的时候 方法和数组用 prototype 来定义继承会好一点
KuroNekoFan
2018-01-26 15:21:55 +08:00
关键是理解原型链,实例和基本类型,引用类型
bucky
2018-01-26 15:28:52 +08:00
还是拥抱 es6 吧
timwei
2018-01-26 16:10:22 +08:00
function Super() {
this.val = 1;
this.arr = [1];
}

function Sub(arr) {
Super.call(this, arr)
}

Sub.prototype = new Super();
var sub1 = new Sub();
var sub2 = new Sub();

sub1.arr.push(2); // [1,2]
sub2.arr // [1]
tjsdtc
2018-01-26 16:54:09 +08:00
这是属性设置的屏蔽问题,补充一点:
现假设设置 foo.a = 1,而 a 不存在 foo 对象中而存在其原型链中时,有三种情况:
1. a 属性是普通属性,此时会在 foo 对象上生成一个 a (就是楼主的情况)。
2. a 属性是只读属性( writable: false ),此时设置会直接无效,foo 对象中不会添加,严格模式下报错。
3. a 属性是一个 setter,则直接调用 setter,foo 对象中不会添加。
isbase
2018-01-26 17:43:46 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/426144

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX