创建对象
使用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__()
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。