这里创建了一个person对象,然后将person.click方法分配给DOM按钮的事件处理程序,当你点击按按钮时,会打印出undefiend,原因是执行时this指向了DOM按钮而不是person
解决方案: 将this强行指向person
EventUtil.addHandle(btn, 'click', person.click.bind(person));
函数柯里化
函数柯里化是把接受多个参数的函数转变成接受单一参数的函数
function add(num1, num2){ return num1 + num2; } function curryAdd(num2){ return add(1, num2); } add(2, 3) // 5 curryAdd(2) // 3
这个例子用来方便理解柯里化的概念
下面是创建函数柯里化的通用方式
function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ let innerArgs = Array.prototype.slice.call(arguments); let finalArgs = args.concat(innerArgs); return fn.apply(null, finalArgs); } }
第一个参数是要进行柯里化的函数,其他参数是要传入的值。这里使用Array.prototype.slice.call(arguments, 1)来获取第一个参数后的所有参数(外部)。在返回的函数中,同样调用Array.prototype.slice.call(arguments)让innerArgs来存放所有的参数(内部),然后用concat将内部外部参数组合,用apply传递给函数
function add(num1, num2){ return num1 + num2; } let curryAdd1 = curry(add, 1); curryAdd1(2); // 3 let curryAdd2 = curry(add, 1, 2); curryAdd2(); // 3
防篡改对象
Javascript中任何对象都可以被同一环境中运行的代码修改,所以开发人员有时候需要定义防篡改对象(tamper-proof object) 来保护自己
不可扩展对象
默认情况下所有对象都是可以扩展的(添加属性和方法)
let person = { name: 'addone' }; person.age = 20;
第二行为person对象扩展了age属性,当然你可以阻止这一行为,使用Object.preventExtensions()
let person = { name: 'addone' }; Object.preventExtensions(person); person.age = 20; person.age // undefined
你还可以用Object.isExtensible()来判断对象是不是可扩展的
let person = { name: 'addone' }; Object.isExtensible(person); // true Object.preventExtensions(person); Object.isExtensible(person); // false
请记住这是不可扩展!!,即不能添加属性或方法
密封的对象
密封对象不可扩展,且不能删除属性和方法
let person = { name: 'addone' }; Object.seal(person); person.age = 20; delete person.name; person.age // undefined person.name // addone
相对的也有Object.isSealed()来判断是否密封
let person = { name: 'addone' }; Object.isExtensible(person); // true Object.isSealed(person); // false Object.seal(person); Object.isExtensible(person); // false Object.isSealed(person); // true
冻结的对象
这是最严格的防篡改级别,冻结的对象即不可扩展,又密封,且不能修改
let person = { name: 'addone' }; Object.freeze(person); person.age = 20; delete person.name; person.name = 'addtwo' person.age // undefined person.name // addone
同样也有Object.isFrozen来检测
let person = { name: 'addone' }; Object.isExtensible(person); // true Object.isSealed(person); // false Object.isFrozen(person); // false Object.freeze(person); Object.isExtensible(person); // false Object.isSealed(person); // true Object.isFrozen(person); // true
以上三种方法在严格模式下进行错误操作均会导致抛出错误
高级定时器
阅读前提
大概理解setTimeout的基本执行机制和js事件机制
重复的定时器
当你使用setInterval重复定义多个定时器的时候,可能会出现某个定时器代码在代码再次被添加到执行队列之前还没有完成执行,导致定时器代码连续执行多次。
机智Javascript引擎解决了这个问题,使用setInterval()的时候,仅当没有该定时器的其他代码实例时,才会将定时器代码添加到队列中。但这还会导致一些问题:
某些间隔被跳过
间隔可能比预期的小
为了避免这个两个问题,你可以使用链式setTimeout()调用
setTimeout(function(){ TODO(); setTimeout(arguments.callee, interval); }, interval)
arguments.callee获取了当前执行函数的引用,然后为其设置另外一个定时器,这样就确保在下一次定时器代码执行前,必须等待指定的间隔。
Yielding Processes
浏览器对长时间运行的脚本进行了制约,如果代码运行超过特定的时间或者特定语句数量就不会继续执行。
如果你发现某个循环占用了大量的时间,那么对于下面这两个问题
该处理是否必须同步完成?
数据是否必须按顺序完成?