您的位置:首页 > Web前端 > JavaScript

Javascript语言精粹(二)

2015-07-15 16:45 537 查看

闭包

// 创建一个构造函数quo
// 它带有get_status方法和status私有属性
var quo = function(status){
return {
get_status: function(){
return status;
}
};
};
var myQuo = quo('amazing');
alert(myQuo.get_status());


当我们调用quo时,它返回一个对象:

①该对象包含一个get_status方法,②该对象的一个引用保存在myQuo中。

即使quo已经返回了(return status;),但get_status方法仍然有访问status属性的特权。

get_status方法访问的并不是status参数的副本,而是status参数本身!

因为该函数可以访问它被创建时所处的上下文环境。也因此该函数被称为闭包。

再看一个更有用的栗子:

// 定义一个函数,它使一个DOM节点的背景色由黄变白
var fade = function(node){
var level = 1;
var step = function(){
var hex = level.toString(16);
node.style.backgroundColor = '#FFFF' + hex + hex;
if(hex < 15){
level += 1;
setTimeout(step, 100);
}
};
setTimeout(step, 100);
};

fade(document.body);


只要fade的内部函数step需要levellevel变量就会持续保留。

糟糕的栗子:

// 弹出节点的序号
var add_the_handlers = function(nodes){
var i;
for(i=0; i<nodes.length; i++){
nodes[i].onclick = function(){
alert(i);  //总是弹出节点的数目
};
}
};


未能达到目的的原因,是因为onclick时间处理器函数绑定了变量 i 本身,而不是函数在构造时的变量 i 的值

(个人理解:js解析的时候,把for循环解析了一遍, 运行的时候 i 已经等于节点数目了。绑定了 i 本身,故弹出的 i 等于节点数目。我们需要弹出的 i 是在它被构造时的值。)

解决糟糕的栗子:

var add_the_handlers = function(nodes){
var helper = function(i){
return function(){
alert(i);
};
};

var i;

for(i=0; i<nodes.length; i++){
nodes[i].onclick = helper(i);
}
};


避免在循环中创建函数,这会带来无谓的计算,还会引起混淆。

可以在循环之外先创建一个辅助函数helper,让辅助函数返回一个绑定了当前 i 值的函数,这样就不会混淆了。

模块

我们可以使用函数和闭包来构建模块,这几乎可以完全摒弃全局变量的使用。

模块是一个提供接口却隐藏状态和实现的函数或对象。

模块模式也可以用来产生安全的对象。

我们来构造一个产生序列号的对象:

var serial_maker = function(){
// 该对象包含一个设置前缀的方法
// 该对象包含一个设置序列号的方法
// 和一个生成字符串的方法

var prefix = ''; //前缀
var seq = 0; //序列号
return {
set_prefix: function(p){
prefix = String(p);
},
set_seq: function(s){
seq = s;
},
generate: function(){
var result = prefix + seq;
seq += 1;
return result;
}
};
};

// 调用
var seqer = serial_maker();
seqer.set_prefix('Q');
seqer.set_seq(1000);
var unique = seqer.generate(); // "Q1000"


如果我们把seqer.generate作为一个值传递给第三方函数,这个函数能产生唯一的字符串,但却不能通过它来改变prefix和seq的值。

级联

有一些方法没有返回值。例如一些设置或修改对象状态的方法。

如果我们让这些方法返回 this 而不是 undefined,就可以启用级联

getElement('mydiv')
.move(350, 150)
.width(100)
.height(100)
.on('mouseenter', 'drag');


这些方法每一个都返回该对象,所以每次调用返回的结果可以被下一次调用所用。

级联能给“全能”接口的热潮降降温,一个接口没必要一次做太多事情。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: