博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

prototype

Posted on 2012-08-31 13:42  bw_0927  阅读(191)  评论(0)    收藏  举报

http://www.mangguo.org/javascript-prototype-inheritance-basic-mechanisms/

http://developer.51cto.com/art/201108/288343.htm

http://tech.ddvip.com/2009-05/1243588153121460.html

 

http://tech.ddvip.com/2009-05/1243588303121461.html

http://www.jb51.net/article/11199.htm

http://blog.csdn.net/junkaih2008/article/details/2653142

http://blog.csdn.net/chaojie2009/article/details/6719353

 http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html

http://blog.csdn.net/chaojie2009/article/details/6719353

 

JavaScript 是基于对象的,任何元素都可以看成对象。然而,类型和对象是不同的。本文中,我们除了讨论类型和对象的一些特点之外,更重要的是研究如何写出好的并且利于 重用的类型。毕竟,JavaScript这种流行的脚本语言如果能够进行良好的封装,并形成一个庞大的类型库,对于重用是非常有意义的。
网上对于prototype的文章很多,一直没明白核心的思想。最后写了很多例子代码后才明白:prototype只能用在类型上。(类型=原型=原型对象)
以下是一些关于类型和对象的例子,大家看完例子后可能更容易理解类型和对象之间的联系:
 
 
例子代码
说明
1
Object.prototype.Property = 1;
Object.prototype.Method = function ()
{
    alert(1);
}
 
var obj = new Object();
alert(obj.Property);
obj.Method();
可以在类型上使用proptotype来为类型添加行为。这些行为只能在类型的实例上体现。

JS中允许的类型有Array, Boolean, Date, Enumerator, Error, Function, Number, Object, RegExp, String
2
var obj = new Object();
obj.prototype.Property = 1; //Error
//Error
obj.prototype.Method = function()
{
    alert(1);
}
在实例上不能使用prototype,否则发生编译错误
3
Object.Property = 1;
Object.Method = function()
{
    alert(1);
}
 
alert(Object.Property);
Object.Method();
可以为类型定义“静态”的属性和方法,直接在类型上调用即可
4
Object.Property = 1;
Object.Method = function()
{
    alert(1);
}
var obj = new Object();
alert(obj.Property); //Error
obj.Method(); //Error
实例不能调用类型的静态属性或方法,否则发生对象未定义的错误。
5
function Aclass()
{
this.Property = 1;
this.Method = function()
{
    alert(1);
}
}
var obj = new Aclass();
alert(obj.Property);
obj.Method();
这个例子演示了通常的在JavaScript中定义一个类型的方法
6
function Aclass()
{
this.Property = 1;
this.Method = function()
{
    alert(1);
}
}
Aclass.prototype.Property2 = 2;
Aclass.prototype.Method2 = function
{
    alert(2);
}
var obj = new Aclass();
alert(obj.Property2);
obj.Method2();
可以在外部使用prototype为自定义的类型添加属性和方法。
7
function Aclass()
{
this.Property = 1;
this.Method = function()
{
    alert(1);
}
}
Aclass.prototype.Property = 2;
Aclass.prototype.Method = function
{
    alert(2);
}
var obj = new Aclass();
alert(obj.Property);
obj.Method();
在外部不能通过prototype改变自定义类型的属性或方法。
该例子可以看到:调用的属性和方法仍是最初定义的结果。
8
function Aclass()
{
this.Property = 1;
this.Method = function()
{
    alert(1);
}
}
var obj = new Aclass();
obj.Property = 2;
obj.Method = function()
{
    alert(2);
}
alert(obj.Property);
obj.Method();
可以在对象上改变属性。(这个是肯定的)
也可以在对象上改变方法。(和普遍的面向对象的概念不同)
9
function Aclass()
{
this.Property = 1;
this.Method = function()
{
    alert(1);
}
}
var obj = new Aclass();
obj.Property2 = 2;
obj.Method2 = function()
{
    alert(2);
}
alert(obj.Property2);
obj.Method2();
可以在对象上增加属性或方法
10
function AClass()
{
       this.Property = 1;
       this.Method = function()
       {
              alert(1);
       }
}
 
function AClass2()
{
       this.Property2 = 2;
       this.Method2 = function()
       {
              alert(2);
       }
}
AClass2.prototype = new AClass();
 
var obj = new AClass2();
alert(obj.Property);
obj.Method();
alert(obj.Property2);
obj.Method2();
这个例子说明了一个类型如何从另一个类型继承。
11
function AClass()
{
       this.Property = 1;
       this.Method = function()
       {
              alert(1);
       }
}
 
function AClass2()
{
       this.Property2 = 2;
       this.Method2 = function()
       {
              alert(2);
       }
}
AClass2.prototype = new AClass();
AClass2.prototype.Property = 3;
AClass2.prototype.Method = function()
{
       alert(4);
}
var obj = new AClass2();
alert(obj.Property);
obj.Method();
这个例子说明了子类如何重写父类的属性或方法。
 
   以上例子中,关于通过类型实现重用方面,重要的有:
·例子1:JavaScript中允许添加行为的类型
·例子2:prototype使用的限制
·例子3:如何定义类型上的静态成员
·例子7:prototype在重定义类型的成员上的限制
·例子10:如何让一个类型继承于另一个类型
·例子11:如何在子类中重新定义父类的成员
  
可见JavaScript能够实现的面向对象的特征有:
·公有属性(public field)
·公有方法(public Method)
·私有属性(private field)
·私有方法(private field)
·方法重载(method overload)
·构造函数(constructor)
·事件(event)
·单一继承(single inherit)
·子类重写父类的属性或方法(override)
·静态属性或方法(static member)

 

 

由于语言设计上的原因,JavaScript 没有真正意义上“类”的概念。而通常使用的 new 命令实例化对象的方法,其实是对原型对象的实例化。这一语言功能的本质依赖于 JavaScript 特有的原型链(prototype chain)模式。

所以严格意义上说,JavaScript 是基于原型的面向对象语言。也就是说,每个实例对象都具有一个原型。对象从该原型中继承属性和方法。

1、构造函数

利用构造函数,可以简单地创建对象。构造函数内的 this 关键字指向实例对象本身:

function People(name){
    this.name = name;
}

使用 new 运算符和构造函数创建实例对象:

var people = new People('小明');
console.log(people.name); //小明

但如果创建了两个实例,这两个实例之间无法直接共享属性和方法:

var people1 = new People('小明');
var people2 = new People('小王');
people1.sex = 'male';
console.log(people2.sex); //undefined

也就是说对象一旦被实例化,其属性方法都独立存在,对某个属性的修改不会影响到其他实例。

2、Prototype (可实现添加,继承,重写)http://developer.51cto.com/art/201108/288343.htm

于是就有了 prototype 属性,这个属性是在生成实例对象时自动创建的。它本身又是一个对象,拥有能够在实例间共享的属性和方法。而实例本身的属性和方法,则包含在构造函数中。换句话说,构造函数内部的属性和方法,在经过实例化后都成为了本地的属性和方法,而原型(prototype)中的属性和方法在实例中只是一种引用,因此能够被多个实例共享。

还是刚才那个构造函数,现在为它增加 prototype 属性:

People.prototype.sex = 'female';
//或者写成 People.prototype = {sex: 'female'};
console.log(people1.sex); //male
console.log(people2.sex); //female

People 构造函数的 prototype 属性参数会直接影响到 people1 和 people2 两个实例。

但为什么 people1.sex 输出 male 呢?这是由于在 JavaScript 中,原型关系以递归形式存在。对象的原型也是一个对象,而原型的本身也可能具有一个原型。原型的最高层级是全局的 Object 对象。

这就是说,一旦 people1.sex 被设置为 male 后,它在原型中对应的值就无法被暴露出来。假如 people1.sex 本身没有值,才会从构造函数的 prototype 属性中读取,以此类推一级一级向上查找,直到 Object 对象。

注:使用 “null” 给对象赋值,可以销毁自定义对象,释放内存资源。

 

=====================================================

http://lovebeyond.iteye.com/blog/1175502

http://developer.51cto.com/art/200907/134913.htm

function Person(){}

var person = new Person();

Person.prototype={//重写Person原型
	name:'zhangsan',
	sayHi:function(){
		alert("重写原型")	
	}
}

//person.sayHi();这里会报错

function Person1(){}

var person1 = new Person1();

Person1.prototype.sayHi = function(){//添加
	alert("hello prototype")	
}

person1.sayHi();//这里能正常执行


由于javascript本身的原型和实例之间松散关系,在Person对象中先实例化了对象,接着重写了Person的原型,就是因为这里的重写导致了现有的原型和之前实例对象之间关系被切断,而Person1则不一样,没有对原型进行重写,而只是在Person1原型上添加的方法和属性,所有区别就在此,所以Person1.sayHi()的执行显然没问题  

 

constructor属性始终指向创建当前对象的构造函数。比如下面例子:

  1. // 等价于 var foo = new Array(1, 56, 34, 12);
  2. var arr = [1, 56, 34, 12];
  3. console.log(arr.constructor === Array); // true
  4. // 等价于 var foo = new Function();
  5. var Foo = function() { };
  6. console.log(Foo.constructor === Function); // true
  7. // 由构造函数实例化一个obj对象
  8. var obj = new Foo();
  9. console.log(obj.constructor === Foo); // true
  10. // 将上面两段代码合起来,就得到下面的结论
  11. console.log(obj.constructor.constructor === Function); // true

但是当constructor遇到prototype时,有趣的事情就发生了。

我们知道每个函数都有一个默认的属性prototype,而这个prototype的constructor默认指向这个函数。如下例所示:

  1. function Person(name) {
  2. this.name = name;
  3. };
  4. Person.prototype.getName = function() {
  5. return this.name;
  6. };
  7. var p = new Person("ZhangSan");
  8. console.log(p.constructor === Person); // true
  9. console.log(Person.prototype.constructor === Person); // true
  10. // 将上两行代码合并就得到如下结果
  11. console.log(p.constructor.prototype.constructor === Person); // true

当时当我们重新定义函数的prototype时(注意:和上例的区别,这里不是修改而是覆盖),constructor属性的行为就有点奇怪了,如下示例:

  1. function Person(name) {
  2. this.name = name;
  3. };
  4. Person.prototype = {
  5. getName: function() {
  6. return this.name;
  7. }
  8. };
  9. var p = new Person("ZhangSan");
  10. console.log(p.constructor === Person); // false
  11. console.log(Person.prototype.constructor === Person); // false
  12. console.log(p.constructor.prototype.constructor === Person); // false

为什么呢?

原来是因为覆盖Person.prototype时,等价于进行如下代码操作:

  1. Person.prototype = new Object({
  2. getName: function() {
  3. return this.name;
  4. }
  5. });

而constructor属性始终指向创建自身的构造函数,所以此时Person.prototype.constructor === Object,即是:

  1. function Person(name) {
  2. this.name = name;
  3. };
  4. Person.prototype = {
  5. getName: function() {
  6. return this.name;
  7. }
  8. };
  9. var p = new Person("ZhangSan");
  10. console.log(p.constructor === Object); // true
  11. console.log(Person.prototype.constructor === Object); // true
  12. console.log(p.constructor.prototype.constructor === Object); // true

怎么修正这种问题呢?方法也很简单,重新覆盖Person.prototype.constructor即可:

  1. function Person(name) {
  2. this.name = name;
  3. };
  4. Person.prototype = new Object({
  5. getName: function() {
  6. return this.name;
  7. }
  8. });
  9. Person.prototype.constructor = Person;
  10. var p = new Person("ZhangSan");
  11. console.log(p.constructor === Person); // true
  12. console.log(Person.prototype.constructor === Person); // true
  13. console.log(p.constructor.prototype.constructor === Person); // true

 =================================

当发生重写时,javascript 引擎首先会检索对象的所有属性,如果发现就返回,否则继续再去找创造这个对象的构造函数的prototype中的属性,如果这个属性找到就返回。

 

<script>
function ClassA()
{
this.a='a';
}
ClassA.prototype.a = 'x';
var objA=new ClassA();

 

for(var p in objA)document.write(p+"");
</script>  

打印a, 无论ClassA.prototype.a = 'x'; 在var objA=new ClassA();之前还是之后 。