β

JavaScript OOP 之创建对象

YujieLee 141 阅读

JS 中创建对象的方法有很多,主要包括简单模式、工厂模式、构造函数模式等等。

对象字面量模式

var obj = {
    property1 : "val1",
    getValue : function() {
        alert(this.property1);
    }
}

通过 new 创建对象

var obj = new Object();
obj.property1 = "val1";
obj.getValue = function() {
    alert(this.property1);
}

上述代码对于创建少量的对象是使用的。但如果使用同一接口创建很多对象,那么就会产生许多重复代码。因此考虑使用下列方法。

工厂模式

function createObject(value1, value2) {
    var obj = new Object();
    obj.property1 = value1;
    obj.property2 = value2;
    obj.getValue = function() {
        alert(this.property1);
    };
    return obj;
}
var obj1 = createObject("val1", "val2");

该方法没有解决如何科学地识别对象的问题。也就是说无法判断它的类。

构造函数模式

function Obj(value1, value2) {
    this.property1 = value1;
    this.property2 = value2;
    this.getValue = function() {
        alert(this.property1);
    };
}
var obj2 = new Obj("val1", "val2");

这种方式解决了识别对象的问题。(instanceof())。但这时候问题又来了,这种方式对每个实例都会创建同样一组新方法,也就是说每一个实例的同名方法 getValue() 方法是不相等的。

原型模式

function Obj() {}
Obj.prototype.property1 = "val1";
Obj.prototype.property2 = "val2";
Obj.prototype.getValue = function() {
    alert(this.property1);
};
var obj1 = new Obj();
obj1.getValue();

这样,所有实例共享一个原型,那么这两个同名方法就可以相等了。但随之而来的问题是,第一,其构造函数没有参数,对实例化不方便。第二,对于引用类型的值(Array 等)处理不妥当,修改了其中一个对象的数组属性后,原型的数组属性也会跟着变化。

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

function Obj(value1, value2) {
    this.property1 = value1;
    this.property2 = value2;
    this.properties = ["foo", "bar"];
}
Obj.prototype = {
    constructor : Obj,
    getProperty : function() {
        alert(this.property1);
    }
}
var obj1 = new Obj("val1", "val2");
var obj2 = new Obj("val3", "val4");
obj1.properties.push("baz");
alert(obj1.properties); // "foo","bar","baz"
alert(obj2.properties); // "foo", "bar"
alert(obj1.getProperty === obj2.getProperty); // true

这种模式正好解决了上述的问题,因此也成为应用最广泛的模式之一。

动态原型模式

function Obj(value1, value2) {
    this.property1 = value1;
    this.property2 = value2;
    if (typeof this.getProperty != "function") {
        Obj.prototype.getProperty = function() {
            alert(this.property1);
        }
    }
}
var obj1 = new Obj("val1", "val2");
obj1.getProperty();

这个模式与上述模式差别不大,只是将初始化原型封装在构造函数里,仅在第一次调用构造函数时才会初始化原型。

稳妥构造函数模式

function Obj(value1, value2) {
    var obj = new Object();
    obj.getProperty1 = function() {
        alert(value1);
    }
    obj.getProperty2 = function() {
        alert(value2);
    }
    return obj;
}
var obj1 = Obj("val1", "val2");

寄生构造函数模式

function Obj(value1, value2) {
    var obj = new Object();
    obj.property1 = value1;
    obj.property2 = value2;
    obj.getProperty = function() {
        alert(this.property);
    }
    return obj;
}
var obj1 = new Obj("val1", "val2");

上述两种方法差别不大,所谓稳妥对象,指的是没有公共属性,而且其方法也不引用 this 对象。而寄生模式可以作为修改原生对象的方法之一。但这两种方法的主要问题是构造函数与返回的对象没有关系,不能够用 instanceof() 来判断对象类型。

使用闭包

静态私有变量

(function(){
    var property = "";
    Obj = function(value){
        property = value;
    }; // 此处不能使用函数声明,因为函数声明是局部变量,而此处需要全局变量
    Obj.prototype.getProperty = function() {
        return property;
    };
    Obj.prototype.setProperty = function(value) {
        property = value;
    };
})();
var obj1 = new Obj("foo");
alert(obj1.getProperty());
var obj2 = new Obj("bar");
alert(obj2.getProperty() + "/" + obj1.getProperty()); // bar;bar

从以上例子可以看出,闭包可以实现静态私有变量,就像 property

模块模式

var singleton = function() {
    var privateVariable = "foo";
    function privateFunction() {
        return "bar";
    }
    return {
        publicProperty : "baz",
        publicMethod : function() {
            privateVariable = "qux";
            return privateFunction();
        }
    };
}();

单例模式的实现。如果必须创建一个对象并以某些数据对其初始化,同时还要公开一些能够访问这些私有数据的方法,那么就可以使用模块模式。这种模式也不能够用 instanceof() 方法判断类型(也没有必要)。

作者:YujieLee
设计,产品,前端,用户体验
原文地址:JavaScript OOP 之创建对象, 感谢原作者分享。