`
prcjack
  • 浏览: 3624 次
  • 性别: Icon_minigender_1
  • 来自: 广州
最近访客 更多访客>>
社区版块
存档分类
最新评论

危险的prototype, 你实现了继承吗?

阅读更多
含有私有变量的类如果被另一个类用prototype模拟"继承",将产生私有变量共享威胁:

function f1(){
  var p = {};
 this.getP = function(){
   return p;
 };
}
function f2(){}
f2.prototype = new f1();

var f1_ins_1 = new f1();
var f1_ins_2 = new f1();
alert(f1_ins_1.getP() == f1_ins_2.getP());// ->false

var f2_ins_1 = new f2();
var f2_ins_2 = new f2();
alert(f2_ins_1.getP() == f2_ins_2.getP());//-> true

//f2_ins_1 与 f2_ins_2共享 f1私有变量p == 我一个下午的bug测试 *_*


建议:含私有变量的类加 final 标识,防止被prototype。
分享到:
评论
14 楼 afcn0 2007-12-21  
根本不是特权方法,而是函数定义在scope当中了,当然会继承scope chain就是这么简单而已
13 楼 prcjack 2007-12-21  
看来是我的代码习惯出了问题,我经常在构造函数内定义方法和私有变量。类似:

function f(){
  var p;
  this.getP = function(){return p;}
}

其目的是让类拥有私有变量,而getP为可以访问私有变量的“特权方法”。
12 楼 ajaxgo 2007-12-21  
<p>
prcjack 写道
你的意思是把所有方法都定义在 构造函数体 外? 类似这样: function f(){ var p; ... } f.prototype.m1 = f... f.prototype.m2 = f... 这是个不错的习惯,jindw 的建议类似!
</p>
<p>什么叫做和jindw的建议类似~~~~是懂prototype的,都这么做~~~~~楼主的做法是只知其一不知其二。无意中,偷学到prototype=new xxxx的方法,就用它,却不知道为什么要这样用,这样用有什么好处,需要注意那些方面~~~~然后在不停的debug和hack后,告诉我们,原来~~啊,要小心prototype……</p>
11 楼 ajaxgo 2007-12-21  
<p><font>太拗了~~~~在并不清楚prototype,并不清楚真正怎样模拟oo的情况下,说prototype太危险会带坏小朋友的~~~~<br/>
给你看看真正的模拟继承,还有没有你那个威胁~</font></p>
<div class='code_title'>js 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-c'>
    <li class='alt'><span><span class='keyword'>var</span><span> Grandfather=</span><span class='keyword'>function</span><span>() {      </span></span></li>
    <li class=''><span>    </span><span class='keyword'>this</span><span>.member=xxxxxx      </span></li>
    <li class='alt'><span>}      </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span>_extend(Grandfather.prototype,{      </span></li>
    <li class=''><span>     methods:</span><span class='keyword'>function</span><span>() {      </span></li>
    <li class='alt'><span>         </span><span class='comment'>//todo    </span><span>  </span></li>
    <li class=''><span>     }      </span></li>
    <li class='alt'><span>});      </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span/><span class='keyword'>var</span><span> Father=</span><span class='keyword'>function</span><span>() {      </span></li>
    <li class=''><span>    </span><span class='keyword'>this</span><span>.superclass.constructor.apply(</span><span class='keyword'>this</span><span>,arguments);      </span></li>
    <li class='alt'><span>}      </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span>Father.prototype=</span><span class='keyword'>new</span><span> Grandfather();      </span></li>
    <li class=''><span>_extend(Father.prototype,{....});      </span></li>
    <li class='alt'><span>Father.prototype.constructor=Father;      </span></li>
    <li class=''><span>Father.prototype.superclass={      </span></li>
    <li class='alt'><span>    constructor:Grandfather   </span></li>
    <li class=''><span>};      </span></li>
    <li class='alt'><span>     </span></li>
    <li class=''><span>     </span></li>
    <li class='alt'><span/><span class='keyword'>var</span><span> Child=</span><span class='keyword'>function</span><span>() {      </span></li>
    <li class=''><span>   </span><span class='keyword'>this</span><span>.superclass.constructor.apply(</span><span class='keyword'>this</span><span>,arguments);      </span></li>
    <li class='alt'><span>}     </span></li>
    <li class=''><span>Child.prototype=</span><span class='keyword'>new</span><span> Father();    </span></li>
    <li class='alt'><span>_extend(Child.prototype,{....});      </span></li>
    <li class=''><span>Child.prototype.constructor=Child;      </span></li>
    <li class='alt'><span>Child.prototype.superclass={      </span></li>
    <li class=''><span>    constructor:Father      </span></li>
    <li class='alt'><span>};   </span></li>
</ol>
</div>
10 楼 prcjack 2007-12-20  
你的意思是把所有方法都定义在 构造函数体 外? 类似这样:
function f(){
  var p;
  ...
}
f.prototype.m1 = f...
f.prototype.m2 = f...

这是个不错的习惯,jindw 的建议类似!
9 楼 micrexp 2007-12-20  
function f1(){  
  var p = {};  
this.getP = function(){  
   return p;  
};  
}  
function f2(){}  
f2.prototype = new f1();  //这里的f1我用a表示
 
var f1_ins_1 = new f1();   //这里的f1我用b表示
var f1_ins_2 = new f1();   //这里的f1我用c表示
//b!=c,这没有话说,相信大家都没有什么意见
alert(f1_ins_1.getP() == f1_ins_2.getP());// ->false  
//请看清楚a,f2.prototype = new f1(); //这是a
var f2_ins_1 = new f2();   //f2_ins_1.getP()==a.getP();
var f2_ins_2 = new f2();   //f2_ins_2.getP()==a.getP();
//所以返回值是TRUE
alert(f2_ins_1.getP() == f2_ins_2.getP());//-> true

//PS:不知道你们看明白没有,呵呵。。 prototype,小心使用
8 楼 afcn0 2007-12-20  
俺不懂继承,不知道是什吗玩意
7 楼 ajaxgo 2007-12-20  
多重继承本来就是危险的,js本身也不是class-based的,要多重继承干吗?人家大名鼎鼎的java都抛弃了多继承。js还要执着干吗??另外,你说的也根本不是多重继承。只是条继承链而已。js以object-based的特性,实现的是prototype链的“继承”关系。另外再次声明,在构造函数内,只要你不去定义类方法,完全不存在这种威胁(因为根本不会存在闭包)。
6 楼 prcjack 2007-12-20  
afcn0 写道
威胁个什吗玩艺,根本就是对象是这么实现的,一个对象当然只有一个函数指针一套scope chain,去学习js语法后再来这里讨论
呵呵,js的语法俺可能还真没学通!不过兄弟可否推荐个继承的函数,当出现多重继承时(也许我们还不知道已经是多重继承了),又不会存在共享私有变量(在父类的父类中)的问题。
5 楼 afcn0 2007-12-20  
威胁个什吗玩艺,根本就是对象是这么实现的,一个对象当然只有一个函数指针一套scope chain,去学习js语法后再来这里讨论
4 楼 prcjack 2007-12-20  
在子类f2,f3里加f1.apply 可以解决,但 如果f1 又继承自另一个父类f0, 那么 f2,f3的实例 还是存在 共享f0 私有变量的 威胁


function f0(){
  var p0 = {};  
this.getP0 = function(){  
   return p0;  
};  
}
f1.prototype = new f0();
alert((f3_ins_1.getP0() == f3_ins_2.getP0()));//-> true
3 楼 jindw 2007-12-20  
prototype的共享的问题确实容易把人搞晕。
我的建议是:
prototype上只能放置无状态元素,比如,没有私有闭包的函数,原始类型。

对于构造器中申明的成员函数。普通对象,数组对象等有状态元素作为成员时更是要特别小心。
2 楼 afcn0 2007-12-20  
什么玩艺呀,f2的prototype对象是在构造之前被指定为了new f1当然你再怎么new f2他的f1 prototype也是原来那个呀,就是这么简单不是什么bug
1 楼 ajaxgo 2007-12-20  
<p>兄弟,这不是继承的错,是因为f2的prototype引用的是f1的一个实例,所以f2的实例在调用getP时,获得是同一个闭包内的P。</p>
<p>这种构造函数的定义明显就是错误的。构造函数只是用来初始化类成员,也从来不需要定义局部变量,也从来都不定义类方法。且,即使按照你的这样的定义,难道不知道子类需要在构造函数中,调用父类的构造函数吗?比如</p>
<div class='code_title'>js 代码</div>
<div class='dp-highlighter'>
<div class='bar'/>
<ol class='dp-c'>
    <li class='alt'><span><span class='keyword'>function</span><span> f2() {   </span></span></li>
    <li class=''><span>   f1.apply(</span><span class='keyword'>this</span><span>,arguemnts);   </span></li>
    <li class='alt'><span>}   </span></li>
</ol>
</div>
<p>这样,就消除了你说的变量冲突问题。也对于oo来说,也是合理的做法。</p>

相关推荐

    JavaScript使用prototype属性实现继承操作示例

    主要介绍了JavaScript使用prototype属性实现继承操作,结合实例形式详细分析了JavaScript使用prototype属性实现继承的相关原理、实现方法与操作注意事项,需要的朋友可以参考下

    JavaScript实现继承的几种方式

    JavaScript的原型(prototype)机制是实现继承的基础。每个函数都有一个prototype属性,这个属性指向一个对象,这个对象的属性和方法可以被实例共享。通过将一个对象设置为另一个对象的原型,我们可以实现继承。 ``...

    JavaScript不使用prototype和new实现继承机制

    本文所描述的方法是一种不使用prototype和new关键字来实现继承的替代方案。 首先,我们看到代码中定义了几个方法来帮助实现继承机制。这些方法包括clone、each、extend和create,它们都被添加到了JavaScript的...

    Javascript中 关于prototype属性实现继承的原理图

    那么,具体到prototype属性如何实现继承,我们来详细解释一下几个关键概念和步骤: 1. prototype属性: 在JavaScript中,函数对象都有一个特殊的属性叫做prototype,这个属性指向了一个原型对象。当创建一个函数时...

    javascript中类和继承(代码示例+prototype.js)

    函数的`prototype`属性则用于实现继承。例如: ```javascript function Person(name) { this.name = name; } Person.prototype.sayName = function() { console.log(this.name); } ``` 这里的`Person`函数就是...

    构造函数定义对象+prototype继承的实现.html

    构造函数定义对象+prototype继承的实现,含CSS样式

    js遍历属性 以及 js prototype 和继承

    JavaScript使用原型链实现继承,这意味着一个对象可以从另一个对象继承属性和方法。主要有两种继承方式: 1. 构造函数继承(经典继承):通过`new`关键字创建一个父类(超类)的新实例,然后将其作为子类的`...

    javascript的prototype继承

    JavaScript的原型继承是其面向对象编程的一大特性,它基于原型链机制实现,允许一个对象可以从另一个对象继承属性和方法。这种继承方式不同于类继承,而是通过将子类的原型对象设置为父类的一个实例来实现。 在...

    prototype学习笔记

    在JavaScript中,我们还可以通过`Object.create()`方法来创建一个新对象,使其`__proto__`指向指定的对象,从而实现继承。这为不使用构造函数实现继承提供了一种方式。 标签中的"源码"可能意味着笔记深入探讨了`...

    js继承实现示例代码

    **使用`Object.prototype.extend`实现继承** 示例代码中定义了一个名为`extend`的方法,该方法被添加到`Object.prototype`上。这种方法允许任何对象都可以调用`extend`来继承另一个对象的属性和方法。 ```...

    JavaScript学习之三 — JavaScript实现继承的7种方式

    本篇文章将深入探讨JavaScript实现继承的七种常见方式,帮助你更好地理解和运用这一概念。 1. 原型链继承(Prototype Chain Inheritance) 原型链是JavaScript实现继承的基础。每个函数都有一个`prototype`属性,这...

    java script 继承的实现

    在 JavaScript 中,继承主要通过原型链(prototype chain)、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承等方法实现。以下是对这些继承方式的详细解释: 1. **原型链继承**:这是 JavaScript ...

    Prototype实现的鼠标拖拽demo

    在这个"Prototype实现的鼠标拖拽demo"中,我们将探讨如何使用Prototype库来创建一个具有拖放功能的交互式用户界面。 首先,Prototype的`Draggable`类是实现拖放行为的基础。`Draggable`允许任何DOM元素变得可拖动,...

    JavaScript使用prototype原型实现的封装继承多态示例

    下面将详细介绍使用prototype实现封装、继承和多态的概念以及相关的代码示例。 首先,封装是面向对象编程中的一个核心概念,它涉及将数据(属性)和操作数据的方法捆绑在一起,形成一个独立的单元,即对象。在...

    【JavaScript的9种继承实现方式归纳】js实现继承的几种方式.pdf

    JavaScript 的灵活性使得其实现继承的方式非常多样化。本文将介绍 JavaScript 中的 9 种继承实现方式,帮助读者更好地理解 JavaScript 的继承机制。 1. 原型链继承 原型链继承是 JavaScript 中实现继承的默认方式。...

    JS继承.txtJS继承.txt

    原型链继承是通过将一个对象设置为另一个对象的原型,从而实现继承的一种方法。这种方式简单直观,但存在一些缺点,比如不能向父类传递初始化参数,且所有实例共享同一个属性。 **示例代码解析**: ```javascript ...

    学习javascript面向对象 javascript实现继承的方式

    在JavaScript中,实现继承有多种方式,每种方式都有其特点、优势和不足。本文将详细介绍六种实现JavaScript继承的方法。 1. 原型链继承 原型链继承是通过改变子类型的原型对象来实现继承的。子类型构造函数的原型被...

    js继承的这6种方式!(上)

    原型链是实现继承最原始的模式,即通过prototype属性实现继承。 //父级-构造函数 function Father() { this.fatherProp = true } //父级-原型属性 Father.prototype.getFatherValue = function() { return this....

Global site tag (gtag.js) - Google Analytics