JavaScript- The Good Parts Chapter 3 Objects
Upon a homely object Love can wink.
—William Shakespeare, The Two Gentlemen of Verona
The simple types of JavaScript are numbers, strings, booleans (true and false), null,and undefined. All other values are objects. Numbers, strings, and booleans are object-like in that they have methods, but they are immutable. Objects in JavaScript are mutable keyed collections. In JavaScript, arrays are objects, functions are objects,regular expressions are objects, and, of course, objects are objects.
An object is a container of properties, where a property has a name and a value. A property name can be any string, including the empty string. A property value can be any JavaScript value except for undefined.
> var undefined_object = {
... name:undefined
... }
undefined
> undefined_object
{ name: undefined }
> undefined_object.name === undefined
true
Objects in JavaScript are class-free. There is no constraint on the names of new properties or on the values of properties. Objects are useful for collecting and organizing data. Objects can contain other objects, so they can easily represent tree or graph structures.
JavaScript includes a prototype linkage feature that allows one object to inherit the properties of another. When used well, this can reduce object initialization time and memory consumption.
Object Literals
Object literals provide a very convenient notation for creating new object values.An object literal is a pair of curly braces surrounding zero or more name/value pairs. An object literal can appear anywhere an expression can appear:
var empty_object = {};
var stooge = {
"first-name": "Jerome",
"last-name": "Howard"
};
> var empty_object = {};
undefined
> var stooge = {
... "first-name": "Jerome",
... "last-name": "Howard"
... };
undefined
> empty_object
{}
> stooge
{ 'first-name': 'Jerome',
'last-name': 'Howard' }
A property’s name can be any string, including the empty string. The quotes around a property’s name in an object literal are optional if the name would be a legal JavaScript name and not a reserved word. So quotes are required around "first-name", but are optional around first_name. Commas are used to separate the pairs.
A property’s value can be obtained from any expression, including another object literal. Objects can nest:
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"
}
};
Retrieval
Values can be retrieved from an object by wrapping a string expression in a [] suffix. If the string expression is a constant, and if it is a legal JavaScript name and not a reserved word, then the . notation can be used instead. The . notation is preferred because it is more compact and it reads better:
> 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"
..... }
... };
undefined
> stooge["first-name"] // "Joe"
'Jerome'
> flight.departure.IATA // "SYD"
'SYD'
The undefined value is produced if an attempt is made to retrieve a nonexistent member:
> stooge["middle-name"] // undefined
undefined
> flight.status // undefined
undefined
> stooge["FIRST-NAME"] // undefined
undefined
>
The || operator can be used to fill in default values:
var middle = stooge["middle-name"] || "(none)";
var status = flight.status || "unknown";
Attempting to retrieve values from undefined will throw a TypeError exception. This can be guarded against with the && operator:
flight.equipment // undefined
flight.equipment.model // throw "TypeError"
flight.equipment && flight.equipment.model // undefined
> flight.equipment // undefined
undefined
> flight.equipment.model // throw "TypeError"
TypeError: Cannot read property 'model' of undefined
at repl:1:18
at REPLServer.self.eval (repl.js:110:21)
at Interface.<anonymous> (repl.js:239:12)
at Interface.emit (events.js:95:17)
at Interface._onLine (readline.js:202:10)
at Interface._line (readline.js:531:8)
at Interface._ttyWrite (readline.js:760:14)
at ReadStream.onkeypress (readline.js:99:10)
at ReadStream.emit (events.js:98:17)
at emitKey (readline.js:1095:12)
> flight.equipment && flight.equipment.model // undefined
undefined
Update
A value in an object can be updated by assignment. If the property name already exists in the object, the property value is replaced:
stooge['first-name'] = 'Jerome';
If the object does not already have that property name, the object is augmented:
stooge['middle-name'] = 'Lester';
stooge.nickname = 'Curly';
flight.equipment = {
model: 'Boeing 777'
};
flight.status = 'overdue';
Reference
Objects are passed around by reference. They are never copied:
var x = stooge;
x.nickname = 'Curly';
var nick = stooge.nickname;
// nick is 'Curly' because x and stooge
// are references to the same object
var a = {}, b = {}, c = {};
// a, b, and c each refer to a
// different empty object
a = b = c = {};
// a, b, and c all refer to
// the same empty object
Prototype
Every object is linked to a prototype object from which it can inherit properties. All objects created from object literals are linked to Object.prototype, an object that comes standard with JavaScript.
When you make a new object, you can select the object that should be its prototype.The mechanism that JavaScript provides to do this is messy and complex, but it can be significantly simplified. We will add a create method to the Object function. The create method creates a new object that uses an old object as its prototype. There will be much more about functions in the next chapter.
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
var another_stooge = Object.create(stooge); > if (typeof Object.create !== 'function') {
... Object.create = function (o) {
..... var F = function () {};
..... F.prototype = o;
..... return new F();
..... };
... }
undefined
> var another_stooge = Object.create(stooge);
undefined
> another_stooge
{}
> stooge
{ 'first-name': 'Jerome',
'last-name': 'Howard' }
> stooge['last-name']
'Howard'
> stooge['first-name']
'Jerome'
The prototype link has no effect on updating. When we make changes to an object,the object’s prototype is not touched:
another_stooge['first-name'] = 'Harry';
another_stooge['middle-name'] = 'Moses';
another_stooge.nickname = 'Moe';
The prototype link is used only in retrieval. If we try to retrieve a property value from an object, and if the object lacks the property name, then JavaScript attempts to retrieve the property value from the prototype object. And if that object is lacking the property, then it goes to its prototype, and so on until the process finally bottoms out with Object.prototype. If the desired property exists nowhere in the prototype chain,then the result is the undefined value. This is called delegation.
The prototype relationship is a dynamic relationship. If we add a new property to a prototype, that property will immediately be visible in all of the objects that are based on that prototype:
stooge.profession = 'actor';
another_stooge.profession // 'actor'
We will see more about the prototype chain in Chapter 6.
Reflection
It is easy to inspect an object to determine what properties it has by attempting to retrieve the properties and examining the values obtained. The typeof operator can be very helpful in determining the type of a property:
typeof flight.number // 'number'
typeof flight.status // 'string'
typeof flight.arrival // 'object'
typeof flight.manifest // 'undefined'
Some care must be taken because any property on the prototype chain can produce a value:
typeof flight.toString // 'function'
typeof flight.constructor // 'function'
There are two approaches to dealing with these undesired properties. The first is to have your program look for and reject function values. Generally, when you are reflecting, you are interested in data, and so you should be aware that some values could be functions.
The other approach is to use the hasOwnProperty method, which returns true if the object has a particular property. The hasOwnProperty method does not look at the prototype chain:
flight.hasOwnProperty('number') // true
flight.hasOwnProperty('constructor') // false
Enumeration
The for in statement can loop over all of the property names in an object. The enumeration will include all of the properties—including functions and prototype properties that you might not be interested in—so it is necessary to filter out the values you don’t want. The most common filters are the hasOwnProperty method and using typeof to exclude functions:
var name;
for (name in another_stooge) {
if (typeof another_stooge[name] !== 'function') {
console.log(name + ': ' + another_stooge[name]);
}
}
There is no guarantee on the order of the names, so be prepared for the names to appear in any order. If you want to assure that the properties appear in a particular order, it is best to avoid the for in statement entirely and instead make an array containing the names of the properties in the correct order:
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]]);
}
By using for instead of for in, we were able to get the properties we wanted without worrying about what might be dredged up from the prototype chain, and we got them in the correct order.
Delete
The delete operator can be used to remove a property from an object. It will remove a property from the object if it has one. It will not touch any of the objects in the prototype linkage.
Removing a property from an object may allow a property from the prototype linkage to shine through:
another_stooge.nickname // 'Moe'
// Remove nickname from another_stooge, revealing
// the nickname of the prototype.
delete another_stooge.nickname;
another_stooge.nickname // 'Curly'
Global Abatement
JavaScript makes it easy to define global variables that can hold all of the assets of your application. Unfortunately, global variables weaken the resiliency of programs and should be avoided.
One way to minimize the use of global variables is to create a single global variable for your application:
var MYAPP = {};
That variable then becomes the container for your application:
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"
}
};
By reducing your global footprint to a single name, you significantly reduce the chance of bad interactions with other applications, widgets, or libraries. Your program also becomes easier to read because it is obvious that MYAPP.stooge refers to a top-level structure. In the next chapter, we will see ways to use closure for information hiding, which is another effective global abatement technique.
JavaScript- The Good Parts Chapter 3 Objects的更多相关文章
- JavaScript: The Good Parts
Chapter 1 Good Parts: JavaScript is an important language because it is the language of the web brow ...
- JavaScript: The Evil Parts - 1
最近在看JavaScript框架设计,在讲解类型判定的时候提到了一些“匪夷所思的情况”,不过没有明说都是什么时候会出现这些情况.自己玩儿了一下,写写随笔吧.不过可能除了我找到的,还有会其他时候会出现这 ...
- JavaScript- The Good Parts CHAPTER 2
I know it well:I read it in the grammar long ago.—William Shakespeare, The Tragedy(悲剧:灾难:惨案) of Titu ...
- JavaScript- The Good Parts Chapter 5 Inheritance
Divides one thing entire to many objects;Like perspectives, which rightly gazed uponShow nothing but ...
- JavaScript- The Good Parts Chapter 4
Why, every fault’s condemn’d ere it be done:Mine were the very cipher of a function. . .—William Sha ...
- JavaScript- The Good Parts Chapter 6
Thee(你) I’ll chase(追逐:追捕) hence(因此:今后), thou(你:尔,汝) wolf in sheep’s array.—William Shakespeare, The ...
- 读 《JavaScript: The Good Parts》 有感
提炼出一门语言或技术的 Good Parts, 使用该子集去构造健壮稳固的应用. 我们总是倾向于去学习和使用所有的语言特性,好像凡是新的,凡是提供了的, 就有必要去使用: 这本书告诉我们, 要有选择性 ...
- Chapter 17. Objects and Inheritance(对象与继承)
javascript面向对象编程有几个层面: 1: 单一对象 (covered in Layer 1: Single Objects) 2: 对象之间的 prototype (described i ...
- 《JavaScript高级程序设计》chapter 1: javascript 简介
1.2.2 文档对象模型 DHTML的出现让开发人员无需重新加载页面就可以修改其外观了. 1.2.3 浏览器对象模型(BOM) BOM真正与众不同的地方在于他作为javascript实 ...
随机推荐
- WindowsPhone客户端第一次审核失败记录
微软返回失败pdf,其中2.7.2和2.7.3没有通过,原因是: 1. 没有提供隐私策略,所以在提交App要填写的隐私策略url里加了隐私策略的网址链接. 2. 由于使用了定位服务,所以第一次进入应用 ...
- 基于strpos()函数的判断用户浏览器方法
$_SERVER['HTTP_USER_AGENT'],超全局变量,用来读取客户用的什么浏览器及其版本. strpos(),指定一个字符并搜索是否包含该字符. <html> <hea ...
- 关于table的一些兼容性问题
不多说,先来看两个常用的简单效果 ---- 兼容拼比一(普通边线效果) 图一:谷歌.火狐.ie8+下 图二:ie6/7下 从图中看出,ie6/7其实是不认识tr边框线的,,所以平时做项目时候,我们一般 ...
- ffmpeg编译 --enable :没有命令
参照官方推荐的编译:http://www.roman10.net/how-to-build-ffmpeg-with-ndk-r9/ build_config.sh总是不过, 问题原因:./config ...
- linux下监控jvm 使用的方法
之前一直用jconsole监控jvm,图形界面简单易用,最近因为需要在纯linux下进行操作,所以总结了一下 linux下监控jvm的例子,这次主要用到了jstat工具, 各个参数意义: jstat ...
- C++和java的区别
Java区别于C++ 表面看来两者最大的不同在于Java没有指针,或者说,Java满地都是指针.对于编程者而言Java的这种设计是安全且更易用的.说Java满地是指针的原因在于它把指针的功能隐藏了,其 ...
- OpenCV学习笔记:如何扫描图像、利用查找表和计时
目的 我们将探索以下问题的答案: 如何遍历图像中的每一个像素? OpenCV的矩阵值是如何存储的? 如何测试我们所实现算法的性能? 查找表是什么?为什么要用它? 测试用例 这里我们测试的,是一种简单的 ...
- Android开发之通过Intent启动其他App的Service
在Android5.0以前可以通过隐式Intent方式启动其他App的Service,就跟Activity启动隐式Intent一样的. 但是在5.0以后,只能使用显示的Intent方式启动了. 启动其 ...
- poj1177Picture(线段树-周长并)
链接 神奇的扫描线啊 估计之前刷面积并的时候太急了 没来得及理解 .. 有一大段代码是与面积并一模一样的 都是离散化 更新 面积并是扫描的x 这次也一样 因为周长只算外围的 所以扫描到一条x边时 要 ...
- BZOJ_1084_[SCOI2005]_最大子矩阵_(动态规划)
描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1084 给出一个n*m的矩阵,其中m<=2,取k个子矩阵,求最大子矩阵和. 分析 1.m= ...