js 中创建对象的方式有很多种,不同的场景下运用不同的方法
工厂模式
比较早的一种方法。用函数封装以特定接口创建对象的细节。
function createPerson (name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function () {
console.log(this.name);
}
return o;
}
var person1 = createPerson('张三', 24, 'chinese');
var person2 = createPerson('李四', 25, 'chinese');
这种方式可以解决创建多个类似对象的问题,但是无法解决对象的识别问题,(即怎样知道一个对象的具体类型,如:Array, Date。 其实也就是对象的构造函数);
构造函数模式
js中的构造函数可以用来创建特定类型的对象。像 Object 和 Array 这样的原生构造函数,在运行时会自动出现在执行环境中。此外、也可以创建自定义的构造函数,然后定义自定义对象类型的属性和方法。
function Person (name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function () {
console.log(this.name);
}
}
var person1 = new Person('张三', 24, 'chinese');
var person2 = new Person('李四', 25, 'chinese');
使用构造函数创建对象,必须使用 new 操作符;以这中方式调用构造函数实际上会经过以下几个步骤:
-
创建一个新对象
-
将构造函数的作用域赋给新对象,(this 就指向了这个新对象);
-
执行构造函数中的代码(为这个新对象添加属性和方法);
-
返回新对象。
person1 和 person2 都是Person 的一个不同的实例。这两个对象都有一个 constructor
属性, 指向 Person 。
console.log(person1.constructor === Person); // true
console.log(person2.constructor === Person); // true
创建构造函数,意味着将来可以将它们的实例标识为特定的类型。
- 将构造函数当作函数
构造函数与其他函数的唯一区别就是调用的方式不一样。任何函数只要通过 new
操作符调用,那它就是一个构造函数。
- 构造函数的问题 构造函数的主要问题就是,每个方法都要在每个实例上重新创建一遍。上面的例子中,person1 和 person2 都有一个 sayName 方法,并且指向的是不同的实例。 然而创建两个完成同样任务的 Function 实例实在没有必要,因此可以把函数的定义转移到构造函数的外部。
function Person(name, obj, job) {
this.name = name;
this.obj = obj;
this.job = job;
this.sayName = sayName;
}
function sayName () {
console.log(this.name);
}
console.log(person1.constructor === Person); // true
console.log(person2.constructor === Person); // true
通过把 sayName 方法定义到外部,而在构造函数内部,把sayName属性 指向到外部的sayName,就可以让实例共享同一个方法。但是这样的问题还是很多,sayName 方法定义在全局作用域,如果需要多个方法的话,就需要定义多个全局方法,丝毫没有封装性可言。
原型模式
我们创建的每一个函数都有一个prototype
(原型)属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的实例共享的属性和方法。
按照字面意思来理解,prototype 就是通过调用构造函数而创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有对象实例共享它包含的属性和方法。 也就是说,不必在构造函数中定义对象实例的信息,而是将这些信息直接添加到原型对象上。
function Person() {}
Person.prototype.name = "张三";
Person.prototype.age = 24;
Person.prototype.job = "chinese";
Person.prototype.sayName = function () {
console.log(this.name);
}
let person1 = new Person();
person1.sayName(); // 张三
let person2 = new Person();
person2.sayName(); // 张三
console.log(person1.sayName === person2.sayName); // true
将 sayName 方法 和属性 都添加到 Person 的 prototype
属性上。这样创建出来的对象都会共享这些方法和属性。并且它们访问的都是同一组属性和方法。
要理解原型模式的工作原理,必须先理解 js 中原型对象的本质。
内容有点多,单独建个页面吧。