[聚合文章] JS创建对象的几种模式

JavaScript 2018-01-10 14 阅读

看了JavaScript中面向对象的一章,里面讲到关于对象创建的几种模式,在这里做一下总结。

工厂模式

直接上代码

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;
}

工厂模式虽解决了创建多个相似对象的问题,但却没有解决对象识别的问题(怎么知道一个对象的类型),随着JavaScript的发展,又一个模式出现了。

构造函数模式

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

相比与工厂模式,不同之处在于:

  1. 没有显示地创建对象
  2. 直接将属性和方法赋给了this对象
  3. 没有return语句

注意:构造函数始终以一个大写字母开头,而非构造函数则应该以一个小写字母开头。

// 当作构造函数使用(通过new操作符来调用)
var person = new Person('jh',19,'Software Engineer');
person.sayName();  //'jh'

构造函数的问题:

每个方法都要在每个实例上重新创建一遍。以这种方式创建函数,会导致不同的作用域链和标识符解析,因此,不同实例上的同名函数是不相等的,以下代码可说明问题:

alert(person1.sayName == person2.sayName); //false

原型模式

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

Tips: 使用hasOwnProperty()方法可检测一个属性是否存在于 实例 中。(原型属性不行)

要取得对象上所有可枚举的实例属性,可用ECMAScript5的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"

var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"

原型对象的问题:

原型中的所有属性被实例共享,可是实例一般都是要有属于自己的全部属性的。

组合使用构造函数模式和原型模式

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);
  }
}

在这个例子中,实例属性都是在构造函数中定义的,而所有实例共享的属性constructor和方法则是在原型中定义的。修改一个实例中的friends属性,并不会影响另一个实例中的friends。

动态原型方法

function Person(name,age,job){
  //属性
  this.name = name;
  this.age = age;
  this.job = job;

  //方法
  if(typeof this.sayName != function){
    Person.prototype.sayName = function(){
      alert(this.name);
    };
  }
}

注意,这里只在sayName()方法不存在的情况下,才会将它添加到原型中。

以上是几种常用的构造函数模式,应理解其中的精髓和每种模式的优点和缺点,在合适的情境下使用。

注:本文内容来自互联网,旨在为开发者提供分享、交流的平台。如有涉及文章版权等事宜,请你联系站长进行处理。