关于js的原型的一个问题

2014-01-23 22:00:48 +08:00
 Tankpt
先附上一段代码
function fTest(name){}

fTest.prototype.name = "hello";

fTest.prototype.setname = function(name){
this.name = name;
};

fTest.prototype.getname = function(){
console.log(this.name);
};

var oTest1 = new fTest();
var oTest2 = new fTest();

oTest2.__proto__ === oTest1.__proto__;//返回true


然后就是我查看了下oTest1中的属性,发现有name,一点疑问,我之前对他的理解都是fTest.prototype.name = "hello";,这句话表明在fTest.prototype中有一个变量为name,然后oTest1和oTest2全部指向他,我的理解是两个共有的一个属性,只要在一个改变了,那另一个去访问也会变化,但是我实际看了下在OTest1对象中有name,这个我在function fTest(name){}中又没进行申明,为啥有这个属性呢?

我的一点怀疑是不是我这个东西的this出了问题,有点乱指了,一点感觉不知道对不对,还望前辈们指点下问题
3266 次点击
所在节点    问与答
28 条回复
FrankFang128
2014-01-23 22:08:36 +08:00
fTest.prototype.name = "hello";
这不是 name 的声明吗?
FrankFang128
2014-01-23 22:09:49 +08:00
不太明白你的疑问在哪里。
你明明声明了为什么觉得自己没声明?
FrankFang128
2014-01-23 22:15:37 +08:00
console.log(oTest1)

> fTest {name: "hello", setname: function, getname: function}
> > __proto__: fTest
> > > constructor: function fTest(name){}
> > > getname: function (){
> > > name: "hello"
> > > setname: function (name){
> > > __proto__: Object

oTest1 和 oTest2 的 name 属性都是从 __proto__ 里得到的,而 __proto__ 指向 fTest.prototype,而 fTest.prototype.name = "hello";.
所以 oTest1 和 oTest2 的 name 属性来自同一个地方,但是 name 不是它们自身的属性
oTest1.hasOwnProperty('name')
false
Tankpt
2014-01-23 22:45:47 +08:00
@FrankFang128 嗯,我看了下你第三条回复,完全同意,现在我就是比如调用了下setname方法,用oTest1.setname("hi");我之前的理解是这个操作会改变fTest.prototype中name属性为hi ,然后调用oTest2.getname()返回的也是hi,但是实际测试的时候返回的还是hello,这样感觉就跟name
然后用oTest1.hasOwnProperty('name')返回的是true,我想问的是是不是在setname中的this出了问题了
FrankFang128
2014-01-23 22:49:20 +08:00
在 context 是 oTest1 的情况下,你只能操作 oTest1 的属性,无法通过 oTest1 改变它的 __proto__ 的属性,也就是说,你添加了一个实例属性,覆盖了『类』属性。
FrankFang128
2014-01-23 22:50:22 +08:00
但是对于没用覆盖过 name 的 oTest2 来说, name 还是 __proto__ 的 name,而不是 its own property。
FrankFang128
2014-01-23 22:54:36 +08:00
应该不能称为「类属性」。 暂时还没想到合适的词。
在你执行 oTest1.setname 时,在 oTest1 上添加了一个 name,同时 oTest1 的 __proto__ 里也有一个 name。
根据 JS 查找成员的规则,它如果在 oTest1 上找到了 name, 就不会再去看 oTest1 的 __proto__ 了。
而 oTest2,因为自身没有 name 属性,所以 JS 引擎会去看它的 __proto__
FrankFang128
2014-01-23 22:56:12 +08:00
已经很久没看面向对象的东西,不过不建议你从面向对象的角度去理解,而是从原型链的角度来理解。
Tankpt
2014-01-23 22:57:32 +08:00
@FrankFang128 嗯嗯。有些明白了。那就是说这个setname方法中的this.name指向的不是fTest.prototype中的name么?
Tankpt
2014-01-23 23:00:32 +08:00
@FrankFang128 嗯,那个js寻找一个属性从实例开始找这点我是明白的,我感觉根据测试的结果来看,这个时候在oTest1实例中就已经有了一个name的属性,然后覆盖了fTest.prototype中的name,然后么就是一下子没想明白这个实例中的name是在哪里加进去的。有点困惑了
FrankFang128
2014-01-23 23:01:30 +08:00
this.name 指向哪里,是不确定的。
唯一确定的是 JS 引擎的查找规则。
在你 setname 之前,如果你想读取 oTest1 的 name,那么 JS 引擎首先看 oTest1 自身有么有 name 属性(没有),然后再看 __proto__ 里有没有(有),如果还找不到,它会继续看 __proto__ 的 __proto__。
但是你 setname 之后, oTest1 就有了「自己的」name 属性。你再让 JS 引擎找 oTest1.name 的时候,它依然用刚才的逻辑找 name。
现在应该懂了吧。
FrankFang128
2014-01-23 23:04:56 +08:00
这是因为 oTest1.setname 中的 this ,指的是 oTest1。所以 oTest1.setname 会在 oTest1(this)上添加 name 属性。



如果你运行 oTest1.setname.call(fTest.prototype,'another name'),那么期间的 this 就是 fTest.prototype 了。
这里涉及的概念是 context。 你可以试着运行下。
FrankFang128
2014-01-23 23:07:15 +08:00
this 和 prototype 就是 JS 最难理解的两个地方啊。
FrankFang128
2014-01-23 23:08:37 +08:00
读 name 的过程和写 name 的过程是不一样的。11楼说的是读的过程。
FrankFang128
2014-01-23 23:10:29 +08:00
而写的过程呢,就简单很多了。
this.name = 'hi'
JS 引擎会看 this 有没有 name 这个属性。没有就新建一个 name ,并赋值为1(没有查看__proto__ 的过程);有就直接赋值。
Tankpt
2014-01-23 23:11:33 +08:00
@FrankFang128 嗯嗯。现在prototype自己琢磨了下,然后差不多能画一些图了,前天看到了this的问题,感觉好玄乎,嗯。你刚那么一说,算是明白了,set中的this指向的是oTest1,那就没错了,难得放假有时间整理下东西,谢谢啦。非常感谢你的耐心指导~~
FrankFang128
2014-01-23 23:15:08 +08:00
至于 this 指向哪里,也是不确定的,要看具体环境。
如果你直接运行一个方法,比如
function foo(){
console.log(this) // window
console.log(this === window) // true
}

如果你运行一个 object 的方法,不如

var obj = {
foo : function(){
console.log(this===obj)
}
}
obj.foo() // true

但是你可以使用 call 来指定 this,比如

var obj = {
foo : function(){
console.log(this===myObj)
}
}

var myObj = {}
obj.foo.call(myObj) // true

so...不知道你懂了没。
FrankFang128
2014-01-23 23:17:16 +08:00
你理懂还有段距离吧。 建议你看看李战的《悟透 JS》http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html
是他的博客,后来编成书了。第一部分很不错,后面的就差一点。
FrankFang128
2014-01-23 23:24:04 +08:00
我理解到现在的程度,用了大半年的时间,还是觉得没理解透啊。嘿嘿
Tankpt
2014-01-23 23:26:07 +08:00
@FrankFang128 嗯嗯。所以在试着整理一下自己理解的东西,准备写个文章,然后看看。嗯嗯。这个文章我有看过点,当时太长了,然后就放在了书签里==!

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

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

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

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

© 2021 V2EX