视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
JavaScript原型对象、构造函数和实例对象功能与用法详解
2020-11-27 22:10:35 责编:小采
文档

本文实例讲述了JavaScript原型对象、构造函数和实例对象功能与用法。分享给大家供大家参考,具体如下:

大家都知道,javascript中其实并没有类的概念。但是,用构造函数跟原型对象却可以模拟类的实现。在这里,就先很不严谨的使用类这个词,以方便说明。

下面整理了一些关于javascript的构造函数、原型对象以及实例对象的笔记,有错误的地方,望指正。

先用一张图简单的概括下这几者之间的关系,再细化:

构造函数和实例对象

构造函数是类的外在表现,构造函数的名字通常用作类名。

其实构造函数也就是一个函数,只不过它于普通的函数又有点不同:

  • 没有显示的创建对象;
  • 直接将属性和方法赋给this
  • 没有return语句;
  • 构造函数是用来构造新对象的。之前的笔记中有提到过,可以是用new关键词来调用构造函数,以创建特定类型的新对象。如,创建一个Object类型的对象实例:

    var o=new Object();
    
    

    为了区别构造函数和普通函数,通常规定构造函数的命名首字母大写,而普通函数的命名首字母小写。当然,这不是必须的,却是一个很好的习惯。

    通过用构造函数创建并初始化的属性是实例属性。所谓的实例属性就是指,通过该构造函数创建的每个对象,都将拥有一份实例属性的单独拷贝。这些属性都是通过实例来访问的,值根据每个实例所定义的为准,若实例中没有定义,则为构造函数初始化时的默认值。来看一个例子:

    function Person(name,age){
     this.name=name;
     this.age=age;
     this.friends=["Tom","Boo"];
    }
    var p1=new Person("Lily",20);
    var p2=new Person("Sam",30);
    alert(p1.name); //Lily
    alert(p2.name); //Sam
    p1.friends.push("Susan");
    alert(p1.friends); //Tom,Boo,Susan
    alert(p2.friends); //Tom,Boo
    
    

    上面的例子定义了一个Person构造函数,并初始化了name、age和friends三个属性。接着创建了两个实例对象,分别为p1和p2。观察这个例子,每个属性都是为各自所拥有的,并不会相互影响。这就是因为每个实例对象都拥有一份属性的副本。

    每个实例对象都有一个属性指向它的构造函数,这属性就是constructor:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    var p1=new Person("Lily",20);
    var p2=new Person("Sam",30);
    alert(p1.constructor==Person); //true
    alert(p2.constructor==Person); //true
    
    

    构造函数有一个prototype属性,指向原型对象。

    原型对象和实例对象

    在javascript中,每个对象都有一个与之相关联的对象,那就是它的原型对象。类的所有实例对象都从它的原型对象上继承属性。

    原型对象是类的唯一标识:当且仅当两个对象继承自同一个原型对象时,它们才是属于同一个类的实例。

    前面有提到,构造函数拥有一个prototype属性,指向原型。换句话来说,一个对象的原型就是它的构造函数的prototype属性的值。当一个函数被定义的时候,它会自动创建和初始化prototype值,它是一个对象,这时这个对象只有一个属性,那就是constructor,它指回和原型相关联的那个构造函数。看个例子:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    alert(Person.prototype); //[object Object]
    alert(Person.prototype.constructor==Person); //true
    
    

    也可以通过原型来创建属性和方法。通过原型创建的属性和方法是被所有实例所共享的。即,在一个实例中修改了该属性或方法的值,那么所有其他实例的属性或方法值都会受到影响:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    Person.prototype.friends=["Tom","Sam"];
    var p1=new Person("Lily",24);
    var p2=new Person("Susan",20);
    alert(p1.friends); //Tom,Sam
    alert(p2.friends); //Tom,Sam
    p1.friends.push("Bill");
    alert(p1.friends); //Tom,Sam,Bill
    alert(p2.friends); //Tom,Sam,Bill
    
    

    由上面的例子可以看出,用原型定义的属性是被所有实例共享的。为p1添加了一个朋友,导致p2也添加了这个朋友。

    其实,很多情况下,这种现象并不是我们想看到的。那么什么时候应该用构造函数初始化属性和方法,哪些时候又该由原型对象来定义呢?

    通常建议在构造函数内定义一般成员,即它的值在每个实例中都将不同,尤其是对象或数组形式的值;而在原型对象中则定义一些所有实例所共享的属性,即在所有实例中,它的值可以是相同的属性。

    当用构造函数创建一个实例时,实例的内部也包含了一个指针,指向构造函数的原型对象。一些浏览器中,支持一个属性__proto__来表示这个内部指针:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    Person.prototype.sayName=function(){
     alert(this.name);
    }
    var p1=new Person("Lily",24);
    alert(p1.__proto__.sayName); //function (){alert(this.name);}
    alert(p1.__proto__.constructor==Person); //true
    
    

    在ECMAscript5中新增了一个方法,Object.getPrototypeOf(),可以返回前面提到的实例对象内部的指向其原型的指针的值:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    var p1=new Person("Lily",24);
    alert(Object.getPrototypeOf(p1)==Person.prototype); //true
    
    

    isPrototypeOf()方法也可用于确定实例对象和其原型之间的这种关系:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    var p1=new Person("Lily",24);
    alert(Person.prototype.isPrototypeOf(p1)); //true
    
    

    原型语法

    从前面介绍原型对象于实例对象及构造函数的关系中,我们已经知道,给原型对象添加属性和方法只要像这样定义即可:Person.prototype=name

    那么是否每定义一个Person的属性,就要敲一遍Person.prototype呢?答案是否定的,我们也可以像用对象字面量创建对象那样来创建原型对象:

    function Person(){
    }
    Person.prototype={
     name:"Tom",
     age:29
    }
    var p1=new Person();
    alert(p1.name); //Tom
    alert(p1.age); //29
    
    

    有一点要注意,这个方法相当于重写了整个原型对象,因此切断了它与构造函数的关系,此时Person.prototype.constructor不再指向Person:

    function Person(){
    }
    Person.prototype={
     name:"Tom",
     age:29
    }
    var p1=new Person();
    alert(Person.prototype.constructor==Person); //false
    alert(Person.prototype.constructor==Object); //true
    
    

    因此,如果想要让它重新指向Person,可以显示的进行赋值:

    function Person(){
    }
    Person.prototype={
     constructor:Person,
     name:"Tom",
     age:29
    }
    var p1=new Person();
    alert(Person.prototype.constructor==Person); //true
    alert(Person.prototype.constructor==Object); //false
    
    

    总结

    最后,我们拿一个例子,再来理理构造函数、原型对象以及实例对象之间的关系:

    function Person(name,age){
     this.name=name;
     this.age=age;
    }
    Person.prototype.sayName=function(){
     alert(this.name);
    }
    var p1=new Person("Tom",20);
    alert(Person.prototype); //object
    alert(Person.prototype.constructor==Person); //true
    alert(p1.constructor==Person); //true
    alert(p1.__proto__==Person.prototype); //true
    alert(p1.__proto__.__proto__==Object.prototype); //true
    alert(p1.__proto__.__proto__.constructor==Object); //true
    alert(Person.constructor==Function); //true
    alert(Object.prototype.constructor==Object);
    
    

    上图说明了这个例子中原型、构造函数和实例属性的关系。

    更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript常用函数技巧汇总》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数算用法总结》

    希望本文所述对大家JavaScript程序设计有所帮助。

    下载本文
    显示全文
    专题