JS 创建对象的几种方式

时间:2023-01-30 18:40:06

面向对象就是把属性和操作属性的方法放在一起作为一个相互依存的整体——对象,即拥有类的概念,基于类可以创建任意多个实例对象,一般具有封装、继承、多态的特性!

ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值 对象 或者函数”。这就是说对象是一组没有特定顺序的值,其中值可以是数据或者函数。

虽然Object构造函数或对象字面量都可以创建单个对象,但这些方式有个明显的缺点,那就是使用同一个接口创造很多对象,会产生大量的重复代码。所以产生了下面几种模式。

1 工厂模式

function createPerson(name,age,job){
var o = {};
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
};
return o;
}
var tanya = createPerson("tanya","30","female");
tanya.sayName();

特点:这种模式抽象了创建具体对象的过程。它用函数来封装以特定接口创建对象的细节。

弊端:没有解决对象识别的问题,而且每次生成一个新对象,都要创建新函数sayName,这使得每个对象都有自己的sayName版本,而事实上,所有的对象都共享同一个函数.

2 构造函数模式

function createPerson(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var tanya =new createPerson("tanya","30","female");
tanya.sayName();

PS:构造函数和普通函数的唯一区别就是调用他们的方式不同:任何函数,只要通过new操作符调用就是构造函数,反之就是普通函数。

使用new操作符创建新实例会经历下面4个步骤:

(1) 创建一个新对象

(2) 将构造函数的作用域赋给新对象(就是this指向了这个新对象)

(3) 执行构造函数中的代码(为这个新对象添加属性)

(4) 返回新对象

构造函数和工厂模式的不同之处:

  • 没有显示的创建对象
  • 直接将属性和方法赋给this对象;
  • 没有return语句

构造函数解决了对象识别的问题(tanya有一个constructor属性,该属性指向createPerson),但是就像工厂模式一样,每个方法都会在每个实例中重新创建一遍。我们可以把函数定义转移到构造函数外部来解决这个问题,但是这样就没有封装性可言了。

3 原型模式

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

PS:JS中万物皆对象,但分为两大类:普通对象和函数对象。所有的函数对象都有一个prototype属性,普通对象是没有prototype属性的,只有_proto_。

function createPerson(){
} createPerson.prototype.name = "tanya";
createPerson.prototype.age = "30";
createPerson.prototype.job = "female";
createPerson.prototype.sayName = function(){
alert(this.name);
};
var tanya =new createPerson();
tanya.sayName();

原型模式虽然解决了构造函数每个方法都会在每个实例中重新创建一遍的问题。但是所有实例在默认情况下都取得了相同的属性值,实例一般都是要有属于自己的全部属性的。

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

function createPerson(name,age,job){
this.name = name;
this.age = age;
this.job = job;
}
createPerson.prototype.sayName = function(){
alert(this.name);
};
var tanya =new createPerson("tanya","30","female");
tanya.sayName();

这是创建自定义类型的最常见方式,构造函数模式定义实例属性,原型模式定义方法和共享的属性。

5 寄生构造函数模式

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

除了使用new操作符来定义新的对象,以及将其称之为构造函数之外,其他和工厂模式定义一模一样。因为创建时用了new,因此使得实现的过程不一样(但是实现过程不重要),结果一样。看起来更优雅

寄生构造函数可以在构造函数不适应的情况使用,比如创建具有额外方法的已有类型(如数组,Date类型等),但是又不污染原有的类型。

6 稳妥构造函数模式

稳妥对象,指的是没有公共属性,其方法也不引用this的对象。

稳妥构造函数与寄生构造函数相似,但是有2点不同:新创建对象的实例方法不引用this,不使用new操作符调用构造函数。

function createPerson(name, age, job) {
var o = new Object(); // private members
var nameUC = name.toUpperCase(); // public members
o.sayName = function() {
alert(name);
};
o.sayNameUC = function() {
alert(nameUC);
}; return o;
} var person = Person("Nicholas", 32, "software Engineer"); person.sayName(); // "Nicholas"
person.sayNameUC(); // "NICHOLAS" alert(person.name); // undefined
alert(person.nameUC); // undefined

凡是想设为 private 的成员都不要挂到 createPerson 返回的对象 o 的属性上面,挂上了就是 public 的了。这里的 private 和 public 都是从形式上类比其他 OO 语言来说的,其实现原理还是 js 中作用域、闭包和对象那一套。