一、语法
- 运算符优先级
. [] () | 提取属性与调用函数 |
delete new typeof + - | 一元运算符 |
* / % | 乘法、除法、求余 |
+ - | 加法/连结、减 |
>= <= > < | 不等式运算符 |
=== !== | 等式运算符 |
&& | 逻辑与 |
?: | 三元 |
注:在js中,“%”不是通常数学意义上的模运算,而实际上是“求余”运算。两个运算数都为正数时,求模运算和求余运算的值相同;两个运算数存在负数时,求模运算和求余运算的值则不相同。
二、对象
-
js包含一种原型链的特性,允许对象继承另一个对象的属性。正确地使用它能减少初始化时消耗的时间和内存。
-
如果属性名是一个合法的js标识符且不是保留字,则不强制要求用引号括住属性名。
-
反射 --- 检查对象有什么属性
只用typeof是不够的,原型链中的任何属性都会返回值,如:
typeof flight.toString //fuuctiontypeof 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 [] //onjectvar 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等
- 实现同一功能的最优解,需考虑全面。