(转)Javascript类- 几种属性的定义方式及区别

几种属性:

先看代码,这段代码中出现了类定义中可能使用到5种属性或者变量

<coolcode lang="java script"linenum="off"> function car(param1,param2){
//构造变量
var varProperty = 'This is a var Perperty';
//构造属性
this.constructProperty = 'This is a construct Property'
}

//原形属性
car.prototype.prototypeProperty = 'This is a prototype property';

//静态属性
car.staticProperty = 'This is a static property';
</coolcode>

构造变量 使用VAR声明和定义,它的作用域仅限于构造方法内部,包括在构造器内部定义的所有方法(构造方法)。直接通过变量名访问:varProperty。有些文章也把叫做私有属性,从作用域上看,它是私有的,但它不是属性,类的原型是无法访问它的。

构造参数 就是上述代码中的 param1,param2,它与构造变量有相同的作用域和方法方式

<coolcode lang="java script"linenum="off"> function car(param1,param2){
//构造变量
var varProperty = 'This is a var Perperty';

echo(varProperty);
echo(param1);

this.someMethod = function(){
echo(varProperty);
echo(param1);
};
}</coolcode>

构造属性 构造属性在类的构造器中通过this.定义,它是公开的(public),可以通过类的实例(this.)直接访问和修改它

原型属性 在类的原型中定义,它也是公开,具有和构造属性相同的作用域,它不仅可以通过实例访问,也可以随时通过原型来访问((ClassName.propertype.)

它和构造属性是有区别的:原型属性可以通过原型直接访问,它存储于类的原型中的,各个实例是通过指针共享访问它具体下面单独分析

<coolcode lang="java script"linenum="off"> function car(){

//构造属性
this.constructProperty = 'This is a construct Property'

this.someMethod = function(){
echo(this.constructProperty); //这样可以
echo(this.ptototypeProperty); //这一可以
};
}

//原形属性
car.prototype.prototypeProperty = 'This is a prototype property';

echo(car.constructProperty); //这样是不能访问构造属性的
echo(car.ptototypeProperty); //这样是不能访问原型属性的

//必须通过实例来访问
aCar = new car();
echo(aCar.constructProperty); //这样可以
echo(aCar.ptototypeProperty); //这样可以

echo(car.prototypeProperty) //原型属性可以通过原型直接访问
</coolcode>

静态属性 直接通过ClassName.的方式定义,它具有和常规OOP语言中的静态属性类似的特性,但注意,它只能通过ClassName访问,不能通过实例访问,在类的中也不能通过this访问

<coolcode lang="java script"linenum="off"> function car(param1,param2){
echo(this.staticProperty);//这样是不能访问到静态属性的。
echo(car.staticProperty);//这样可以访问到静态属性的。
}

//静态属性
car.staticProperty = 'This is a static property';

aCar = new car();
echo(aCar.staticPerperty); //这样是不能访问到静态属性的。
echo(car.staticProperty); //这样可以访问到静态属性的。</coolcode>

构造属性和原型属性的区别:

上面已经说了构造属性和原型属性的定义方式,和访问方法,它们的主要区别在于:原型属性可以通过原型直接访问,它存储于类的原型中的,各个实例是通过指针共享访问它。也就是说对于每个构造属性,每个实例都有一个自己存储副本;而对于每个原形属性,每个实例实际上是共享同一个存储副本,实例中存储的仅仅是一个指向原型属性的指针。

看代码吧:

<coolcode lang="java script"linenum="off"> function car(){
//构造属性
this.constructProperty = new Array ('tom','jerry');
}

//原形属性
car.prototype.prototypeProperty = new Array ('tom','jerry');

aCar = new car();
bCar = new car();
cCar = new car();

//修改aCar的构造属性
aCar.constructProperty.push('Emeric');
echo(aCar.constructProperty);
echo(bCar.constructProperty);
echo(bCar.constructProperty);

//修改aCar的原型属性
aCar.prototypeProperty.push('Emeric');
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</coolcode>

输出结果:

//改变aCar的构造属性,仅仅影响到的aCar单一实例
tom,jerry,Emeric
tom,jerry
tom,jerry
//改变aCar的原型属性,影响到了所有实例
tom,jerry,Emeric
tom,jerry,Emeric
tom,jerry,Emeric
这里我们为什么在示例代码中使用数组,而没有使用其它简单变量呢?来看另一段代码:这段代码的和上面的唯一区别是使用了字符串作为属性,

<coolcode lang="java script"linenum="off"> function car(){
//构造属性
this.constructProperty = 'This is a construct Property'
}

//原形属性
car.prototype.prototypeProperty = 'This is a prototype property';

aCar = new car();
bCar = new car();
cCar = new car();

aCar.constructProperty = 'New string';
echo(aCar.constructProperty);
echo(bCar.constructProperty);
echo(bCar.constructProperty);

aCar.prototypeProperty = 'New string';
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</coolcode>

输出结果如下,对aCar的两种属性的修改都没有影响到其它实例,正如上面所说,javascript在实例中使用指针来指向原型属性,当使用 aCar.prototypeProperty = 'New string' 进行直接赋值时,javascript进行的操作是修改实例的指针(aCar.prototypeProperty ),使其指向新的存储副本 'New string' ,这一过程往往会掩盖了原型属性的共享特性。

 

New string
This is a construct Property
This is a construct Property
New string
This is a prototype property
This is a prototype property


再看一段补充代码,这是接着上面的代码运行的,我们通过原型来直接修改了原型属性:

<coolcode lang="java script"linenum="off"> car.prototype.prototypeProperty = 'Another New String!';
echo(aCar.prototypeProperty);
echo(bCar.prototypeProperty);
echo(bCar.prototypeProperty);
</coolcode>

输出结果如下,会发现,这一修改仅仅影响到了bCar和cCar。

原因其实就是因为上面 aCar.prototypeProperty = 'New string' 的,它改变了 aCar.prototypeProperty 的指向,而不再指向 原型,因而他也就脱离了原型的控制。

New string
Another New String!
Another New String!

由于原型属性的共享特性和可能发生的实例指针脱离原型的现象,我们应该仅仅对需要共享的属性使用原型定义,一般的属性应该尽量使用构造来定义;在修改原型属性时应该尽可能通过原型(car.prototype.)来访问修改,而不要通过实例(aCar.)来修改;。以此来避免可能发生的属性混乱问题。

 

 

引用通告地址: 点击获取引用地址
评论: 13 | 引用: 0 | 阅读: 11065
更多




karina [ 2021-02-04 11:18 网址 | 回复 | 编辑 删除 ]
marianne [ 2020-12-27 09:55 网址 | 回复 | 编辑 删除 ]
david [ 2020-12-02 14:31 网址 | 回复 | 编辑 删除 ]
ronald [ 2020-11-29 06:51 网址 | 回复 | 编辑 删除 ]
marianne [ 2020-07-06 20:28 网址 | 回复 | 编辑 删除 ]
karina [ 2020-07-06 12:07 网址 | 回复 | 编辑 删除 ]
frank [ 2020-04-18 03:52 网址 | 回复 | 编辑 删除 ]
laurie [ 2020-04-11 02:02 网址 | 回复 | 编辑 删除 ]
ernest [ 2020-03-22 08:56 网址 | 回复 | 编辑 删除 ]
david [ 2020-02-16 21:49 网址 | 回复 | 编辑 删除 ]
发表评论
昵 称: 密 码:
网 址: 邮 箱:
验证码: 验证码图片 选 项:
头 像:
内 容:
  • 粗体
  • 斜体
  • 下划线
  • 插入图像
  • 超链接
  • 电子邮件
  • 插入引用