创建JS对象的多种方式总结
一、工厂模式
/**
* 工厂模式创建对象
* @param name
* @return {Object}
*/
function createPerson(name){
var o = new Object();
o.name = name;
o.getName = function() {
console.log(this.name);
}
return o;
}
var person = createPerson('zhangsan');
console.log(person.__proto__ === Object.prototype); // true
缺点:无法识别当前的对象,因为创建的所有对象实例都指向的是同一个原型
二、构造函数模式
构造函数创建对象基础版本
/**
* 使用构造函数的方式来创建对象
* @param name
* @constructor
*/
function Person(name) {
this.name = name;
this.getName = function() {
console.log(this.name)
}
}
var person = new Person('lisi');
console.log(person.__proto__ === Person.prototype)
优点:实例剋识别伪一个特定的类型
缺点:每次创建实例对象的时候,每个方法都会被创建一次
构造函数模式优化
function Person(name) {
this.name = name;
this.getName = getName;
}
function getName() {
console.log(this.name);
}
var person = new Person('zhangsan');
console.log(person.__proto__ === Person.prototype);
优点:解决了每个方法都要被重新创建的问题
缺点:不合乎代码规范……
三、原型模式
原型模式基础版
function Person(name) {
}
Person.prototype.name = 'lisi';
Person.prototype.getName = function() {
console.log(this.name);
}
var person = new Person();
console.log(Person.prototype.constructor) // Person
优点:方法不会被重新创建
缺点:1. 所有的属性和方法所有的实例上面都是共享的;2. 不能初始化参数
原型模式优化版本一
function Person(name) {
}
Person.prototype = {
name: 'lisi',
getName: function() {
console.log(this.name);
}
}
var person = new Person();
console.log(Person.prototype.constructor) // Object
console.log(person.constructor == person.__proto__.constructor) // true
优点:封装性好了一些
缺点:重写了Person的原型prototype属性,丢失了原始的prototype上的constructor属性
原型模式优化版本二
function Person(name) {
}
Person.prototype = {
constructor: Person,
name: 'lisi',
getName: function() {
console.log(this.name)
}
}
var person = new Person();
优点:实例可以通过constructor属性找到所属的构造函数
缺点:所有的属性和方法都共享,而且不能初始化参数
四、组合模式
function Person(name) {
this.name = name;
}
Person.prototype = {
constructor: Person,
getName: function() {
console.log(this.name)
}
}
var person = new Person('zhangsan');
优点:基本符合预期,属性私有,方法共享,是目前使用最广泛的方式
缺点:方法和属性没有写在一起,封装性不是太好
五、动态原型模式
// 第一种创建思路:
function Person(name) {
this.name = name;
if (typeof this.getName !== 'function') {
Person.prototype.getName = function() {
console.log(this.name);
}
}
}
var person = new Person();
// 第二种创建的思路:使用对象字面量重写原型上的方法
function Person(name) {
this.name = name;
if (typeof this.getName !== 'function') {
Person.prototype = {
constructor: Person,
getName: function() {
console.log(this.name)
}
}
return new Person(name);
}
}
var person1 = new Person('zhangsan');
var person2 = new Person('lisi');
console.log(person1.getName());
console.log(person2.getName());
六、寄生构造函数模式
/**
* 寄生构造函数模式
* @param name
* @return {Object}
* @constructor
*/
function Person(name){
var o = new Object();
o.name = name;
o.getName = function() {
console.log(this.name)
}
return o;
}
var person = new Person('zhangsan');
console.log(person instanceof Person); // false
console.log(person instanceof Object); // true
// 使用寄生-构造函数-模式来创建一个自定义的数组
/**
* 特殊数组的构造器
* @constructor
*/
function SpecialArray() {
var values = new Array();
/*for (var i = 0, len = arguments.length; i < len; i++) {
values.push(arguments[i]);
}*/
// 开始添加数据(可以直接使用apply的方式来优化代码)
values.push.apply(values, arguments);
// 新增的方法
values.toPipedString = function(){
return this.join('|');
}
return values;
}
// 使用new来创建对象
var colors1 = new SpecialArray('red1', 'green1', 'blue1');
// 不使用new来创建对象
var colors2 = SpecialArray('red2', 'green2', 'blue2');
console.log(colors1, colors1.toPipedString());
console.log(colors2, colors2.toPipedString());
七、稳妥构造函数模式
/**
* 稳妥的创建对象的方式
* @param name
* @return {number}
* @constructor
*/
function Person(name){
var o = new Object();
o.sayName = function() {
// 这里有点类似于在一个函数里面使用外部的变量
// 这里直接输出的是name
console.log(name);
}
return o;
}
var person = Person('lisi');
person.sayName();
person.name = 'zhangsan';
person.sayName();
console.log(person instanceof Person); // false
console.log(person instanceof Object); // false
与寄生的模式的不同点:1. 新创建的实例方法不引用this 2.不使用new操作符调用构造函数
优点:最适合一些安全的环境中使用
缺点:和工厂模式一样,是无法识别对象的所属类型的