【JavaScript语言精粹】读书笔记(二)——对象

来源:互联网 发布:seafile数据是否加密 编辑:程序博客网 时间:2024/06/05 10:12

对于丑陋的事物,爱会闭目无视。 ——威廉·莎士比亚,《维洛那二绅士(The Two Gentlemen of Verona)》


JavaScript的简单类型包含数字、字符串。布尔值、null值和undefined值其他所有的值都是对象

数字、字符串和布尔值“貌似”对象,因为它们拥有方法,但它们是不可变的。

JavaScript中的对象是可变的键控集合(keyed collections)。

在JavaScript中,数组是对象,函数是对象,正则表达式是对象,当然,对象也是对象。


对象是属性的容器,其中每个属性都拥有名字和值。

属性的名字可以是包括空字符串在内的任意字符串。

属性值可以是除undefined值之外的任何值。


JavaScript中的对象是无类别(class-free)的。它对新属性的名字和值没有约束。

对象适合用于收集和管理数据。

对象可以包含其他对象,所以它们可以容易地表示成树形或图形结构。


JavaScript包括一个原型链特性,允许对象继承另一个对象的属性。正确地使用它能够减少对象初始化的时间和内存消耗


1. 对象字面量

对象字面量提供了一种非常方便地创建新对象值得表示法。一个对象字面量就是包围在一对花括号中的零或多个“名/值”对。

对象字面量可以出现在任何允许表达式出现的地方。

var empty object = {};var stooge = {"first-name": "Jerome","last-name": "Howard"};

注:如果属性名是一个合法的JavaScript标识符且不是保留字,并不强制要求用引号括住属性名,所以yoga引号括住“first-name”是必须的,但是否括住“first_name”则是可选的。逗号用来分隔多个“名/值”对。

属性的值可以从包括另一个对象字面量在内的任意表达式中获取。对象是可以嵌套的:

var stooge = {"first-name": "Jerome","last-name": "Howard","email": {"type": "work","value": "abc@qq.com"}};

2. 检索

要检索对象中包含的值,可以采用在[]后缀中括住一个字符串表达式的方式。如果字符串表达式是一个常数,而且它是一个合法的JavaScript标识符而并非保留字,那么也可以用 .表示法代替。优先考虑使用 .表示法,因为它更紧凑且可读性更好。

stooge["first-name"] // Jeromestooge.email.value   // abc@qq.com

如果尝试检索一个不存在的成员元素的值,则返回undefined值。

||运算符可以用来填充默认值:

var middle = stooge["middle-name"] || "none";var phone = stooge.phone || "unknown";
尝试检索一个undefined值将会导致TypeError异常。这可以通过&&运算符来避免错误。

stooge.address                        // undefinedstooge.address.city                   // throw"TypeError"stooge.address && stooge.address.city // undefined

3. 更新

对象中的值可以通过赋值语句来更新。如果属性名已经存在于对象中,那么这个属性的值被替换。

如果对象之前并没有这个属性,那么该属性就被扩充到该对象中。

var operation = {add: "addMethod",update: "updateMethod"}operation.update = "editMethod"; // 更新operation.del = "deleteMethod";  // 扩充

4. 引用

对象通过引用来传递。他们永远不会被拷贝:

var x = stooge;x.nickname = "llc";var nick = stooge.nickname; // 因为x和stooge是指向用一个对象的引用,所以nick为‘llc’var a = {}, b = {}, c = {}; // a、b和c各自引用不同的空对象a = b = c = {};             // a、b和c引用同一个空对象

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";

原型连接只有在检索值得时候才会被用到。如果我们尝试去获取对象的某个属性值,且该对象没有属性名,那么JavaScript会试着从原型对象中获取属性值。如果那个原型对象也没有该属性,那么再从它的原型中寻找,以此类推,直到该过程最后到达终点Object.prototype,如果想要的属性完全不存在于原型链中,那么结果就是undefined值。这个过程称为委托

原型关系是一种动态的关系。如果我们添加一个新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见。

stooge.profession = "actor";another_stooge.profession // actor

6. 反射

检查对象并确定对象有什么属性很容易,只要试着去检索该属性并验证取得的值。typeof操作符对确定属性的类型很有帮助:

var flight = {airline: "Oceanic",number: 815,departure: {IATA: "SYD",time: "2017-08-11 14:29",city: "Sydney"},arrival: {IATA: "LAX",time: "2017-08-12 10:07",city: "Los Angeles"}}typeof flight.number // 'number'typeof flight.airline // 'string'typeof flight.arrival // 'object'typeof flight.manifest // 'undefined'

注:原型链中的任何属性也会产生一个值:

typeof flight.toString // 'function'typeof flight.constructor // 'function'

有两个方法去处理这些不需要的属性。

第一个是让你的程序检查并提出函数。一般来说,做反射的目标是数据,因此你应该意识到一些值可能会是函数。

另一个方式是使用hasOwnProperty方法,如果对象拥有独有的属性,他将返回true。hasOwnProperty方法不会检查原型链。

flight.hasOwnProperty('number') // trueflight.hasOwnProperty('constructor') // false

7. 枚举

for in 语句可用来遍历一个对象中的所有属性名。该枚举过程建辉列出所有的属性——包括函数和你可能不关心的原型中的属性——所以又必要过滤掉那些你不想要的值。最为常见的过滤器是hasOwnProperty方法,以及使用typeof来排除函数:

var name;for (name in another_stooge) {if (typeof another_stooge[name] !== 'function') {document.writeln(name + ': ' + another_stooge[name]);}}

属性名出现的顺序是不确定的,因此要对任何可能出现的顺序有所准备。如果你想要确保属性以特定的顺序出现,最好的办法就是完全避免使用for in 语句,而是创建一个数组,在其中以正确的顺序包含属性名:

var i;var properties = [                  'first-name',                  'middle-name',                  'last-name',                  'profession'                  ];for (i = 0; i < properties.length; i++) {document.writeln(properties[i] + ': ' + another_stooge[properties[i]]);}

通过使用for 而不是for in,可以得到我们想要的属性,而不用担心可能发掘出原型链中的属性,并且我们按正确的顺序取得了它们的值。

8. 删除

delete运算符可以用来删除对象的属性。它将会移除对象中确定包含的属性。它不会触及原型链中的任何对象。

删除对象的属性可能会让来自原型链中的属性浮现出来:

another_stooge.nickname // 'Moe' // 删除another_stooge的nickname属性,从而暴露出原型的nickname属性delete another_stooge.nickname;another_stooge.nickname // 'llc'

9. 减少全局变量污染

JavaScript可以很随意地定义那些可保存所有应用资源的全局变量,不幸的是,全局变量削弱了程序的灵活性,所以应该避免。

最小化使用全局变量的一个方法是在你的应用中只创建唯一一个全局变量,该变量此时变成了你的应用的容器:

var MYAPP = {};MYAPP.stooge = {"first-name": "Jerome","last-name": "Howard"};MYAPP.flight = {airline: "Oceanic",number: 815,departure: {IATA: "SYD",time: "2017-08-11 14:29",city: "Sydney"},arrival: {IATA: "LAX",time: "2017-08-12 10:07",city: "Los Angeles"}}

只要把多个全局变量都整理在一个名称空间下,你将显著降低与其他应用程序、组件或类库之间产生糟糕的相互影响的可能性。你的程序也会变得容易阅读,因为很明显MYAPP.stooge指向的是顶层结构。之后详解:使用闭包来进行信息隐藏的方式,它是另一个有效减少全局污染的方法。



原创粉丝点击