JavaScript语言精粹
一、语法
- 运算符优先级
. [] () | 提取属性与调用函数 |
delete new typeof + - | 一元运算符 |
* / % | 乘法、除法、求余 |
+ - | 加法/连结、减 |
>= <= > < | 不等式运算符 |
=== !== | 等式运算符 |
&& | 逻辑与 |
?: | 三元 |
注:在js中,“%”不是通常数学意义上的模运算,而实际上是“求余”运算。两个运算数都为正数时,求模运算和求余运算的值相同;两个运算数存在负数时,求模运算和求余运算的值则不相同。
二、对象
- js包含一种原型链的特性,允许对象继承另一个对象的属性。正确地使用它能减少初始化时消耗的时间和内存。
- 如果属性名是一个合法的js标识符且不是保留字,则不强制要求用引号括住属性名。
- 反射 -— 检查对象有什么属性
只用typeof是不够的,原型链中的任何属性都会返回值,如:
typeof flight.toString //fuuction
typeof flight.constructor //function
有两种方法可以去处理这些不需要的属性:
- 让程序检查并丢弃为函数的属性;
使用hasOwnProperty(不会检查原型链)方法;
- 减少全局变量的污染。全局变量削弱了程序的灵活性,应该避免使用。
三、函数
所谓编程,就是将一组需求分解成一组函数与数据结构的技能。
每个函数在创建时会附加连个隐藏属性:函数的上下文和实现函数行为的代码; 函数在调用时,除了有声明是的形式参数,每个函数还接收连个附加的参数:this
和 arguments
arguments 不是一个真正的数组,可以使用一下方法来转化为真正数组:
Array.prototype.slice.apply(arguments);
Array.prototype.concat(thisArg, arguments);
- 函数的4种调用模式:
- 方法调用模式;
- 函数调用模式;
- 构造器调用模式 (new);
apply调用模式;
- 扩充类型的功能
举例:
function.prototype.method = function(name, func){
this.prototype[name] = func;
return this;
}
通过给function.prototype
增加一个method
方法,我们下次给对象增加方法的时候就不必键入prototype
这几个字符。省去一些麻烦。
- 函数中声明变量
最后的做法是在函数体的顶部声明函数中可能用到的所有变量。
- 模块
可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象。
模块模式的一般形式 是:一个定义了私有变量和函数的函数; 利用闭包创建可以访问私有变量和函数的特权函数; 最后返回这个特权函数,或者把他们保存到一个可访问的地方。模块模式经常结合单例模式(Singleton Pattern)使用。
- 级联
- 柯里化
把函数与传递给它的参数相结合, 产生出一个新的函数。
- 记忆(加速程序计算的一种优化技术,如用闭包存储结果)
四、继承
在那些基于类的语言中,继承(inheritance或extends)提供了两个有用的服务。
- 它是代码重用的一种形式。
- 引入了一套类型系统的规范。
实现 new 一个对象的内部实现机制
Function.method(‘new’, function () {
// 创建一个新对象,它继承自构造器函数的原型对象
var that = Object.create(this.prototype);
// 调用构造器函数, 绑定 -this- 到新对象上
var other = this.apply(that, arguments);
// 如果它的返回值不是一个对象, 就返回该新对象
return (typeof other === 'object' && other) || that
})
对象说明符
var myObject = maker(f, l, m, c, c);
==>
var myObject = maker({
first: f,
middle: m,
last: l,
state: s,
city: c
})
- 利用原型进行差异化继承
通过定制一个新的对象,我们指明它与所基于的基本对象的区别。
- 函数化 —- 应用模块模式
一个函数化构造器的伪代码模块:
var constructor = function (spec, my) {
var that, 其他的私有变量
my = my || {};
把共享的变量和函数添加到my中
that = 一个新对象
添加给that的特权方法
return that;
}
五、 数组
- JS允许数组包含任意混合类型的值
- JS数组的length是没有上界的, 把length设小将导致所有下标大于等于新length的属性被删除
- 使用splice来删除,尽量少用delete
- 当属性名是小而连续的整数时,你应该使用数组;否则使用对象
判断一个对象是否为数组
typeof [] //onject
var is_array = function (value) {return Object.prototype.toString.apply(value) === '[object Array]';
}
- 方法的扩充
- 指定初始值
六、 正则表达式(略)
七、 方法
数组方法
- concat
- join(比用“+”好拼接这些片段要快)
- pop
- push
- reverse
- shift
- slice(start, end)
- sort
- splice(start, deleteCount, item…)
- unshift
函数方法
- apply(thisArg, argArray)
- toExponential(fractionDigits)
- toFixed(fractionDigits)
- toPrecision(precision)
- toString(radix)
对象方法
- hasOwnProperty(name)
RegExp
- exec(string)(正则表达式的最强大和最慢的方法)
- test(string)返回true/false
字符串方法
- charAt(pos)
- charCodeAt(pos)
- concat(string…)
- indexOf(searchString, pos)
- lastIndexOf(searchString, pos)
- localeCompare(that)
- match(regexp)
- replace(searchValue, replaceValue)
- search(regexp)与indexOf方法类似
- slice(start, end)
- split(separator, limit)
- subString(不能处理负数,请用slice代替他)
- toLocalLowerCase()/toLocalUpperCase()
- toLowerCase()/toUpperCase()
- fromCharCode(char…)
八、 代码风格
有时候觉得注释就像一个时间机器,我用它发送重要的信息给未来的我。
- 对一个脚本应用或工具库,我只用唯一一个全局变量。
- 每个对象都有它自己的命名空间,所以我很容易使用对象去管理代码。
- 使用闭包能提供进一步的信息隐藏,增强我的模块的健壮性。
九、 优美的特性
精简的JS —- 主要内容:
- 函数是顶级对象
在精简JS中,函数是有词法作用域的闭包
- 基于原型继承的动态对象
对象是无类别的。我们可以通过普通的赋值给任何对象增加一个新成员的属性。一个对象可以从另一个对象继承成员属性。
- 对象字面量和数组字面量
这对创建新的对象和数组来说是一种非常方便的表示法。JS字面量是数据交换格式JSON的灵感
十、 毒瘤
- 在JS所有的糟糕特性之中,最为糟糕的一个就是它对全局变量的依赖。
- typeof
- parseInt
NaN (typeof NaN === ‘number’ //true;) 判断一个值是否可用做数字的最佳方法是使用isFinite函数,应为它会筛除NaN和Infinity,但isFinite会试图把它的运算数转换为一个数字。自定义方法:
var isNumber = function isNumber(value){
return typeof value === 'number' && isFinite(value);
}
- 对象
JS的对象永远不会是真的空对象,因为它们可以从原型链中取得成员属性。
写在后面
本书在豆瓣评分很高,但整本书看下来,说实话,到没感觉有特别多的感悟,可能自己学艺不精,还接受不到的大师的深层次的教导。
但收获还是有的:
- 代码习惯的纠正;
- 基础知识的强化理解,如原型链,闭包等;
- 某些一般性bug来源;如typeof, NaN等
- 实现同一功能的最优解,需考虑全面。
还没有评论,来说两句吧...