美文网首页
创建对象----原型模式和构造函数

创建对象----原型模式和构造函数

作者: visa丶 | 来源:发表于2017-08-11 14:54 被阅读0次

创建对象

工厂模式

function createPerson(name, age, job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function(){
        alert(this.name);
    };    
    return o;
}

var person1 = createPerson("Nicholas", 29, "Software Engineer");
var person2 = createPerson("Greg", 27, "Doctor");

person1.sayName();   //"Nicholas"
person2.sayName();   //"Greg"
  • 工厂模式虽然解决了创建多个相似对象的问题,但是没有解决对象识别的问题(即如何知道对象的类型)

构造函数模式

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert(this.name);
    };    
}

var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.sayName();   //"Nicholas"
person2.sayName();   //"Greg"

alert(person1 instanceof Object);  //true
alert(person1 instanceof Person);  //true
alert(person2 instanceof Object);  //true
alert(person2 instanceof Person);  //true

alert(person1.sayName == person2.sayName);  //false 
  • 构造函数始终都应该以一个<font color=#ff0000>大写字母</font>开头,要创建新的实例,必须使用new操作符。

  • 每一个实例都有一个constructor(构造函数)属性,该属性指向实例的构造函数。

      alert(person1.constructor == Person);  //true
      alert(person2.constructor == Person);  //true
    
  • 构造函数与其他函数唯一的不同就是调用方式不同,任何函数只要用new操作符来调用,那它就可以作为构造函数

  • 构造函数的问题:每个方法在每个实例上都要重新创建一遍,不同实例上的同名方法其实是互相不相等的


原型模式

  • 每个函数都有一个prototype(原型)属性,这个属性是一个<font color=#ff0000>指针</font>,指向一个对象,这个对象的作用是包含可以由特定类型的所有实例共享的属性和方法。prototype也就是通过调用构造函数而创建的那个对象实例的原型对象。

      function Person(){
      }
    
      Person.prototype.name = "Nicholas";
      Person.prototype.age = 29;
      Person.prototype.job = "Software Engineer";
      Person.prototype.sayName = function(){
          alert(this.name);
      };
      
      var person1 = new Person();
      person1.sayName();   //"Nicholas"
      
      var person2 = new Person();
      person2.sayName();   //"Nicholas"
      
      alert(person1.sayName == person2.sayName);  //true
    
  • 新对象的这些属性和方法是所有实例共享的

理解原型对象

  • 无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。

  • 默认情况下,所有原型对象会自动获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针。就上面的例子而言,Person.prototype.constructor指向Person。

  • 创建了自定义构造函数之后,其原型对象只会获得constructor属性,至于其他方法,则全是从Object继承来的,当调用构造函数创建一个新实例之后,该实例的内部将会包含一个指针(内部属性),指向构造函数的原型对象。这个属性叫做[[prototype]],也就是proto。注意:这个连接存在于实例和构造函数的原型对象之间,和构造函数没有直接关系。

  • 虽然所有实现中都无法访问到[[prototype]],但是可以通过isPrototypeOf()方法来确定对象之间是否是否存在这种关系

      alert(Person.prototype.isPrototypeOf(person1));  //true
      alert(Person.prototype.isPrototypeOf(person2));  //true
    
  • Object.getPrototypeOf() 取得一个对象的原型

      //only works if Object.getPrototypeOf() is available
      if (Object.getPrototypeOf){
          alert(Object.getPrototypeOf(person1) == Person.prototype);  //true
          alert(Object.getPrototypeOf(person1).name);  //"Nicholas"
      }
    
  • 原型最初只包含constructor属性,而该属性也是共享的,因此可以通过对象实例来访问

  • 虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。

      function Person(){
      }
      
      Person.prototype.name = "Nicholas";
      Person.prototype.age = 29;
      Person.prototype.job = "Software Engineer";
      Person.prototype.sayName = function(){
          alert(this.name);
      };
      
      var person1 = new Person();
      var person2 = new Person();
      
      person1.name = "Greg";
      alert(person1.name);   //"Greg" from instance
      alert(person2.name);   //"Nicholas" from prototype
    
  • 通过delete操作符可以完全删除实例属性,从而让我们能重新访问原型中的属性

      delete person1.name;
      alert(person1.name);   //"Nicholas" - from the prototype
    
  • hasOwnProperty() 方法可以检测一个属性是存在于实例中,还是原型中,只有给定属性在对象实例中,才会返回true。

原型与in操作符

  • in操作符有两种使用方式,一种是在for-in循环中,一种是单独使用。单独使用时,in操作符会在通过对象能够访问访问给定属性时返回true,无论该属性在实例中还是原型中。

      function Person(){
      }
      
      Person.prototype.name = "Nicholas";
      Person.prototype.age = 29;
      Person.prototype.job = "Software Engineer";
      Person.prototype.sayName = function(){
          alert(this.name);
      };
      
      var person1 = new Person();
      var person2 = new Person();
      
      alert(person1.hasOwnProperty("name"));  //false
      alert("name" in person1);  //true
      
      person1.name = "Greg";
      alert(person1.name);   //"Greg" from instance
      alert(person1.hasOwnProperty("name"));  //true
      alert("name" in person1);  //true
      
      alert(person2.name);   //"Nicholas" from prototype
      alert(person2.hasOwnProperty("name"));  //false
      alert("name" in person2);  //true
      
      delete person1.name;
      alert(person1.name);   //"Nicholas" - from the prototype
      alert(person1.hasOwnProperty("name"));  //false
      alert("name" in person1);  //true
    
  • 在for-in循环时,返回的是所有能够通过对象访问的,可枚举的属性。

  • Object.keys() 接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。

      function Person(){
      }
      
      Person.prototype.name = "Nicholas";
      Person.prototype.age = 29;
      Person.prototype.job = "Software Engineer";
      Person.prototype.sayName = function(){
          alert(this.name);
      };
      
      var keys = Object.keys(Person.prototype);
      alert(keys);   //"name,age,job,sayName"
    
  • Object.getOwnPropertyNames() 获得所有实例属性,无论是否可枚举

      var keys = Object.getOwnPropertyNames(Person.prototype);
      alert(keys);   //"constructor,name,age,job,sayName"
    

更简单的原型语法

function Person(){
}

Person.prototype = {
    name : "Nicholas",
    age : 29,
    job: "Software Engineer",
    sayName : function () {
        alert(this.name);
    }
};
  • 如果将Person.prototype设置为等于一个以对象字面量形式创建的新对象,那么constructor将不再指向Person。因为这样本质上完全重写了默认的prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object)构造函数,不再指向Person函数。

      var friend = new Person();
      
      alert(friend instanceof Object);  //true
      alert(friend instanceof Person);  //true
      alert(friend.constructor == Person);  //false
      alert(friend.constructor == Object);  //true
    
  • 可以把constructor重新设置回适当的值。

      function Person(){
      }
      Person.prototype = {
      constructor: Person,
      name : "Nicholas",
      age : 29,
      job: "Software Engineer",
      sayName : function () {
          alert(this.name);
      }
      };
    
  • 以这种方式重设constructor属性会导致它的[[Enumerable]]特性被设置为true。默认情况下,原生的constructor属性是不可枚举的。

原型的动态性

  • 由于在原型中查找值得过程是一次搜索,因此我们对原型对象做的任何修改都能立即从实例上反映出来————即使是先创建实例后修改原型。

  • 实例和原型之间的联系是一个指针,而不是一个副本。

  • 调用构造函数时,会为实例添加一个指向最初原型的[[prototype]]指针。如果重写整个原型对象,会切断构造函数与最初原型之间的联系。<font color=#ff0000>实例中的指针仅指向原型,并非构造函数!</font>

      function Person(){
      }
      
      var friend = new Person();
              
      Person.prototype = {
          constructor: Person,
          name : "Nicholas",
          age : 29,
          job : "Software Engineer",
          sayName : function () {
              alert(this.name);
          }
      };
      
      friend.sayName();   //error
    
  • 上面报错的原因是重写原型对象切断了现有原型和已经存在的对象实例的联系。实例引用的仍是原来的原型。


组合使用构造函数和原型

  • 创建自定义类型的最常见模式就是组合使用构造函数和原型,构造函数用于定义实例属性,原型用于定义方法和共享的属性。这样,每个实例都会有自己的一份实例属性的副本,但同时也共享着对方法的引用,最大限度地节省了内存。

      function Person(name, age, job){
          this.name = name;
          this.age = age;
          this.job = job;
          this.friends = ["Shelby", "Court"];
      }
      
      Person.prototype = {
          constructor: Person,
          sayName : function () {
              alert(this.name);
          }
      };
      
      var person1 = new Person("Nicholas", 29, "Software Engineer");
      var person2 = new Person("Greg", 27, "Doctor");
      
      person1.friends.push("Van");
      
      alert(person1.friends);    //"Shelby,Court,Van"
      alert(person2.friends);    //"Shelby,Court"
      alert(person1.friends === person2.friends);  //false
      alert(person1.sayName === person2.sayName);  //true

相关文章

  • 对象的创建与继承

    创建对象 工厂模式 => 构造函数模式 => 原型对象模式 => 构造函数模式+原型对象模式 工厂模式 构造函数模...

  • 构造函数-js-高级程序设计-第六章笔记

    前言 理解对象 创建对象构造函数模式原型模式组合使用构造函数模式和原型模式动态原型模式寄生构造函数模式稳妥构造函数...

  • JavaScript 面向对象

    单个对象 创建自定义对象 创建对象字面量 变体 工厂模式 构造函数模式 原型模式 构造函数模式+原型模式 寄生构造模式

  • 链式操作

    对象字面量创建对象 构造函数创建对象 构造函数和原型一起创建对象 参考 JavaScript设计模式 --- 方法...

  • 2020-12-15

    js对象的创建和函数 创建对象 工厂模式 构造函数 原型方式+构造函数

  • Js创建对象的几种模式

    Js创建对象的几种模式 工厂模式 构造函数模式 原型模式 组合使用构造函数模式和原型模式 动态原型模式 稳妥构造函数模式

  • 关于JavaScript创建对象的多种方式

    JavaScript创建对象的方法 工厂模式 构造函数模式 原型模式 组合使用构造函数模式和原型模式 动态原型模式...

  • js中创建对象的方式

    大纲:创建单个对象(Object构造函数,对象字面量)创建多个对象(工厂模式,构造函数模式,原型模式,组合使用构造...

  • JavaScript创建对象

    JavaScript中创建对象有以下七种方式: 工厂模式构造函数模式原型模式构造函数和原型组合模式动态原型模式寄生...

  • js创建对象的几种方式

    1.object创建对象 2.工厂模式创建对象 3.基于构造函数创建对象 4.基于原型创建对象 5.构造函数与原型...

网友评论

      本文标题:创建对象----原型模式和构造函数

      本文链接:https://www.haomeiwen.com/subject/asalrxtx.html