JS-创建对象

38次阅读

共计 3959 个字符,预计需要花费 10 分钟才能阅读完成。

创建对象
使用 new Object() 或者对象字面量都可以创建对象,但是这样创建的对象过于简单,不易于对象的属性与方法的扩展与继承。下面讲的对象可以与 JavaEE 中的 bean 做类比。
工厂模式
对,首先可能想到的是使用设计模式中的工厂模式
function createPizza(type) {
var o = new Object();
o.type = type;
o.bake = function() {
alert(‘Start~’);
alert(this.type);
alert(‘End~’);
};
return o;
}

var cheesePizza = createPizza(‘cheese’);
var veggiePizza = createPizza(‘veggie’);
cheesePizza.bake();
优点
工厂模式解决了创建多个类似对象的问题
缺点
对象无法识别,即创建出来的对象无法通过 instanceof 等分析出属于哪种类型
构造函数模式
用构造函数可用来创建特定类型的对象
// 构造函数首字母遵循 OO 语言惯例进行大写
function Pizza(type) {
this.type = type;
this.bake = function() {
alert(‘Start~’);
alert(this.type);
alert(‘End~’);
};
}

var cheesePizza = new Pizza(‘cheese’);
var veggiePizza = new Pizza(‘veggie’);
cheesePizza.bake();
与工厂模式相比:

没有在方法中显示创造对象(o);
直接将属性与方法赋值给 this;
没有 return 语句

在用 new 的时候,会经历一下 4 步:

创建一个新对象
将构造函数的作用域赋值给新对象(此时 this 指向新对象)
执行构造函数代码(为对象添加属性)
返回新对象

如果不使用 new,将构造函数当做函数使用,则 this 指向 Global 对象(在浏览器中为 window 对象),当然,可以使用 call 方法来指定作用域,例如
var o = new Object();
Pizza.call(o, ‘salty’);
o.bake();
使用构造函数方法,每个实例对象都有一个 constructor 构造函数属性,该属性指向 Pizza(使用对象字面量、工厂模式方法创建的对象该属性指向 Object)
cheesePizza.constructor == Pizza
检查某个对象属于哪种类型,一般使用 instanceof,cheesePizza 同时属于 Pizza 与 Object(之所以属于 Object,是因为所有对象均继承于 Object)
cheesePizza instanceof Pizza;
cheesePizza instanceof Object;
优点
与工厂模式相比,构造函数模式能够识别出对象类型与下面的原型模式相比,能够实现对象属性的互相独立,在引用类型属性上很有用
缺点
每个实例对象的方法都是独立的,导致方法不能够共享
原型模式
每个函数(不是实例对象)都有一个 prototype 属性,该属性是一个指针,指向一个对象,对象的用途是包含所有实例共享的属性和方法。prototype 通过调用构造函数创建的那个对象实例的原型对象。使用原型对象的好处是可以让所有实例对象共享属性与方法。
function Pizza() {

}

Pizza.prototype.type = ‘original’
Pizza.prototype.bake = function() {
alert(‘Start~’);
alert(this.type);
alert(‘End~’);
};

var cheesePizza = new Pizza();
cheesePizza.type = ‘cheese’;
var veggiePizza = new Pizza();
veggiePizza.type = ‘veggie’;

cheesePizza.bake();
veggiePizza.bake();
各个对象共享属性与方法,同时每个对象都可以建立自己的属性,并屏蔽掉原型对象的同名属性,因为共享属性与方法,所以以下等式成立
cheesePizza.bake == veggiePizza.bake
对象字面量重写原型对象
也可以通过对象字面量来重写整个原型对象:
Pizza.prototype = {
type: ‘original’,
bake: function() {
alert(‘Start~’);
alert(this.type);
alert(‘End~’);
}
}
这样完全重写,原型对象上的 constructor 属性不再指向 Pizza 函数(全新的 constructor 指向 Object),不过不影响通过 instanceof 来识别对象类型。如果 constructor 特别重要的话,可以显式将它置为适当的值:
Pizza.prototype = {
constructor: Pizza,
type: ‘original’,
bake: function() {
alert(‘Start~’);
alert(this.type);
alert(‘End~’);
}
}
不过这种方式会将 constructor 的属性特征变为可枚举,而默认情况下它是不可枚举的,如果想不可枚举,可以使用 Object.defineProperty() 方法。
原型的动态性
对原型对象的修改会体现在实例对象上,即使实例对象先被创建。但是通过对象字面量重写的原型对象则没有该动态性
优点
定义在原型对象上的属性,能够保证在各实例对象上的共享
缺点
对于引用类型的属性,各实例的共享会导致额外的问题。
组合使用构造函数模式与原型模式
整合构造函数模式与原型模式,构造函数模式用于定义实例属性,原型模式用于定义方法和共享属性。
动态原型模式
寄生构造函数模式
稳妥构造函数模式
各创建模式在 Chrome 浏览器中的表现
可以通过 Chrome 浏览器观察使用工厂模式创建的 cheesePizza 对象属性为:
cheesePizza
{type: “cheese”, bake: ƒ}
bake: ƒ ()
type: “cheese”
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
使用构造函数模式创建 cheesePizza 对象属性为:
cheesePizza
Pizza {type: “cheese”, bake: ƒ}
bake: ƒ ()
type: “cheese”
__proto__:
constructor: ƒ Pizza(type)
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
使用原型模式创建 cheesePizza 对象属性为:
cheesePizza
Pizza {type: “cheese”}
type: “cheese”
__proto__:
bake: ƒ ()
type: “original”
constructor: ƒ Pizza()
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
参考文章
ESLint 需要约束 for-in (guard-for-in)
个人不定期更新主页

正文完
 0