论坛首页 编程语言技术论坛

javascript中基于原型法直接实现继承中的一个陷阱和解决

浏览 12421 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-06-15  
这里所指的原型法继承意指Lich_Ray在无类语言的OOP(JavaScript描述) 中所用的方式。
简单起见,使用无默认值的方式
引用

.....
可以把单继承作为一个 Object 类的能力保留下来,如果不强求默认值的话:
//把那些垃圾的库抛在脑后,让它们见识见识什么叫优雅。  
Object.prototype.extend = function (aClass) {   
    this.prototype = new aClass   
}   
....



但是,这个继承方式有一个很微妙的问题
function Base(){ 
    this.x = 100
    this.y = 10 
    this.area = function(){
        return this.x * this.y
    }
}

function Child(){
    this.x = 10
    this.area = function(){
        return this.__proto__.area() + 100000
    }
}

Child.extend(Base)

则如下调用
js> c = new Child()
[object Object]
js> c.area()
101000.0

得到的不是期望中的100100.0
实际上,通过__proto__的引用得到的是prototype对象,调用其上的area方法时this指的是这个prototype对象,而访问不到Child对象所定义的x.
javascript中在属性/方法的读取时才按照prototype链进行搜索,此时,会正确进行this的转换. javascript对象在写入时,适用的是最内层作用域,它是没有办法也不应该去修改prototype中的同名属性的(这个是由prototype机制的自身限制,不这么做,整个机制就立马塌陷)
因此,要正确执行继承过来但又被覆写过的方法的,必须要做一个手工处理,借用javascript在方法/属性搜索时的自动this转换。而不能直接在__proto__上去找
我见过的解决办法:

function ChildB(){    
    this.x = 10;  
    this.oldArea=this.area; 
    this.area = function(){
        return this.oldArea() + 100000    
        }
}
ChildB.extend(Base)

这样就符合直观了:
js> b = new ChildB()
[object Object]
js> b.area()
100100.0

但是,这个做法本身并不是很舒服.我相信一些开源库中应当有好一些的解决办法.
   发表时间:2007-06-15  
没错啊,因为我的期望就是101000!因为 this 只有一个,传递两层调用,this 就找不着北了,确实需要手工重绑定;不过没人会对此抱歉,OOP 就是这么回事,Java 中还有 super 呢!当然了,也可以考虑再添加一个强制使用本级 this 属性的 Object 类方法。
如果不过,换作我,会这么干:
function Child() {
    this.x = 10
    this.area = function () {
        return this.__proto__.area.apply(this) + 100000
    }
}

事情就是这么简单。自己试试看吧。
PS: 看完别忘了给我这个回帖评个 5 stars 
0 请登录后投票
   发表时间:2007-06-16  
没错啊,因为我的期望就是101000!因为 this 只有一个,传递两层调用,this 就找不着北了,确实需要手工重绑定;不过没人会对此抱歉,OOP 就是这么回事,Java 中还有 super 呢!

和java还是不一样.java中继承链上的属性只有一份(js中每层一个),方法每个定义都会有一个. super只是用来免去硬绑定父类名的(在js中就是想绑定还有点难度).python中super还起到了在mro链中搜索的功用,较完善的处理了多继承的情况.
引用

当然了,也可以考虑再添加一个强制使用本级 this 属性的 Object 类方法。
如果不过,换作我,会这么干:
引用

function Child() {
    this.x = 10
    this.area = function () {
        return this.__proto__.area.apply(this) + 100000
    }
}

事情就是这么简单。自己试试看吧。

hehe. 这个做法就是我之前说的"需要把肠子都拉出来"的做法.看起来可是很不顺眼阿
从直观上来说,不应当由使用者来搞定这些应当由语言机制提供的事情. 就跟python中作用域的读写不对称问题一样,虽然知道是维持整个体系正常的必要手段,而且也存在用可写变量绕过限制的方式,但毕竟还是比较不爽的.

引用

当然了,也可以考虑再添加一个强制使用本级 this 属性的 Object 类方法。

即便有这个方法,还是有点累赘,而且实际上也是双分派了.不如象有些javascript库一样显式使用双分派.
0 请登录后投票
   发表时间:2007-06-16  
Lich_Ray 写道

function Child() {
    this.x = 10
    this.area = function () {
        return this.__proto__.area.apply(this) + 100000
    }
}


function是javascript的一等公民,他的this会随着指向的对象而改变,这正是他强大的地方。
0 请登录后投票
   发表时间:2007-06-16  
dogstar 写道
function是javascript的一等公民,他的this会随着指向的对象而改变,这正是他强大的地方。

因此在用prototype+function模拟class的行为时,会有一点点不便。缺少一种将function明确绑定到类/对象,从而固化为该类/对象的方法的方式。
很期待javascript2中统一function/method所采用的机制.

0 请登录后投票
   发表时间:2007-06-16  
还是收起你的期待吧。所谓“统一function/method”真的只是 prototype 的冰山一角,或者是冰山一脚;我宁可少用几个关键字,多想想,因为可以这样用,又可以那样用,无拘无束;也不愿不通过脑子思考就知道怎么用。关键字,说白了就是个习惯问题,我就是心理变态,看不得有人把他的意志凌驾于我的心情之上。所以事实上,我写的无类语言的OOP(JavaScript描述)中所描述的绑定在 Object.prototype 上的那些东西,类似的我还可以弄出一大堆,但我自己编程的时候从来不用,JavaScript 本质是简单的,几个特殊属性调一调什么事情搞不定啊;别人头脑中的策略从来就是给菜鸟用的。一门语言,一套思想学好了,脑中的体系自然全面,不需要别人教我:“你现在可以放心地复写方法了!用 JavaScript 2 的继承不存在上述问题!”——没有问题才是最大的问题。成天被别人的想法罩着,还以为自己又学到新东西了呢。
0 请登录后投票
   发表时间:2007-06-16  
hehe.只要你适应了一个语言的哲学,确实可以很自由。
但是,代码是写给别人看的,兄弟们在这里掐,其实也是show给过往的XDJM们看的。关键是要让别人能够简单的没有问题的看明白。
就像我曾经有一段时间觉得算法是一件很崇高的工作,尤其是精巧高效的算法。但是现在,如果看到乙方项目组有兄弟写出那么高妙的东西,我就恨不得能把他胖揍一顿。我只要求他们以简单、直观、愚蠢的方式来实现要实现的东西。那样,才不至于人一走茶就凉.
只不过在自己的业余爱好里面,有时候还是会为了一些巧妙的结构和用法去绞尽脑汁。但是,我肯定会化很多字把巧妙之处记下来给自己以后看以节省时间。记忆力衰退了,没办法。
0 请登录后投票
   发表时间:2007-06-18  
其实大家没有太大的争论点,只是锁关注的方向不同。正如ruby可能不适合大规模的团队开发,语法太过灵活,同样的功能一人一个写法,确实头疼。所以如果要探讨的话,请明确同一目标:只谈语言本身,看我们是否能够得出相似的结论。
0 请登录后投票
   发表时间:2007-06-18  
Lich_Ray 写道
还是收起你的期待吧。所谓“统一function/method”真的只是 prototype 的冰山一角,或者是冰山一脚;我宁可少用几个关键字,多想想,因为可以这样用,又可以那样用,无拘无束;也不愿不通过脑子思考就知道怎么用。关键字,说白了就是个习惯问题,我就是心理变态,看不得有人把他的意志凌驾于我的心情之上。所以事实上,我写的无类语言的OOP(JavaScript描述)中所描述的绑定在 Object.prototype 上的那些东西,类似的我还可以弄出一大堆,但我自己编程的时候从来不用,JavaScript 本质是简单的,几个特殊属性调一调什么事情搞不定啊;别人头脑中的策略从来就是给菜鸟用的。一门语言,一套思想学好了,脑中的体系自然全面,不需要别人教我:“你现在可以放心地复写方法了!用 JavaScript 2 的继承不存在上述问题!”——没有问题才是最大的问题。成天被别人的想法罩着,还以为自己又学到新东西了呢。

绝对 200%赞同 JS之所以能够被ECMA选中,而不是其它语言,是有它独特的魅力所在 --这点上那帮欧洲专家应该比我们清楚吧?
说一个题外话,现在js局限在browser,未免有点浪费。可看看两个使用ECMA262引擎的应用
http://www.whitebeam.org/overview/jsoverview.rhtm
http://www.imagenow.com/products/extensions/iscript.shtml
sony也有,不过是js.net的
http://www.sonymediasoftware.com/download/step2.asp?DID=635
0 请登录后投票
   发表时间:2007-06-18  
charon 写道

但是,代码是写给别人看的,兄弟们在这里掐,其实也是show给过往的XDJM们看的。关键是要让别人能够简单的没有问题的看明白。

的确是,这可能也是FP还没能“工业化生产”上流行的原因之一。
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics