存档

文章标签 ‘javascript 闭包’

《javascript精粹》读书笔记 – 函数

2011年1月14日 没有评论

1. 当实际参数的个数与形式参数的个数不匹配时,不会导致错误。
如果实际参数值过多了,超出的参数值将被忽略;如果实际的参数值过少,缺失的值将被替换为undefined。

2. 在javascript中一共有四种调用模式: 方法调用模式、函数调用模式、构造器调用模式和apply调用模式。这些模式在如何初始化关键参数this上存在差异。
a.方法调用模式:
当一个函数被保存为对象的一个属性时,我们称它为一个方法。方法调用模式可以使用this去访问对象,所以它能够从对象中取值或修改对象。
b.函数调用模式:
当一个函数并非一个对象的属性时,它被当作一个函数来调用。当函数以此模式调用时,this被绑定到全局变量,这是语言设计上的一个错误。(正确的情况:当内部函数被调用时,this应该仍然被绑定到外部函数的this变量。)解决方法:如果该方法定义一个变量并给他赋值为this,那么内部函数就可以通过那个变量访问到this,按照约定,给那个变量命名为 that:
[js]
//给 myObject增加一个double方法
myObject.double = function()
{
var that = this; //解决方法

var helper = function()
{
that.value = add(that.value, that.value);
}

helper(); //以函数的形式调用helper。
}

//以方法的形式调用double
myObject.double();
[/js]
c.构造器调用模式:
在一个函数前面带上new来调用,那么将创建一个隐藏连接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上。
[js]
//创建一个名为Quo的构造函数。它构造一个带有status属性的对象
var Quo = function(String)
{
this.status = String;
}

//给Quo的所有实例提供一个名为get_status的公共方法
Quo.prototype.get_status = function()
{
return this.status;
}

//构造一个Quo实例
var myQuo = new Quo("confused"); //构造器模式调用
document.writeln(myQuo.get_status());
[/js]
按照约定,构造器函数保存在以大写格式命名的变量里。
d.Apply调用模式:
apply方法接受两个参数,第一个是将被绑定给this的值,第二个就是参数数组。它让我们构建一个参数数组并用其去调用函数。
[js]
//构造一个Quo实例
var myQuo = new Quo("confused"); //构造器模式调用
document.writeln(myQuo.get_status());

//构建一个包含两个数字的数组,并将他们相加
add = function(a, b)
{
return a+b;
}

var anArray = [3, 4];
var sum = add.apply(null, anArray); //7

//构建一个包含status成员的对象
var statusObject = {
status: "A-OK"
};

//statusObject并没有继承自Quo.prototype,但我们可以再statusObject上调用
//get_status方法,尽管statusObject并没有一个名为get_status的方法。
var status = Quo.prototype.get_status.apply(statusObject);
[/js]

3. 参数:
当一个函数被调用时,会有一个默认的参数,就是 arguments “数组”。
[js]
//构造一个将很多值相加的函数

//注意该函数内部定义的变量sum不会与函数外部定义的sum产生冲突。
//该函数只能看到内部的那个变量。
var sum = function()
{
var i, sum=0;
for(i = 0; i < arguments.length; i+=1)
{
sum += arguments[i];
}
return sum;
};

document.writeln(sum(4, 8, 15, 16, 23, 42)); //108
[/js]
注:arguments并不是一个真正的数组。它知识一个“类似数组”的对象。arguments用友一个length属性,但它缺少所有的数组方法。

4. 返回:
一个函数总是会返回一个值。如果没有置顶返回值,则返回undefined。
如果函数以构造器方式被调用,且返回值不是一个对象,则返回this(该新对象)。

5.给类型增加方法:
[js]
Function.prototype.method = function(name, func)
{
this.prototype[name] = func;
return this;
}

//给Number添加一个integer方法,来提取数字钟的整数部分
//根据正负来判断是使用Math.ceil还是Math.floor
Number.method(‘integer’, function(){
return Math[this < 0 ? 'ceil' : 'floor'](this);
});

document.writeln((-10/3).integer()); //-3

//去掉字符串两端空白的方法
String.method(‘trim’, function()
{
return this.replace(/^\s+|\s+$/g, ”);
});
[/js]
基本类型的原型是公共结构,所以在类库混用时务必小心。一个保险的做法就是只在确定没有该方法时再添加:
[js]
//有条件的增加一个方法

Function.prototype.method = function(name, func)
{
if(!this.prototype[name])
{
this.prototype[name] = func;
return this;
}
};
[/js]

6.闭包
理解内部函数能访问外部函数的实际变量而无需复制
[js]
//构造一个函数,用错误的方式给一个数组中的借点设置事件处理程序
//当点击一个节点时,按照预想应该弹出一个对话框显示节点的序号
//但他总是会显示节点的数目

var add_the_handlers = function(nodes) {
var i;
for (i = 0; i < nodes.length; i += 1) {
nodes[i].onclick = function(e) {
alert(i);
}
}
}
[/js]
add_the_handlers函数的目的是给每个事件处理器一个唯一值(i)。它未能达到目的的原因是事件处理器函数绑定了变量i,而不是函数在构造时的变量i的值
正确的写法:
[js]
//点击一个节点,将会弹出一个对话框显示节点的序号
var add_the_handlers = function (nodes) {
var i;
for (i = 0; i < nodes.length; i +=1 ) {
nodes[i].onclick = function (i) {
return funtion (e) {
return alert(e);
} ;
}(i);
}
}
[/js]
现在,定义了一个函数并立即传递i进去执行, 而不是把一个函数赋值给onclick。那个函数将返回一个事件处理器函数。这个事件处理器函数绑定的是传递进去的i的值,而不只定义在add_the_handlers函数里的i的值。那个被返回的函数被复制给onclick。

7.javascript的单例模式
Javascript的单例就是用对象字面量表示法创建的对象,对象的属性值可以是数值或函数,并且属性值在该对象的生命周期中不会发生变化。他通常作为工具为程序其他部分提供功能支持

8.模块
模块模式的一般形式是:一个定义了私有变量和函数的函数;利用闭包创建可以访问私有变量和函数的特权函数,或者把他们保存到一个可访问的地方。
[js]
String.method(‘deentityify’, function (){
var entity = {
quot: ‘"’,
lt: ‘<’,
gt: ‘>’
}

return function () {
return this.replace(/&([^&;]+);/g,
function (a, b) {
var r = entity[b];
return typeof r === ‘string’ ? r : a;
});
};
}());
[/js]
模块模式利用了函数作用域和闭包来创建绑定对象与私有成员关联,摒弃了全局变量的使用,从而缓解这个JavaScript的最为糟糕的特性之一所带来的影响

深入理解 JavaScript闭包(closure)

2010年7月2日 1 条评论

最近在网上查阅了不少Javascript闭包(closure)相关的资料,写的大多是非常的学术和专业。对于初学者来说别说理解闭包了,就连文字叙述都很难看懂。撰写此文的目的就是用最通俗的文字揭开Javascript闭包的真实面目。

一、什么是闭包?
“官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相信很少有人能直接看懂这句话,因为他描述的太学术。其实这句话通俗的来说就是:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。看下面这段代码:
[js]
function a() {
var i = 0;
function b() {
alert(++i);
}
return b;
}
var c = a();
c();
[/js]

阅读全文…