javascript中的prototype属性

本文详细解释了JavaScript中prototype的概念及应用,包括如何利用prototype属性为构造函数添加共享方法和属性,以及如何通过原型链实现继承。

在js中经常看到prototype,看了一遍,理解了后又忘了,- - …可能是理解的不够深入,现在写个博客总结下:

每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数被用作构造函数调用(使用new操作符调用)的时候,新创建的对象会从原型对象上继承属性和方法。

你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。
看下面例子:

function Test(){}
alert(Test.prototype); // 输出 "Object"

下面说明一下构造函数:

function Person(name)  
{  
   this.name=name;  
   this.showMe=function()  
        {  
           alert(this.name);  
        }  
};  
var one=new Person("liming");  
one.showMe();//liming 

这个构造函数与一般函数调用的区别在于new操作符,关于构造函数调用时是否有new还有不同的区别,可以看我另一篇文章:构造函数是否有new的区别

按照javascript的说法,function定义的这个Person就是一个Object(对象),而且还是一个很特殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别。这个区别就是function定义的对象有一个prototype属性,使用new生成的对象就没有这个prototype属性。
prototype属性又指向了一个prototype对象,注意prototype属性与prototype对象是两个不同的东西,要注意区别。在prototype对象中又有一个constructor属性,这个constructor属性同样指向一个constructor对象,而这个constructor对象恰恰就是这个function函数本身。
这里写图片描述

看个代码:

function Person(name)  
{  
   this.name=name;  
   this.showMe=function()  
        {  
           alert(this.name);  
        }  
};  
var one=new Person('js'); 
alert(Person.prototype)//Object  
alert(one.prototype)//undefined  
alert(typeof Person.prototype);//object  
alert(Person.prototype.constructor);//function Person(name) {...};  

上面的代码证明了one这个对象没有prototype属性。
所有对象本身都可以有prototype属性,它本身也是对象。如此循环下去就形成一个prototype链,这个链当遇到链中的prototype为null时即中止。(Object的默认prototype是null)。
如上代码var one=new Person(‘js’),这个one对象的prototyp是null, 所以 one的prototype链只包含一个对象Object.prototype。这也说明了为什么function定义的对象有一个prototype属性,使用new生成的对象就没有这个prototype属性,因为已经实例化了。

//首先创建一个基本的Person类型  
function Person(name)  
{  
   this.name=name;  
   this.showMe=function()  
        {  
           alert(this.name);  
        }  
};  

//可以通过prototype属性来为该类型新增属性或方法  
Person.prototype.from=function()  
{  
  alert('I come from prototype.');  
}  

 //实例化Person对象
var one=new Person('js');  
one.showMe();  //js
one.from();//I come from prototype.

看看继承:
分析如下的代码结构,可以看出类型MyClass2本身并没有定义testNumber,但通过prototype属性将MyClass1的所有定义都继承下来了,而且还继承了Object中的toString方法。因此该prototype的链包含3个。


    var MyClass1 =function(formalParameter) {  

        this.testNumber =formalParameter;  

    };  

    var MyClass2 = function(formalParameter){  

        this.testString  = formalParameter;  

    }; 

     MyClass2.prototype = new MyClass1(9);  

    var myObject2 = new MyClass2("Hello World!");  

    alert(myObject2.testString);//Hello World!  

    alert(myObject2.testNumber); //9  

    alert(myObject2.toString); //function toString() {}  

在js中,每个对象都可以继承自另外一个其它的对象,我们可以称之为引用原型。当我们访问一个属性时,如果能通过对象本身直接找到,则返回,否则它会向引用原型中追溯,直到根部prototype(即object)。如下所示:

Object.prototype.inObj = 1;  

var A = function() {  

    this.inA = 2;  

}  

A.prototype.inAProto = 3;  

var B = function() {  

    this.inB = 4;  

}  

B.prototype = new A();  

B.prototype.inBProto = 5;  

var x = new B();  

alert(x.inObj + “,” + x.inA + “,” + x.inAProto + “,” + x.inB + “,” +x.inBProto); //1, 2, 3, 4, 5  

对于上述的代码,创建一个对象x,它所生成的prototype链结构如下:
这里写图片描述

我们知道,将ClassA的一个实例赋值给ClassB,则 ClassB就继承了ClassA的所有属性。

 var ClassA = function() {  

        this.a = "a";  

    };  

    var ClassB = function() {  

    this.b= "b";  

    };  



    ClassB.prototype = new ClassA();  

    var objB = new ClassB();  

    alert(objB.a); // a  

    alert(objB.b); // b

从上述的变量输出结果,可以看出本身ClassB是没有属性a的,但在创建的对象中调用objB.a时却输出了a,说明在执行ClassB.prototype= new ClassA();后,ClassB继承了ClassA的所有属性。

js的原型继承是引用原型,而不是复制原型。当修改原型时会导致所有的实例变化。

 var ClassA = function() {  

     this.a = "a";  

     };  



     var ClassB = function() {  

         this.b = "b";  

     };  

     ClassB.prototype = new ClassA();  

     var objB = new ClassB();  

     alert(objB.a); // a  

     ClassB.prototype.a ="changed";  

     alert(objB.a); //changed  

每个子类对象都执行同一个原型的引用,所以子类对象中的原型成员实际是同一个

    var ClassA = function() {

        this.a = "a";

        this.Method = function() {

            alert("ClassA");

        }

    };

    var ClassB = function() {

        this.b = "b";

    };

    ClassB.prototype = new ClassA();

    var objB1 = new ClassB();

    var objB2 = new ClassB();

    alert(objB1.a == objB2.a); //true

    alert(objB1.b == objB2.b); //true

    alert(objB1.Method ==objB2.Method);//true

子类对象的写操作只访问子类对象的成员,相互之间不产生影响。写一定是写子类,读则要看是否子类中有,若有则读子类,若无则读原型

  var ClassA = function() {  

     this.a = "a";  

    };  

    var ClassB = function() {  

         this.b = "b";  

    };  

    ClassB.prototype = new ClassA();  

    var objB1 = new ClassB();  

    var objB2 = new ClassB();  

    objB1.a = "change";  

    alert(objB1.a);  // change  

    alert(objB2.a);  // a  

由上述代码分析,其中由于进行了objB1.a进行了重新改变,所以其值在接下来进行了改变,但它不会影响到objB2对象。但若是原型发生了变化,则如2所示,它下面的所有实例均会发生变化。

构造子类时,原型的构造函数不会被执行

var ClassA = function() {  

        alert("ClassA");  

        this.a = "a";  

    };  

    var ClassB = function() {  

        alert("ClassB");  

        this.b = "b";  

    };  

    ClassB.prototype = new ClassA();// ClassA  

    var objB1 = new ClassB();  // ClassB  

    var objB2 = new ClassB();  // ClassB  

由此可以看出,在构造子类时并没有象Java中那样需要调用父类的构造函数。

在子类对象中访问原型的成员对象,会影响到其它对象

 var ClassA = function() {  

        this.a = [];  

    };  

    var ClassB = function() {  

        this.b = "b";  

    };  

    ClassB.prototype = new ClassA();  

    var objB1 = new ClassB();  

    var objB2 = new ClassB();  

    objB1.a.push(1,2,3);  

    alert(objB2.a); // 1,2,3  

由此可以看出,在子类对象中访问原型的成员对象后,由于采用的是引用原型方式,其实它和ClassB.a.push实现的是同样的功能。所以其它的子类也会跟着变化。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值