内容来自:《JavaScript高级程序设计》、MDN
1、防止篡改对象
限制对象扩展:Object.preventExtensions(obj);
Object.preventExtensions()方法让一个对象变的不可扩展,也就是永远不能再添加新的属性。
var person = {age:1};
Object.preventExtensions(person);
person.name = 'mike';
console.log(person.name);//undefined
console.log(Object.isExtensible(person));//false
使用Object.istExtensible()方法还可以确定对象是否可以扩展。
密封对象:Object.seal(obj);
Object.seal() 方法可以让一个对象密封,并返回被密封后的对象。密封对象将会阻止向对象添加新的属性,并且会将所有已有属性的可配置性(configurable)置为不可配置(false),即不可修改属性的描述或删除属性。但是可写性描述(writable)为可写(true)的属性的值仍然可以被修改。
使用Object.isSealed()方法可以确定对象是否被密封了。因为被密封的对象不可扩展,所以用Object.isExtensible()检测密封的对象也会返回false。
var person = {age:1};
Object.seal(person);
person.name = 'mike';
console.log(person.name);//undefined
console.log(Object.isExtensible(person));//false
console.log(Object.isSealed(person));//true
冻结对象:Object.seal(obj);
Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。冻结的对象既不可扩展,又是密封的。
Object.isFrozen()方法用于检测冻结对象。因为冻结对象既是密封的又是不可扩展的,所以用Object.isExtensible()和Object.isSealed()检测冻结对象将分别返回false和true。
var person = {age:1};
Object. freeze(person);
person.age = 2;
console.log(person.age);//undefined
console.log(Object.isExtensible(person));//false
console.log(Object.isSealed(person));//true
console.log(Object. isFrozen(person));//true
2、定时器
重复定时器
下面代码中是链式调用setTimeout(),每次函数执行的时候都会创建一个新的定时器。第二个setTimeout()调用使用了arguments.callee来获取对当前执行的函数的引用,并为其设置另外一个定时器。这样做的好处是,在前一个定时器代码执行完之前,不会向队列插入新的定时器代码,确保不会有任何缺失的间隔。而且,它可以保证在下一次定时器代码执行之前,至少要等待指定的间隔,避免了连续的运行。这个模式主要用于重复定时器,如下例所示。
注:arguments.callee 属性包含当前正在执行的函数。callee 是 arguments 对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。
setTimeout(function(){
//处理代码
setTimeout(arguments.callee, timer);
},timer)
使用重复定时器代替循环
起因:现代浏览器为JavaScript运行都被分配了一个确定数量的资源,这样做的目的是:防止恶意的代码把用户的计算机搞挂了。其中一个限制是长时间运行脚本的制约,如果代码运行超过特定的时间或者特定语句数量就不让它继续执行。如果代码达到了这个限制,会弹出一个浏览器错误的对话框,告诉用户某个脚本会用过长的时间执行,询问是允许其继续执行还是停止它。所有JavaScript开发人员的目标就是,确保用户永远不会在浏览器中看到这个令人费解的对话框。定时器是绕开此限制的方法之一。
脚本长时间运行的问题通常是由两个原因之一造成的:过长的、过深嵌套的函数调用或者是进行大量处理的循环。这两者中,后者是较为容易解决的问题。长时间运行的循环通常遵循以下模式:
for(var i=0; i < data.length; i++){
code(data[i]);//处理代码
}
这种循环模式的问题在于要处理的项目的数量在运行前是不可知的。如果完成code()要花100ms,只有2个项目的数组可能不会造成影响,但是10个的数组可能会导致脚本要运行一秒钟才能完成。数组中的项目数量直接关系到执行完该循环的时间长度。同时由于JavaScript的执行是一个阻塞操作,脚本运行所花时间越久,用户无法与页面交互的时间也越久。
在解决这个问题之前,开发者需要确定一个代码逻辑:如果没有for循环的阻塞,会出现其他的逻辑混乱,那么最好不要改动它。若不会影响其他代码或页面效果,可以使用以下方法。
setTimeout(function(){
var item = data.shift();
code(item);
if(data.length>0{
setTimeout(arguments.callee, timer);
}
},timer)
上述的代码含义是:使用定时器分割for循环。这是一种叫做数组分块(array chunking)的技术,小块小块地处理数组,通常每次一小块。基本的思路是为要处理的项目创建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。
函数节流
var n=0;
window.onresize = function(){
console.log(++n);
}
浏览器中某些计算和处理要比其他的昂贵很多。例如,DOM操作比起非DOM交互需要更多的内存和CPU时间。连续尝试进行过多的DOM相关操作可能会导致浏览器挂起,有时候甚至会崩溃。尤其在IE中使用onresize事件处理程序的时候容易发生,当调整浏览器大小的时候,该事件会连续触发。在onresize事件处理程序内部如果尝试进行DOM操作,其高频率的更改可能会让浏览器崩溃。为了绕开这个问题,你可以使用定时器对该函数进行节流。
函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。以下是该模式的基本形式:
var n=0;
function resizeHandler() {
console.log(n);
n++;
}
function throttle(method, context) {
clearTimeout(method.tId);
method.tId=setTimeout(function(){
method.call(context);
},500);
}
window.onresize = function(){
throttle(resizeHandler);
};
多数情况下,用户是感觉不到变化的,虽然给浏览器节省的计算可能会非常大。 只要代码是周期性执行的,都应该使用节流,但是你不能控制请求执行的速率。这里展示的throttle()函数用了100ms作为间隔,你当然可以根据你的需要来修改它。
3、其他
赋值
var i=1,ret;
ret=i!==1||true;
console.log(ret); //true