1
FrankFang128 2014-01-23 22:08:36 +08:00
fTest.prototype.name = "hello";
这不是 name 的声明吗? |
2
FrankFang128 2014-01-23 22:09:49 +08:00
不太明白你的疑问在哪里。
你明明声明了为什么觉得自己没声明? |
3
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 |
4
Tankpt OP @FrankFang128 嗯,我看了下你第三条回复,完全同意,现在我就是比如调用了下setname方法,用oTest1.setname("hi");我之前的理解是这个操作会改变fTest.prototype中name属性为hi ,然后调用oTest2.getname()返回的也是hi,但是实际测试的时候返回的还是hello,这样感觉就跟name
然后用oTest1.hasOwnProperty('name')返回的是true,我想问的是是不是在setname中的this出了问题了 |
5
FrankFang128 2014-01-23 22:49:20 +08:00
在 context 是 oTest1 的情况下,你只能操作 oTest1 的属性,无法通过 oTest1 改变它的 __proto__ 的属性,也就是说,你添加了一个实例属性,覆盖了『类』属性。
|
6
FrankFang128 2014-01-23 22:50:22 +08:00
但是对于没用覆盖过 name 的 oTest2 来说, name 还是 __proto__ 的 name,而不是 its own property。
|
7
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__ |
8
FrankFang128 2014-01-23 22:56:12 +08:00
已经很久没看面向对象的东西,不过不建议你从面向对象的角度去理解,而是从原型链的角度来理解。
|
9
Tankpt OP @FrankFang128 嗯嗯。有些明白了。那就是说这个setname方法中的this.name指向的不是fTest.prototype中的name么?
|
10
Tankpt OP @FrankFang128 嗯,那个js寻找一个属性从实例开始找这点我是明白的,我感觉根据测试的结果来看,这个时候在oTest1实例中就已经有了一个name的属性,然后覆盖了fTest.prototype中的name,然后么就是一下子没想明白这个实例中的name是在哪里加进去的。有点困惑了
|
11
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。 现在应该懂了吧。 |
12
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。 你可以试着运行下。 |
13
FrankFang128 2014-01-23 23:07:15 +08:00
this 和 prototype 就是 JS 最难理解的两个地方啊。
|
14
FrankFang128 2014-01-23 23:08:37 +08:00
读 name 的过程和写 name 的过程是不一样的。11楼说的是读的过程。
|
15
FrankFang128 2014-01-23 23:10:29 +08:00
而写的过程呢,就简单很多了。
this.name = 'hi' JS 引擎会看 this 有没有 name 这个属性。没有就新建一个 name ,并赋值为1(没有查看__proto__ 的过程);有就直接赋值。 |
16
Tankpt OP @FrankFang128 嗯嗯。现在prototype自己琢磨了下,然后差不多能画一些图了,前天看到了this的问题,感觉好玄乎,嗯。你刚那么一说,算是明白了,set中的this指向的是oTest1,那就没错了,难得放假有时间整理下东西,谢谢啦。非常感谢你的耐心指导~~
|
17
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...不知道你懂了没。 |
18
FrankFang128 2014-01-23 23:17:16 +08:00
你理懂还有段距离吧。 建议你看看李战的《悟透 JS》http://www.cnblogs.com/leadzen/archive/2008/02/25/1073404.html
是他的博客,后来编成书了。第一部分很不错,后面的就差一点。 |
19
FrankFang128 2014-01-23 23:24:04 +08:00
我理解到现在的程度,用了大半年的时间,还是觉得没理解透啊。嘿嘿
|
20
Tankpt OP @FrankFang128 嗯嗯。所以在试着整理一下自己理解的东西,准备写个文章,然后看看。嗯嗯。这个文章我有看过点,当时太长了,然后就放在了书签里==!
|
21
otakustay 2014-01-24 02:34:38 +08:00
js找属性的逻辑很简单:
1. 自己有没有这属性,有的返回 2. 原型有没有这属性,有的返回 3. 原型的原型有没有这属性,有的返回 4. 如果原型的原型的...的原型不存在,返回个undefined js写属性的逻辑更简单:直接往上面写,和原型没关系 然后你的代码: 1. oTest1和oTest2共享一个原型,这个无误 2. 在没有调用setName前,找oTest1的name找到的是原型上的,oTest2的name也是原型上的,他们一样 3. oTest1.setName('hello')后,oTest1的name找的是自己的,这是上面说的步骤的第1步。而oTest2找name是原型上的,是上面的第2步。因此它们返回的东西不一样,且你能看到oTest1有name了 至于你说的oTest1的name变了oTest2会变,这个显然是错的,根据上面找属性的步骤来看,oTest1.setName('hello')改的是oTest1上的东西(在原型的前面),导致原型上的那个name在oTest1读取时被“隐藏”起来了,但仅仅是隐藏,其值是没有被改动的。 |
22
otakustay 2014-01-24 02:40:56 +08:00 2
至于this更简单,就是4种调用方法来决定this是啥
我想说js其实没有任何难的,无论是this还是原型链还是作用域链,统统简单的要死,根本就是一帮半调子开发者自己玩不出来就到处说这难那难,把人吓得看一眼就觉得复杂没敢认真去理解 给你看一下我讲课和技术分享时用的一些PPT:https://www.dropbox.com/sh/alem0za5y1y53j4/DpqaYZJeIn 其中的Brief Javascript.pptx就是js的入门课程,虽然没有对应的讲述会稍微有些难理解,不过你可以看一下,关于原型、作用域、this在这里面都有讲到,我认为这个PPT上的东西都能理解的话,js就算入门了 想继续深入的可以看所谓闭包.pptx,和闭包、作用域链有关的概念这里面应该全讲清楚了,再往下可以看Inside the browser.pptx和异步编程与浏览器执行模型.pptx,这是浏览器底下的知识了 |
23
sd4399340 2014-01-24 10:15:08 +08:00
|
24
Tankpt OP |
25
otakustay 2014-01-24 11:44:27 +08:00
@sd4399340 我自己能打开,搞不懂dropbox,给一个skydrive的吧不过可能版本有些老,错误倒是没有:https://skydrive.live.com/redir?resid=556CE34496EA9887%21105
|
26
FrankFang128 2014-01-24 12:43:07 +08:00
|
27
Tankpt OP @FrankFang128 恩恩。那个图么。就是感觉这么画出来直观点。我怕自己解释不清,哈哈。我刚又看了一遍你们的回复,明白多了。灰常感谢
|
28
Tankpt OP @FrankFang128 不晓得论坛里怎么私信,今天对那个constructor对象有点疑问了,主要是在实现继承的过程中,发现contructor指向了父类的构造函数,这个从面向对象的理解上,我觉得没问题,就是在实现上有点疑惑,不晓得在哪里改动了,或者说这个constructor属性是在什么情况下会修改,就比如下面的这个段代码
function SuperType(){ this.name ="person"; } SuperType.prototype.getname = function(){ console.log(this.name); }; function Subtype(){ this.name = "man"; } Subtype.prototype = new SuperType(); 在Subtype.prototype 中的constructor指向了SuperType,我的理解这个不是应该指向subtype么 |