javascript 语言精粹 学习笔记(二)
接着我们来看看,表达式之后的部分。
表达式
基本的表达式,无非是字面量值、变量、内置的值(true、false、null、undefined、NaN、Infinity)、以new开头的调用表达式、delete开头的属性提取表达式、以前置运算符作为前导的表达式、或者由一下形式构成的:
- expression + infix operator + expression
- expression ? expression : expression
- 函数调用
- 函数提取表达式
之后就是表达式结合的重要规则了,优先级由上往下降低:
. [] () 提取属性与调用函数
delete new typeof + - ! 一元运算符
* / % 乘法、除法、求余
+ - 加法/连接、减法
>= <= > < 不等式运算符
=== !== 等式运算符
&& 逻辑与
|| 逻辑或
?: 三元
- typeof运算符产生的值有’number’、’string’、’boolean’、’undefined’、’function’、’object’。null的typeof结果是object。
- +运算符,只在两个运算数都是数字的情况下,才起到加法的作用,不然的话,就是字符串连接的作用。
- /运算符,即使是在两个运算数都是整数的情况下,也可能产生非整数结果。毕竟前面提到了js默认的数字类型是64位的浮点数
字面量
对象字面量里的属性名,可以是标识符或字符串。这些名字被当做字面量名而不是变量名来对待,所以对象的属性名在编译时才能知道。属性的值就是表达式。
函数
这一章对于函数只是略微介绍了一下,详细的内容在之后的章节会细说。
第三章 对象
对于丑陋的事物,爱会闭目无视。
——威廉·莎士比亚《维洛那二绅士》(The Two Gentlemen of Verona)
js的简单数据类型包括数字、字符串、布尔值(true、false)、null值和undefined值。其他所有的值都是对象。
数组、字符串、布尔值看上去很像对象,以为他们都有可用的方法,但他们是不可变的。js中的对象是可变的键控集合。(至于为什么不是对象,还拥有方法,这个可以去翻阅《javascript高级程序设计》中的内置对象那一章,其中讲了几个基本类型是如何变成包装类型调用方法的)。
对象是属性的集合,属性名可以是包括空字符串在内的任何字符串。
js里的对象是无类型(class-free)的。
js包含叫做原型链的特性,允许对象继承另一个对象的属性(这里的继承和传统面向对象的继承是有所区别的,不能照搬概念)。正确使用可以减少对象初始化消耗的时间和内存。
对象字面量
对象字面量就是一对花括号中的零或多个“名/值”对。对象字面量可以出现在任何允许表达式出现的地方。对象是可嵌套的,属性的值也可以是另一个对象字面量。
如果属性名是一个合法的js标识符且不是保留字,所以不强制用引号括住属性名。
检索
- 可以采用[]后缀括住一个字符串表达式,来检索对象里的值。不过,在符合js标识符命名规范下,优先使用 . 表示法,因为更紧凑可读性更好。
- 如果检索不存在的成员属性,返回undefined。
||运算符可以用来填充默认值。
var middle = stooge["middle-name"] || "(none)"; var status = flight.status || "unknown";
尝试从undefined的成员属性中取值将会导致TypeError,这时可以通过&&运算符来避免错误。
flight.equipment //undefined flight.equipment.model //throw "TypeError"
更新
- 对象里的值可以被赋值语句来更新,如果已经存在于对象里,那么就会被替换。
- 如果对象之前没有那个属性,该属性就被扩充到对象里。
引用
对象通过引用来传递,永远不会被复制。
原型
- 每个对象都会链接到一个原型对象上,从中继承属性。
- 所有对象字面量创建的对象都能连接到Object.prototype,这是js的标配对象
当创建新对象时,你可以选择某个对象作为它的原型。Object.create方法,创建一个使用原对象作为其原型的新对象。
if(typeof Object.beget !== 'function') { Object.create = function(o) { var F = function (o) {}; F.prototype = o; return new F(); }; } var another_stooge = Object.create(stooge);
原型连接在更新时是不起作用的。当对某个对象做出改变时,不会触及该对象的原型。
- 委托:当尝试去获取某个对象的属性值时,但该对象没有此属性名时,js会尝试从原型对象中获取属性值。如果那个原型对象都没有,再从它的原型中检索,直到最后到达Object.prototype。如果想要的完全不存在原型链中,结果是undefined。
- 原型关系是一种动态关系,添加新的属性到原型中,该属性会立即对所有基于该原型创建的对象可见。
反射
- typeof操作符对于确定属性的类型很有帮助
请注意原型链中的任何属性都会产生值
typeof flight.toString //'function' typeof flight.constructor //'function'
有两种方法可以处理掉这些不需要的属性。第一个是让你的程序做检查并丢弃这些值为函数的属性。但是,一些值也可能是函数。
- 另一个方法是使用hasOwnProperty方法,这个方法不会检查原型链。
枚举
for in语句用来遍历一个对象中的所有属性名,但是这会包括函数和原型中的属性。过滤掉不想要的属性的常用办法,是hasOwnProperty和typeof。
vaf 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 += 1) { document.writeln(properties[i] + ': ' + another_stooge[properties[i]]); }
删除
- delete运算符只能用来删除对象的属性。如果对象包含该属性,属性会被移除。
- 它不会触及原型链中的任何对象
删除对象的属性可能会让原型链中的同名属性暴露出来。
another_stooge.nickname //'Moe' //删除该对象的nickname属性,从而暴露出原型的nickname属性 delete another_stooge.nickname; another_stooge.nickname //'Curly'
减少全局变量的污染
js可以很灵活的定义全局变量,来容纳所有的资源。遗憾的是,全局变量削弱了程序的灵活性,应该避免使用。
最小化使用全局变量的方法之一:创建唯一的全局变量,作为应用的容器。
eg.下一次是函数部分的笔记