JavaScript精粹读书笔记(3)

来源:互联网 发布:电信光纤网络 编辑:程序博客网 时间:2024/06/09 13:40

 

第3章 对象
JavaScript的简单类型包括数字、字符串、布尔值(true和false)、null值和undefined值。其他所有的值都是对象。数字、字符串和布尔值“貌似”对象,因为它们拥有方法,但它们是不可变的。JavaScript中的对象是可变的键-值集合(keyed collections)。在JavaScript中,数组是对象,函数是对象,正则表达式是对象,当然,对象自然也是对象。
对象是属性的容器,其中每个属性都拥有名字和值。属性的名字可以是包括空字符串在内的任意字符串。属性值可以是除undefined值之外的任何值。
JavaScript中的对象是无类型(默然说话:或者说JavaScript只有一种类型,就是对象)(class-free)的。它对新属性的名字和值没有约束。对象适合用于收集和管理数据。对象可以包含其他对象,所以它们可以容易地表示成树形或图形结构。
JavaScript包括一个原型链特性,允许对象继承另一对象的属性。正确地使用它能减少对象初始化的时间和内存消耗。
3.1   对象定义
对象定义提供了一种非常方便地创建新对象值的表示法。一个对象定义就是包围在一对花括号中的零或多个“名:值”对。对象定义可以出现在任何允许表达式出现的地方。
var empty_object={};
var stooge={
       “first-name”:”Jerome”,
       “last-name”:”Howard”
};
属性名可以是换手空字符串在内的任何字符串。在对象定义中,如果属性名是一个合法的JavaScript标识符且不是保留字,并不强制要求用引号括住属性名。所以用引号括住”first-name”是必须的,但是否括住first_name则是可选的。逗号用来分隔多个“名:值”对。
属性的值可以从包括另一个对象定义在内的任意表达式中获得。对象是可嵌套的:
var flight={
       airline:”Oceanic”,
       number:815,
       departure:{
              IATA:”SYD”,
              time:”2004-09-22 14:55”,
              city:”Sydney”
       },
       arrival:{
              IATA:”LAX”,
              time:”2004-09-23 10:42”,
              city:”Los Angeles”
       }
};
3.2   检索
要检索对象中包含的值,可以采用在[]后缀中括住一个字符串表达式的方式。如果字符串表达式是一个常数,而且它是一个合法的JavaScript标识符而非保留字,那么也可以用点(.)表示法代替。优先考虑使用点(.)表示法,因为它更紧凑且可读性更好。
stooge[“first-name”]                        //”Joe”
flight.departure.IATA                       //”SYD”
如果你尝试检索一个并不存在的成员元素的值,将返回一个undefined值。
stooge[“middle-name”]                          //undefined
stooge[“FIRST-NAME”]                          //undefined
flight.status                                      //undefined
||运算符可以用来填充默认值:
var middle=stooge[“middle-name”]||”(none)”;
var status=flight.status||”unknown”;
尝试检索一个undefined值将会导致TypeError异常。这可以通过&&运算符来避免错误。
flight.equipment                                                                 //undefined
flight.equipment.model                                                             //throw “TypeError”
flight.equipment && flight.equipment.model                            //undefined
3.3   更新
对象中的值可以通过赋值语句来更新。如果属性名已经存在于对象中,那么这个属性的值被替换。
stooge[‘first-name’]=’Jerome’;
如果对象之前并没有这个属性,那么该属性就被扩充到该对象中。
stooge[‘middle-name’]=’Lester’;
flight.equipment={
       model:’Boeing 777’
};
3.4   引用
对象通过引用来传递。它们永远不会被拷贝:
var x=stooge;
x.nickname=’Curly’;
var nick=stooge.nickname;//因为x和stooge是指向同一个对象的引用,所以nick为’Curly’
var a={},b={},c={};//a,b和c每个都引用一个不同的空对象
a=b=c={}//a,b和c都引用同一个空对象。
3.5   原型
每个对象都连接到一个原型对象,它可以继承属性。所有通过对象定义创建的对象都连接到Object.prototype这个JavaScript中标准的对象。
当你创建一个新对象时,你可以选择某个对象作为它的原型。JavaScript提供的实现机制杂乱而复杂,但其实它可以被明显地简化。我们将给Object增加一个beget方法。这个beget方法创建一个使用原对象作为其原型的新对象。下章将会有更多关于函数的内容。
if(typeof(Object.beget!==’function’)){
       Object.beget=function(o){
              var F=function(){};
              F.prototype=o;
              return new F();
       };
}
var another_stooge=Object.beget(stooge);
原型链在更新时是不起作用的。当我们对某个对象做出改变时,不会触及到该对象的原型:
another_stooge[‘first-name’]=’Harry’;
another_stooge[‘middle-name’]=’Moses’;
another_stooge.nickname=’Moe’;
stooge[‘first-name’];                 //不会被更新为’Harry’
原型连接只有在检索值的时候才被用到。如果我们尝试去获取对象的某个属性值,且该对象没有此属性名,那么JavaScript会试着从原型对象中去获取属性值,直到该过程最后到达终点Object.prototype。如果找不到该属性,结果就是undefined。这个过程称为委托
如果我们添加一个新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见。
stooge.profession=’actor’;
another_stooge.profession               //’actor’
我们将会在第6章中看到更多关于原型链的内容。
3.6   反射
JavaScript似乎没有直接提供相关反射的处理,所以需要自己编写代码实现,检查对象并确定对象有什么属性。
我们可以使用typeof来确定属性的类型。
typeof(flight.number)                            //’number’
typeof(flight.status)                        //’string’
typeof(flight.arrival)                       //’object’
typeof(flight.manifest)                           //’undefined’
但原型链中的任何属性也会产生一个值。我们可以使用hasOwnProperty方法,如果对象拥有独有的属性,它将返回true。hasOwnProperty方法不会检查原型链。
flight. hasOwnProperty(‘number’)                //true
flight. hasOwnProperty(‘constructor’)           //false
3.7   枚举
for in语句可用来遍历一个对象中的所有属性名。该枚举过程将会列出所有的属性——包括函数和你可能不关心的原型中的属性——所以有必要过滤掉那些你不想要的值。最为常用的过滤器是hasOwnProperty方法,以及使用typeof来排除函数:
for(var name in another_stooge){
       if(typeof(another_stooge[name])!==’function’){
              document.writeln(name+”:”+another_stooge[name]);
       }
}
for in无法保证属性名出现的顺序,因此要对任何可能出现的顺序有所准备。如果你想要确保属性以特定的顺序出现,最好的办法就是完全避免使用for in语句,而是创建一个数组,在其中以正确的顺序包含属性名。再通过使用for而不是for in,可以得到我们想要的属性,而不用担心可能发掘出原型链中的属性,并且我们按正确的顺序取得了它们的值。
var i;
var properties = [
    'first-name',
    'middle-name',
    'last-name',
    'profession'
];
for (i = 0; i < properties.length; i += 1) {
    document.writeln(properties[i] + ': ' +
            another_stooge[properties[i]]);
    }
}
3.8   删除
delete运算符可以用来删除对象的属性。它将会移除对象中确定包含的属性。它不会触及原型链中的任何对象。
删除对象的属性可能会让来自原型链中的属性浮现出来:
another_stooge.nickname                             //’Moe’
//删除another_stooge的nickname属性,从而暴露出原型的nickname属性
delete another_stooge.nickname;
another_stooge.nickname                       //’Curly’
3.9   减少全局变量污染
JavaScript可以很随意地定义那些可保存所有应用资源的全局变量。不幸的是,全局变量削弱了程序的灵活性,所以应该避免。
最小化使用全局变量的一个方法是在你的应用中创建唯一一个全局变量:
var MYAPP={};
该变量此时变成了你的应用的容器:
MYAPP.stooge={
         “first-name”:”Joe”,
         “last-name”:”Howard”
};
MYAPP.flight={
         airline:”Oceanic”,
         number:815,
         departure:{
                   IATA:”SYD”,
                   time:”2004-09-22 14:55”,
                   city:”Sydney”
         },
         arrival:{
                   IATA:”LAX”,
                   time:”2004-09-23 10:42”,
                   city:”Los Angeles”
         }
};
只要把多个全局变量都整理在一个名称空间下,你将显著降低与其他应用程序、组件或类库之间产生糟糕的相互影响的可能性。你的程序也会变得更容易阅读,因为很明显MYAPP.stooge指向的是顶层结构。在下一章中,我们将会看到使用闭包来进行信息隐藏的方式,它是另一个有效减少全局污染的方法。