JavaScript面向对象设计—对象创建

24 December 2015

面向对象 js 对象创建 模式

面向对象(Object-Oriendted OO)语言的一个标准,那就是他们都有类的概念。 但javaScript是没有类的,因此它的对象定义为“无序属性的集合,其属性可以包含基本值,对象或函数”。

对象的创建方式

1.通过 new Object()创建:

  var o = new Object();

2.使用 {}

  var o = {};

虽然Object构造函数和对象字面量都可以创建对象,但都有明显的缺点:使用同一个接口创建很多对象,会产生大量重复代码。 为了解决上面的问题,开始有了模式用来创建对象。

创建对象

1.工厂模式

工厂模式是软件工厂领域里最广为人知的一种设计模式。

  function createPerson(name , age , job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.getName = function(){
      return o.name;
    };
    return o;
  }
  var person1 = createPerson('jin' , 24 , 'ue');
  var person2 = createPerson('soul' , 24 , 'php');

上面的代码展示了最基本的工厂模式的特点。函数createPerson()就好比一个工厂,参数 [name , age , job]好比是零件, 通过工厂内的 o 处理,生成了多个相似的产品。

总结: 工厂模式可以解决创建多个相似对象的问题,但不能解决对象识别(都是Object对象)。

2.构造函数模式

构造函数可以用来创建特定类型的对象。

  function Person(name , age , job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.getName = function(){
      return this.name;
    };
  }
  var person1 = new Person('jin' , 24 , 'ue');
  var person2 = new Person('soul' , 24 , 'php');

创建Person实例必须使用new。创建实例的步骤主要有4步:

    1. 创建一个新对象
    1. 将构造函数的作用域赋给新对象(this会指向新对象)
    1. 执行构造函数的代码
    1. 返回新对象

总结:创建自定义的构造函数可以将它的实例标识为一种特定的类型。但每个方法都要在每个实例中创建一次。

3.原型模式

我们创建的每一个函数都有一个propotype(原型)属性,这个属性是一个指针,指向一个对象,这个对象包含可以由特定类型的所有实例 共享的属性和方法。

  function Person(){
  }
  Person.prototype.name = 'Jin';
  Person.prototype.age = 24;
  Person.prototype.job = 'ue';
  Person.prototype.getName = function(){
  	return this.name;
  }
  var person1 = new Person();
  var person2 = new Person();
  console.log(person1.getName == person2.getName())//true

要点:实例内部包含着一个指针指向构造函数的原型对象,这个连接是存在于实例与构造函数的原型对象之间,而非实例与构造函数之间。 实例中没有包含属性和函数,但还是可以调用person1.getName()。就是因为这个指针。不过这个过程会调用2次,一次是person1内部,第二次是 原型对象的getName()。

屏蔽原型属性和函数的做法:

  //覆盖原型对象的属性
  person1.name = 'yi';

重新访问原型对象的属性:

  //删除实例中的属性
  delete person1.name

判断属性是在实例中还是在原型对象中:

  //判断属性是在实例中还是在原型对象中
  person1.hasOwnProperty('name') //true  : 实例中  | false : 原型对象中|| 不存在
  //判断属性在原型中  true: 在原型中
  function hasPrototypeProperty(object , name){
    return !object.hasOwnProperty(name) && (name in object);
  }

获取对象属性:

 //可枚举属性获取
 var keys = Object.keys(person1.prototype);
 //for in
 for (var name in person1){
   keys[keys.length] = name;
 }
 keys = keys.join(',');
 //包含不可枚举属性获取
 keys = Object.getPropertyNames(Person.prototype);

总结:成也共享,败也共享。原型中的属性和函数都是共享的。无论哪个实例修改了原型里面的属性或函数多会在其他实例中体现出来。

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

原理:构造函数模式用于定义实例的属性,原型模式用于定义方法和共享属性。

  function Person(name , age , job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['mk' ,'jghon'];
  }
  Person.prototype = {
    constructor: Person,
    getName : function(){
      return this.name;
    }
  }
  var person1 = new Person('jin' ,24 ,'ue');
  var person2 = new Person('soul',24,'php');
  person1.friends.push('ayty');
  consloe.log(person1.friends);//'mk,jghon,ayty'
  console.log(person2.friends);//'mk,jghon'
  console.log(person1.friends === person2.friends);//false
  console.log(person1.getName === person2.getName);//true

目前ECMAScript中使用最广泛,认同度最高的一种创建自定义类型的方法。

5. 动态原型模式

动态原型模式把所有的信息都封装在构造函数中,可以通过检查某个应该存在的方法是否有效,来决定是否初始化原型。

  function Person(name , age , job){
    this.name = name;
    this.age = age;
    this.job = job;
    
    if (typeof this.getName != 'function'){
      Person.prototype.getName = function(){
        return this.name;
      }
    }
  }
  var person = new Person('jin',24,'ue');
  person.getName();

总结:只有在getName函数不存在原型中,才会执行if语句将getName函数添加到原型中。采用这种方式创建出来的对象可以使用instanceof操作符来确定类型。

6. 寄生构造函数模式

基本思想:创建一个函数,该函数的功能仅仅是封装创建对象的代码,然后返回创建的对象。

  function Person(name , age , job){
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.getName = function(){
      return this.name;
    }
    return o;
  }
  var person = new Person('jin',24,'ue');
  person.getName();

总结:返回的对象和构造函数没有半毛钱关系,不能依赖instanceof判断。最后考虑这种类型。

6.稳妥构造函数模式

稳妥对象:就是没有公共属性,方法也不引用this对象。防止其他程序改动。

  function Person(name , age , job){
    var o = new Object();
    o.getName = function(){
      return name;
    }
    return o;
  }
  var person = new Person('jin',24,'ue');
  person.getName();

总结:类似于寄生构造函数模式。适合在安全环境使用。

7.其他方法(“极简主义法”)

荷兰程序员Gabor de Mooij提出这种方法为”极简主义法”(minimalist approach)。 这种方法不使用this和prototype,代码部署起来非常简单,这大概也是它被叫做”极简主义法”的原因。

  var Person = {
    P : function(name , age , job){
      var person = {};
      pseron.name = name;
      person.age = age;
      person.job = job;
      person.getName = function(){
      	return person.name;
      }
      return person;
    }
  }
  var person = Prson.P('jin',24,'ue');
  person.getName();