第4章 表达式和运算符
4.4 属性访问表达式
JS为属性访问定义了两种语法:
expression . identifier
expression [ expression ]
var o = {x: 1, y: {2: 3}};
var a = [o, 4, [5, 6]];
o.x //1
o['x'] //1,引号不能省略
a[1] //4,也作a['1']
4.8.2 一元算术运算符
递增(++)
需要注意的是,表达式 ++x 并不总和 x = x + 1 完全一样,“++” 运算符从不进行字符串连接操作,它总是会将操作数转换为数字并增1,如果x是字符串’1‘,++x的结果就是数字2。
4.9.2 比较运算符
'1' + 2 //12
'11' < '3' //true
'11' < 3 //false,数字的比较
'one' < 3 //false,'one'转换为NaN
4.9.3 in 运算符
var data = ['a', 'b', 'c'];
'0' in data; //true
1 in data; //true
3 in data; //false
4.10.1 逻辑与(&&)
&& 并不总是返回 true 和 false,还有下面的特别用法:
如果 && 的左操作数为假值,则无需计算右操作数,直接返回左操作数的值。
如果 && 的左操作数为真值,刚整个表达式的结果依赖于右操作数的值。当左操作数是真值时,&& 运算符将计算右操作数的值并将其返回作为整个表达式的计算结果。
var o = {x: 1};
var p = null;
o && o.x; // 1
o && o.y; // undefined
p && p.x; // null
&& 的行为有时称做“短路”:
// 下面这两行是一个意思
if (a === b) stop();
(a === b) && stop();
当 && 右侧的表达式具有副作用的时候(赋值、递增、递减和函数调用表达式)要格外小心。因为这些带有副作用的表达式的执行依赖于左操作数的计算结果。
4.10.2 逻辑或(||)
|| 运算符与 && 一样,也有一些复杂的用法:
它会首先计算左操作数的值,如果计算结果为真值,那么返回这个真值,否则,再计算第二个操作数的值,即计算右侧的表达式,并返回这个表达式的计算结果。
第5章 语句
5.5.3 for
function tail(o) { //返回链表的最后一个节点对象
for (; o.next; o = o.next) //根据判断o.next是不是真值来执行遍历
return o;
}
5.6.6 try / catch / finally 语句
try {
// 要求用户输入一个数字
var n = Number(prompt('请输入一个正整数', ''));
// 假设输入是合法的,计算这个数的阶乘
var f = factorial(n);
// 显示结果
alert(n + '! = ' + f);
}
catch (ex) {
// 如果输入不合法,将执行这里的逻辑
alert(ex); // 告诉用户产生了什么错误
}
第6章 对象
6.1 创建对象
6.1.1 对象直接量
var point = { x: 1, y: 2 };
6.1.2 通过 new 创建对象
6.1.3 原型
6.1.4 Object.create()
var o1 = Object.create({x: 1, y: 2}); //o1继承了属性x和y
var o2 = Object.create(null); //o2不继承任何属性和方法
var o3 = Object.create(Object.prototype); //o3和{}和new Object()一样
6.2 属性的查询和设置
对于点来说,右侧必须是一个以属性名称命名的简单标识符。对于方括号来说,内必须是一个计算结果为字符串的表达式,这个字符串就是属性的名字:
var x = {a: 1, b: 2, c: 3};
x.a; // 1
x['b'] // 2
x[c] // 无效
6.2.2 继承
function inherit(p) {
if (p === null) {
throw TypeError();
}
if (Object.create) {
return Object.create(p);
}
var t = typeof p;
if (t !== 'object' && t !== 'function') {
throw TypeError();
}
var f = function(){};
f.prototype = p;
return new f();
}
var o = {};
o.x = 1;
var p = inherit(o);
p.y = 2;
var q = inherit(p);
q.z = 3;
6.3 删除属性
delete 可以删除对象的属性,只是断开属性的宿主对象的联系,而不会操作属性中的属性。
delete 只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象)。
当 delete 表达式删除成功或没有任何副作用(比如删除不存在的属性)时,它返回 true。如果 delete后不是一个属性访问表达式,delete 同样返回 true。
delete 不能删除那些可配置为 false 的属性(尽管可以删除不可扩展对象的可配置属性)。某些内置对象的属性是不可配置的,比如通过变量声明和函数声明创建的全局对象的属性。
delete Object.prototype; // 不能删除,属性是不可配置的
var x = 1; // 声明一个全局变量
delete this.x; // 不能删除这个属性
function f() {} // 声明一个全局函数
delete this.f; // 也不能删除全局函数
6.4 检测属性
var o = {x: 1};
'x' in o;
'toString' in o;
对象的hasOwnProperty() 方法用来检测给定的名字是否是对象的自有属性,对于继承属性它将返回false。
propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性的可枚举性为true时它才返回true。某些内置属性是不可枚举的
var o = inherit({y: 2});
o.x = 1;
o.propertyIsEnumerable('x'); //true
o.propertyIsEnumerable('y'); //false,y是继承来的
Object.prototype.propertyIsEnumerable('toString'); // false,不可枚举
6.8 对象的三个属性
每一个对象都有与之相关的原型(prototype)、类(class)和可扩展性(extensible attribute)。
6.8.1 原型属性
var p = {x: 1};
var o = Object.create(p);
p.isPrototypeOf(o); // true
Object.prototype.isPrototypeOf(o); // true