JavaScript把几乎一切都当做对象,因此语言中所有的元素都可以被创建、赋予属性以及被链接到原型链中。仅有的例外是null和undefined。在JavaScript中对象是被创建出来的,它们不是凭空产生的。
1. 对象字面量
字面量语法可以用内联的方式描述一个对象,外面有一个大括号,里面的代码是一系列由逗号隔开的属性。不像 new Object()语法,字面量语法不会被显示调用,因为在特定的上下文中,字面量实际上是使用Object.create方法的快捷方式。举个例子:
var
foo = {
bar:
'baz'
};
var
foo2 =
Object.
create(
Object.
prototype,{
bar:{
writable:
true,
configurable:
true,
value:
'baz'
}
});
console.
log(
foo.
bar);
//baz
console.
log(
foo2.
bar);
//baz
字面量语法很清晰,表现力强而且很紧凑。你可以使用内联的方式同时描述和创建对象。这种特质让字面量语法成为创建简单的一次性对象的最佳选择。这种一次性对象可以用来处理事件、整理对象间状态的改变或者划分功能,同时可以保持代码在视觉上的聚合。字面量语法和new Object()的另一个细小区别是,字面量语法的构造函数不能被重新定义。不过,原生对象的构造函数属于全局命名空间,如果修改可能会导致意想不到的行为,很难追踪。字面量语法被隐式调用这一点,给代码提供了一点防御性。
var
foo =
new
Object();
var
bar = {};
console.
log(
typeof(
foo));
//object
console.
log(
typeof(
bar));
//object
window.
Object =
function(){
arguments.
callee.
call();
}
//Uncaught RangeError: Maximun call stack size exceed
var
foo =
new
Object();
这种字面量语法并不是在所有情况下都适用,例如,你不能创建一个原型不是内置对象的对象。而且因为字面量语法是隐式调用的,所以它没有显式的构造函数。另外,很多JSON解释器需要属性使用双引号来定义,而字面量语法并没有这种要求。
2. new Object()
当谈到new Object()时,其实讨论的是new运算符。这个运算符根据需求来创建对象的实例。它接受一个构造函数和一系列初始化过程中使用的可选参数。对象创建完成后,新创建的对象继承自构造函数的原型。
var
Animal,
cat,
dog;
Animal =
function(
inLove){
this.
lovesHumans =
inLove ||
false;
};
cat =
new
Animal();
dog =
new
Animal(
true);
console.
log(
cat.
lovesHumans);
//false
console.
log(
dog,
lovesHumans);
//true
new运算符是一种JavaScript试图让自己类似于Java的退化结构。很多人都会对new运算符感到很疑惑,因为它强加了一种伪类动词到JavaScript中,但JavaScript并不是一种正规的基于继承方法的语言。为了更好的理解new关键字在幕后做了什么,让我们看一下前面的例子,来剖析new都为我们做了什么。希望这可以清除掉由它的语义带来的潜在的歧义。
1. JavaScript创建一个新的对象
这相当于创建了一个对象自变量{}。
2. JavaScript将新创建的对象的构造函数链接到函数Animal上
console.
log(
cat.
constructor);
3. JavaScript讲对象的原型链接到Animal.prototype
在对象构造过程中,新创建的对象会获得前一个构造函数属性的引用。它们是一个浅拷贝,如果以后修改的话,实际情况是原构造函数属性的引用会被一个本地的引用覆盖。
var
Animal,
cat,
dog;
Animal =
function(
inLove){
this.
lovesHumans =
inLove ||
false;
};
cat =
new
Animal();
dog =
new
Animal(
true);
//捕获异常
try {
console.
log(
cat.
jump());
}
catch (
error) {
//something
}
Animal.
prototype.
jump =
function(){
return
'how high ?';
};
console.
log(
cat.
jump());
//how high ?
console.
log(
dog,
jump());
//how high ?
cat.
jump =
function(){
return
'no';
}
console.
log(
cat.
jump());
//no
console.
log(
dog.
jump());
//how high ?
4. JavaScript将传入的参数赋给新创建的对象
new运算符在新对象创建时,将任意数量的属性初始化到对象中。它们会作为参数传入到构造函数中。
var
Animal,
dog;
Animal =
function(
inLove){
this.
lovesHumans =
inLove ||
false;
};
dog =
new
Animal(
true);
/**
* new 运算符做了以下动作
* dog = {};
* dog.lovesHumans = true
*/
3. Object.create
在ECMAScript 5 中引入Object.create方法之前,只能使用new运算符来实现原型链继承。总而言之,Object.create()和字面量对象应该替换new Object()这种方法。Object.create()给开发者提供了new运算符的优点,而且方法签名与语言其他部分还能保持一致。Object.create的好处已经超越了仅仅提升语义本身,实际上它在对继承的支持方面更加强大。Object.create可以接收两个参数:一个是提供原型的对象,另一个是可选属性对象,这个对象包含对新创建对象的配置。
var
car = {
drive
:
function(
miles){
return
this.
odometer +=
miles;
}
};
var
tesla =
Object.
create(
car,{
'odometer'
:{
value:
0,
enumerable:
true
}
});
console.
log(
tesla.
drive(
10));
//10