红宝书第22章高级技巧
Posted mijiujs
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了红宝书第22章高级技巧相关的知识,希望对你有一定的参考价值。
1.高级函数
1.1安全类型检测
typeof在Safari(第4版修复)老版中对正则表达式应用返回function,instanceof操作符存在多个全局作用域(像一个页面包含多个frame)会有问题,因此该两种检测类型都有一定局限
在任何值上调用Object原生的toString()方法,都会返回一个[Object NaticeConstructorName]格式的字符串。
Object.prototype.toString.call(arr) === "[object Array]" Object.prototype.toString.call(fn) == "[object Function]" Object.prototype.toString.call(regexp) == "[object RegExp]"
1.2作用域安全的构造函数
构造函数就是一个使用new操作符调用的函数。当使用new调用时,构造函数内用到的this对象会指向新创建的对象实例
function Person(name, age, job) { this.name = name this.age = age this.job = job } let person = new Person(‘lpr‘, 23, ‘程序员‘)
问题在当没有使用new操作符时来调用改构造函数,由于this是在运行时绑定的,所以this会直接映射到全局对象window上,导致错误对象属性的意外增加
let person = Person(‘lpr‘, 23, ‘程序员‘) console.log(window.name) // ‘lpr‘
解决方法是创建作用域安全的构造函数
function Person(name, age, job) { if (this instanceof Person) { this.name = name this.age = age this.job = job } else { return new Person(name, age, job) } }
该方法下使用构造函数窃取模式的继承且不使用原型链会破坏这个继承
function Polygon(sides) { if (this instanceof Polygon) { this.sides = sides; } else { return new Polygon(sides); } } function Rectangle(width, height) { Polygon.call(this,2); this.width = width; this.height = height; } let rect = new Rectangle(5, 10); console.log(rect.sides); //undefined
可以使用构造函数窃取+原型链或寄生组合结合
function Polygon(sides) { if (this instanceof Polygon) { this.sides = sides; } else { return new Polygon(sides); } } function Rectangle(width, height) { Polygon.call(this,2); this.width = width; this.height = height; } Rectangle.prototype = new Polygon(); let rect = new Rectangle(5, 10); console.log(rect.sides); //2
1.3惰性载入函数
惰性载入表示函数执行的分支只会发生一次
方法1:
函数被调用时再处理函数。在第一次调用的过程中该函数会覆盖为另外一个按合适方式执行的函数,这样任何对原函数的调用都不用再经过执行的分支。
function fn() { if () { fn = function () { // doSomething } } else if () { fn = function () { } } else { fn = function () { } } return fn() }
在这个惰性载入的函数fn()中,if语句的每一个分支都会为变量fn赋值,有效覆盖了原有的函数。最后一步调用新赋的函数。下一次调用fn()的时候就会直接调用被分配的函数。
方法2:
声明函数时就指定适当函数。这样第一次调用函数时就不会损失性能,而在代码首次加载时会损失一点性能。
let fn = (function() { if () { return function () { // doSomething } } else if () { return function () { } } else { return function () { } } })()
该技巧就是创建一个匿名,自执行的函数,用以确定应该使用哪一个函数的实现。实际的逻辑都一样,不一样的地方就是第一行代码用let定义了函数、新增了自执行的匿名函数,另外每个分支都返回正确的函数定义,以便立即将其赋值给fn
1.4函数绑定
函数绑定就是创建一个函数,可以在特定的this环境中以指定参数调用另一个函数。
function bind(fn,context){ return function(){ return fn.apply(context,arguments) } }
ES5为函数定义了原生bind()方法
fn.bind(context)
1.5函数柯里化
函数柯里化用于创建已经设置好一个或多个参数的函数。
2.防篡改对象
一旦被对象防篡改就无法撤销了
2.1不可扩展对象
默认情况下,所有对象都可扩展,即任何时候都可以向对象中添加属性和方法。用以下方法
阻止扩展:Object.preventExtensions(obj)
检测是否可扩展:Object.isExtensible(obj) // true or false
2.2密封对象
密封对象不可扩展,且其已有属性的特性configurable为false,即不能删除其属性和方法,不能使用Object.defineProperty()把数据属性修改为访问器属性或者相反,但能修改值,
密封对象:Object.seal(obj)
检测是否被密封:Object.isSealed(obj) // true or false
2.3冻结对象
密封且不可修改值。congfigurable为false,writable为false。
冻结对象:Object.freeze(obj)
检测是否冻结:Object.isFrozen(obj)
3.高级定时器
js运行在单线程的环境中,定时器并不是线程,仅仅只是计划代码在未来的某个时间执行。
3.1重复的定时器
setInterval()有2个问题:1.某些间隔会被跳过;2:多个定时器的代码执行之间的间隔可能会比预期小。
假设某个事件处理程序设置一个200ms间隔的setInterval,而事件处理程序花了300ms,就会同时出现跳过间隔且连续运行定时器代码的情况。解决方法:
setTimeout(function( // 处理中 setTimeout(arguments.callee,interval) ),interval)
好处:在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且他可以保证在下一次定时器代码执行前,至少要等待指定的间隔,避免了连续的运行。
以上是关于红宝书第22章高级技巧的主要内容,如果未能解决你的问题,请参考以下文章
《JavaScript高级程序设计(第四版)》学习笔记第3章
《JavaScript高级程序设计(第四版)》学习笔记第5章
《JavaScript高级程序设计(第四版)》学习笔记第5章