-
运算符优先级
-
优先考虑使用.表示法,因为它更紧凑且可读性更好,但是如果你尝试检索一个不一定存在的值,则需使用['string']写法,它将返回一个
undefined
,若尝试从undefined
的成员属性中取值,则会导致 TypeError 异常,这时可以通过&&
运算符避免错误const obj = { name: 'zhangsan' } obj.name // 'zhangsan' obj['age'] // undefined obj.hubby.name // throw 'TypeError' obj.hubby && obj.hubby.name // undefiend
-
for in
语句可以遍历一个对象中的所有属性,该枚举过程将会列出所有的属性——包括函数和原型中的属性。所以通常可以使用hasOwnProperty
方法过滤。属性名的出现顺序是不确定的,如果你想要确保属性以特定顺序出现,最高的办法就是避免使用for in
语句,而是创建一个数组,在其中以正确的顺序保函属性名。通过 for 而不是 for in,可以得到我们想要的属性,而不用担心可能发觉出原型链中的属性,并且我们按正确顺序取得了它们的值。const obj = {.........} const arr = [ 'name', 'age', 'height', 'weight', 'hubby' ] arr.forEach(k => { console.log(item + ': ' + obj[k]) })
减少全局变量污染
闭包的好处是内部函数可以访问定义他们的外部函数的参数和变量(除了 this 和 arguments),且内部函数拥有比外部函数更长的生命周期。
函数柯里化:1.参数复用;2.提前返回;3延迟计算/运行(bind就是个延迟执行的例子)
-
对象说明符:
// bad const myObj = maker(a, b, c, d, e) // good const myObj = maker({ first: a, middle: b, last: c, state: d, city: e }) // 现在多个参数可以按照任意顺序排列,如果maker函数接受参数使用默认值,那么一些参数也可以忽略调,并且代码也更容易阅读
伪类:当一个函数被创建时,新函数对象会被赋予一个
prototype
属性,他的值是一个包含constructor
属性且属性值为该新函数的对象。prototype
是存放继承特征的地方。当采用构造器调用模式,即用new
前缀调用一个函数时,函数执行方式会被修改。构造器函数存在一个严重的危害,如果你在调用构造器函数时忘记加上new
前缀,那么this将会绑定到全局对象上,造成不但没有扩充新对象,反而破坏了全局变量环境,所以构造器函数约定明明成首字母大写的形式(es6的class解决了这个问题,如果不用new调用,则会报错。es6的class可以看做是一个语法糖,他的绝大部分功能es5都可以做到,但是es6的class写法更加清晰、更像面对对象编程的语法)。原型:一个新的对象可以继承一个旧对象的属性(
Object.creat(parentObj)
)。你可以通过构造一个有用的对象开始,接着构造更多的和那个对象类似的对象。这样可以完全避免把一个应用拆解成一系列嵌套抽象类的分类过程。-
函数化:上面几种继承模式的一个弱点就是没法保护隐私(私有变量、私有函数)。如果对象的所有状态都是私有的,那么该对象就成为一个『防伪(tamper-proof)』对象。该对象的属性可以被替换或删除,但该对象的完整性不会受到损害。
const mammal = function (spec, my = {}) { // my对象是一个为继承链中的构造器提供秘密共享的容器,my对象可以选择性使用 let _this _this = {} // _this = new Object() // _this = Object.creat({}) // name和saying现在就是完全私有的,只能通过下面两个方法去访问它,无法从其他方式访问 _this.getName = function () { return spec.name } _this.say = function () { return spec.saying || '' } return _this } const myMammal = mammal({ name: 'zhangsan' }) // 创建cat继承他,我们的cat只需要关心自身差异 const cat = function (spec = 'meow') { const _this = mammal(spec) _this.xyz = function () { return 'Hello World' } _this.getName = function () { return 'aaaaaa==' + spec.name } return _this } const myCat = cat({name: 'lisi'})
-
正则尾部符号意义: g(global)/i(ignoreCase)/m(multiline)image-20211229142706807
-
用正则表达式字面量创建RegExp对象共享同一个单利:
// 字面量 function test () { return /a/gi } const x = test() const y = test() x.lastIndex = 10 console.log(y.lastIndex) // 10 // new function reg () { return new RegExp(a, 'gi') } const x = reg() const y = reg() x.lastIndex = 8 console.log(y.lastIndex) // 0
-
除了控制字符和特殊字符外,所有的字符都会被按照字面处理,下列字符如果需要按照字面去匹配,那么必须要用一个
\
前缀来进行转义。\ / [ ] ( ) { } ? + * | . ^ $
-
正则表达式分组:
- 捕获型(/([a-z])/):任何匹配这个分组的字符都会被捕获。每个捕获型分组都被指定了一个数字。在正则表达式中第一个捕获(的分组是1,第二个捕获(的分组是2。($1....$x)
- 非捕获型(/(?:a)/):非捕获型分组仅做简单的匹配,并不会捕获所匹配的文本。这会带来微弱的性能优势。非捕获型分组不会干扰捕获型分组的编号。
- 向前正向匹配(/(?=a)/):它类似于非捕获型分组,但在这个组匹配后,文本会倒回到它开始的地方,实际上并不会匹配到任何东西。这不是一个好特性。
- 向前负向匹配(/(?!a)/):它类似于向前正向匹配分组,但只有当它匹配失败时它才回继续向前进行匹配。这不是一个好特性
"abcabc".match(/(a)(b)(c)/) // ["abc", "a", "b", "c"] "abcabc".match(/(?:a)(b)(c)/) // ["abc", "b", "c"] '<div>'.match(/<(?=br>)/) // null '<br>'.match(/<(?=br>)/) // ["<"] '<div>'.match(/<(?!br>)/) // ["<"] '<br>'.match(/<(?!br>)/) // null
regexp.exec()
是正则表达式最强大(也是最慢)的方法。如果它成功匹配regexp
和字符串string
,它会返回一个数组。数组下标0的元素将包含正则表达式regexp匹配的子字符串。下标1的元素是分组1捕获的文本,2的元素是分组2捕获的文本,以此类推。如果匹配失败,它会放回null
。如果regexp带有一个g标识,regexp.lastIndex
会被设置为该匹配后第一个字符的位置,不成功则会重置为0。regexp.test()
是正则表达式最简单(也是最快)的方法。如果它匹配成功则会返回true
,否则返回false
。不要对这个方法使用g标识。统一的代码风格....
-
毒瘤:
- 全局变量
- 自动插入分号
-
糟粕:
- ==,隐式转换:
- 对象和布尔值比较时,会先转换为字符串,在转换为数字
- 对象和字符串比较时,对象转换为字符串,然后两者进行比较
- 对象和数字比较时,对象转化为字符串,然后转换为数字,再和数字进行比较
- 字符串和数字比较时,字符串转换为数字
- 字符串和布尔值进行比较时,二者全部转换成数值再比较
- 布尔值和数字进行比较时,布尔转换为数字
'' == 0 // true [1,2,3] == '1,2,3' // true '0' == false // true [] == false // true true == 1 // true
- with: js提供了with语句,本意是想用它来快捷的访问对象属性,不幸的是,他的结果有时不可预料
- eval: eval传递一个字符串给js编译器,并执行其结果。使用eval会导致代码更加难以阅读,且导致性能显著降低,因为它需要运行编译器。eval函数减弱了程序的安全性,因为他给求值的文本太多权利,而且就像with语句执行方式一样,他降低了语言的性能
- continue: 重构移除continue后,性能会得到改善
- 缺少块的语句:貌似在做一件事,实际确实另一件事的程序是非常难理解清楚的。
if (a) t = 1 fn() // 它看起来像是要这样: if (a) { t = 1 fn() } // 实际上本意是 if (a) { t = 1 } fn()
- 位运算符:在java里,位运算符处理的是整数,ja没有整型,只有双精度浮点数。因此,位操作符把它们的数字运算数先转换成整数,接着执行运算,最后再换回去。再大多数语言中,这些位运算符接近于硬件处理,所以非常快,而js执行环境一般接触不到硬件,所以非常慢。
& and 按位与 | or 按位或 ^ xor 按位异或 ~ not 按位非 >> 带符号右位移 >>> 无符号又位移(用0补足) << 左位移
- ==,隐式转换:
《JavaScript语言精粹》阅读笔记
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
推荐阅读更多精彩内容
- 第1章 精华 javascript是一门杰出的动态编程语言,拥有极强的表达能力。但是它是一门弱类型语言,编译器无法...
- 首发于:segmentfault《JavaScript语言精粹 修订版》 读书笔记 之前看到这篇文章,前端网老姚浅...
- 人比较笨,以前只做项目,案例,然而一些javascript的很多理论不知道该怎么描述,所以最近开启一波读书之旅; ...