高级技巧
高级函数
安全的类型检测
alert(Object.prototype.toString.call(value))
惰性载入函数
避免对浏览器支持能力的多次判断
函数绑定
let handler = {
message: "Event handled",
handleClick: function (event) {
alert(this.message);
}
}
let btn = document.getElementsByTagName("input")[0];
btn.addEventListener("click", function (event) {
handler.handleClick(event);
});
倘若将handler.handleClick
直接作为参数传入addEventListener
中将会显示undefined
而不是Event handled
bind()
函数,接收一个函数和一个环境
function bind(fn, context){
return function(){
return fn.apply(context, arguments);
};
}
利用bind()
函数即可直接将函数当作参数传递给addEventListener
中
btn.addEventListener("click", bind(handler.handleClick, handler));
ECMAScript 5 为所有函数定义了一个原生的bind()方法
btn.addEventListener("click", handler.handleClick.bind(handler));
函数柯里化
柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。
function curry(fn){
let 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);
};
}
function add(num1, num2) {
return num1 + num2;
}
let curriedAdd = curry(add, 5);//传入1个参数
alert(curriedAdd(3));
curriedAdd = curry(add, 5, 12);//传入2个参数
alert(curriedAdd());
函数柯里化与bind()
函数的结合
function bind(fn, context){
let args = Array.prototype.slice.call(arguments, 2);
return function(){
let innerArgs = Array.prototype.slice.call(arguments);
let finalArgs = args.concat(innerArgs);
return fn.apply(context, finalArgs);
};
}
let handler = {
message: "Event handled",
handleClick: function(name, event){
alert(this.message + ":"+ name + ":"+ event.type);
}
};
let btn = document.getElementById("my-btn");
btn.addEventListener("click", bind(handler.handleClick, handler, "my-btn"));
btn.addEventListener("click", handle.handleClick.bind(handler, "my-btn"));
防篡改对象
一旦把对象定义为防篡改,就无法撤销了
不可拓展对象
let person = {
name: "Nicholas"};
person.age = 29;//ok
let dog = {
name: "xiaobai"};
Object.preventExtensions(dog);//不能再给对象添加属性和方法
dog.age = 29;//无效
已有的成员不受影响,依旧可以修改和删除已有的成员
Object.isExtensible(person)
密封的对象
密封对象不可扩展,且不能删除属性和方法
let person = {
name: "Nicholas" };
Object.seal(person);//使用seal方法将对象密封
person.age = 29;
alert(person.age); //undefined
delete person.name;
alert(person.name); //"Nicholas"
Object.isSealed()
冻结的对象
不可拓展、不可删除,也不可修改
Object.freeze(person);
Object.idFrozen()
高级定时器
在JavaScript 中没有任何代码是立刻执行的,但一旦进程空闲则尽快执行
指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码
重复的定时器
为了避免setInterval()的重复定时器的缺点,可以使用setTimeout()的链式调用:
setTimeout(function(){
//处理中
setTimeout(arguments.callee, interval);
}, interval);
setTimeout(function () {
let div = document.getElementById("mydiv");
let left = parseInt(div.style.left) + 5;
div.style.left = left + "px";
if(left < 200){
setTimeout(arguments.callee, 50);
}
}, 50);
Yielding Processes
数组分块
setTimeout(function(){
//取出下一个条目并处理
let item = array.shift();
process(item);
//若还有条目,再设置另一个定时器
if(array.length > 0){
setTimeout(arguments.callee, 100);
}
}, 100);
function trunk(array, process, context