JavaScript the Definitive Guide (4)
概述
第六版和第五版的最大区别在于ECMAScript 5的引入, 这是目前发布的最新的js版本, 有着最新的属性和函数, 目前主流浏览器基本都已经完全支持. 本文为阅读5-9章内容的笔记总结, 主要是覆盖了JS中的语句和典型对象.
阅读笔记
Chapter 5 - Statements
switch/case
中使用的是===
进行比较判断的, 而不是==
;with
带入scope chain
的对象只有读取权限, 没有写入功能, 即with
后, 可以获取其代入的对象, 但其内声明的变量都依然归于gloabl
或者local
之中;debugger
是ECMAScript 5引入的一个新的statement
, 起主要作用是和浏览器结合使用, 用于创建断点以便查错使用;use strict
也是ECMAScript 5引入的, 严格来说不算statement
而是directive
, 不过两者很是相近; 其使用必须位于js整体的起始位置或者是一个function
主体的起始位置;use strict
的使用会开启代码的strict mode
, 为了提升效率, 错误追踪以及更好的安全性, 其语法要求会更加严格, 简单列举如下:- 停用
with
语句; - 所有变量必须声明才能调用;
- 所有独立声明的函数而非对象的方法定义的, 其
this
域都默认为undefined
, 而函数如果通过apply
,call
调用, 其this
域为传入对象; - 对未声明变量的赋值或者不能写入的对象进行写入, 都会抛出异常;
eval
调用会自动创建临时局部scope
, 不再能直接对母域新建声明了;arguments
成为传入参数的硬拷贝, 和传入参数名之间不在绝对相等, 即改变一方不会引起另一方的改变, 同时停用其caller
,callee
方法;delete
用于变量, 函数或者函数参数的时候会抛出异常, 操作对象的某个未声明属性也会抛出异常;- 对象(包括函数)创建中不能出现同名属性(参数);
- 直接声明的八进制数是不允许的(即0开头的数字);
eval
,arguments
作为keywords
对待, 不能赋值, 或赋予其他变量, 也不能用于identifier
;
- 停用
Chapter 6 - Objects
- Property Attributes (ECMAScript 5之后引入可自定义配置, 之前默认三者皆有.)
writable
: 可赋值;enumerable
: 可递归;configurable
: 可配置 - 可删除也可修改;
- Object Attributes
portotype
: 指向当前对象的属性继承对象;class
: 指代对象所属类别;extensible
: 指示当前对象是否能够新增属性 (ECMAScript 5引入);
- Object Categories and Property Types:
native object
: js中内置的对象, 包含Arrays, functions, dates, regular expressions
等;host object
: 由js运行环境所定义的对象, 比如常见的浏览器, 就包含了HTMLElement
对象;user-defined
: 执行js代码的时候创建的对象;own property
: 直接由对象中定义的属性;inherited property
: 由对象的prototype object
继承来的属性;
Prototype
:- 任何一个对象(除了
Object.protytpe
)的出现都必然包含了第二个对象的存在:new Array() => Array.prototype
; Object.prototype
是唯一一个没有母继承的对象了, 它是最顶部的类;- 类似
new Array() => Array.prototype => Object.prototype
这样的两个prototype
就组成了Array
的prototype chain
; Object.create()
是ECMAScript 5引入的新的创建对象的方法, 其接受两个参数, 第一个参数会作为新建对象的prototype
传入, 第二个则是用来描述新对象的属性的. 如果你传入null
, 则新建对象是完全没有prototype
的, 只有Object.create(Object.prototype)
才是等价于我们常用的{}
ornew Object()
;- 获取某个object的未定义属性将返回
undefined
, 但是获取undefined
或者null
的某个属性则会抛出异常;
- 任何一个对象(除了
getter
&&setter
- ECMAScript 5新引入的两个
accessor properties
, 分别对应某个属性的调用和赋值; - 只有
setter
的属性只有写入权限, 只有getter
的属性则是只读权限;
- ECMAScript 5新引入的两个
property attributes
value, writable, enumerable, and configurable
- 对应的
accessor property
:get, set, enumerable, and configurable
Object.getOwnPropertyDescriptor(object_name, property_name)
获取某个属性的特征描述;Object.defineProperty(object_name, property_name,{property_attribute:attribute_value})
对某个属性设定其特征描述;
下例即为利用Object.defineProperty
自定义的一个extend()
函数:
1 | // Example 6-3. Copying property attributes |
- Object Attributes;
Object.getPrototypeOf()
ECMAScript 5引入, 可用于获取某个对象的prototype;p.isPrototypeOf()
同上, 用于判断某个对象是否为另一个对象的prototype;Object.isExtensible()
,Object.preventExtensions()
则分别是用于判断一个object是否是可扩展的, 以及禁止其可扩展性的(此操作不可复原);Object.seal()
类似Object.preventExtensions()
, 不过它同时禁掉了properties
的configurable
属性,Object.isSealed()
则是对应用于判断是否sealed
的函数;Object.freeze()
比Object.seal()
还要严格,所有属性都变为可读了, 对应的查询函数为:Object.isFrozen()
;Object.preventExtensions()
,Object.seal()
,Object.freeze()
都是只针对当前object而言的;class
属性目前基本没啥用, 有点等价或者说更细化的typeOf
orinstanceOf
了;
Chapter 7 - Arrays
这里主要记录ECMAScript 5引入的一些新的方法, 3已有的可以查看 阅读笔记-2
forEach(value,index,array_itself)
:array
自身的循环调用函数, 相当于for(i in array_name){}
, 区别在于其不支持break
等可以跳出循环的语句, 如果你想要提前结束循环, 就需要通过try/catch
包裹并利用抛出异常来结束循环;map()
: 也算是循环的一种, 遍历每个元素并传递给传入的函数, 最终返回一个新数组;filter()
: 顾名思义, 这是对数组进行筛选的, 值得一提的是filter()
会自动跳过空白,所以对于稀疏数组通过filter()
可以去除所有空白, 在加上undefined
判断, 就可以去除所有空值了;every()
和some()
:every()
是当数组每个元素都使传入函数为真的时候返回真,some()
则是只要一个为真即返回为真, 需要注意的事, 对于空数组,every()
会返回真, 而some()
会返回为假;reduce(function,initial_value)
和reduceRight()
: 通过执行传入函数而对数组元素进行整合,计算,判断, 最终返回一个结果:var max = a.reduce(function(x,y) { return (x>y)?x:y; });
即返回数组的最大值;reduceRight()
与reduce()
一致, 只是循环顺序相反, 从右到左; 当没有声明初始值时, 采用第一个执行元素作为初始值;indexOf()
和lastIndexOf
: 顾名思义, 获取数组中某个元素的index, 前者获取首个匹配元素的index, 后者获取最后一个匹配元素的index;
Chapter 8 - Functions
Functions的调用有四种:
- 直接调用;
- 作为对象的方法调用;
- 作为constructor调用;
- 通过
call
,apply
方法调用(间接调用);
call()
和apply
:call
和apply
都是间接调用的方法, 允许一个函数临时客串为某个object的方法;- 一定程度上, 可以等价于
o.m = f;o.m();delete o.m;
- 其接受的第一个参数会成为函数运行的
this
域, 如果是非strict mode下, 传入null/undefined
则会自动将global作为this
, 而如果传入的是primitive datatype
, 则自动转为对应的wrapper object
, 即string => String
; call
和apply
的区别主要体现在后面的参数上, 前者以分散元素传入, 后者则以整体数组形式传入, 所以用apply
可以把原本只支持不定长参数的函数转换为接受数组的函数:var biggest = Math.max.apply(Math, array_of_numbers);
;apply
对类array元素处理方式同array元素;
bind()
: 很是类似call
和apply
, 本质也是把某个函数作为某个对象的方法调用, 实现则是通过把object和function绑定, 形成一个新函数从而每次调用新函数都等价于调用了object.funtion
,bind
接受多个参数, 其首个以后的参数都会作为this
域成员代入函数中, 并按序成为函数自身的参数function f(y,z) { return this.x + y + z };var g = f.bind({x:1}, 2);g(3) // 2被赋予了y, 新的3则给了z
;higher-order function
: 作用于另一个函数之上的函数;partial and memoization
这两个都是function programing
中常用的方法:partial
: 类似bind()
这种会把传入参数默认分配到函数自身的部分接受参数上的做法就是partial application
;memoization
: 将函数运行过程的计算结果缓存起来的方式;
1 | function array(a, n) { return Array.prototype.slice.call(a, n || 0); } |
1 | // Return a memoized version of f. |
Chapter 9 - Classes and Modules
除了 阅读笔记-2中包含的, 由于ECMAScript 5所引入的那些object property
自然都可以应用到新的class中, 从而创建更为复杂有效的函数. 其实js中目前不存在class这个关键词, 所以其模仿的class, 说白了就是一个复杂一些的函数对象.
而因为其内容驳杂繁多, 我么会在后面的应用中有很多实践的机会, 这里就不一一描述了.