函数表达式
1.函数表达式和函数声明
函数表达式:
x();//wrong
var x = function (arg0,arg1,arg2){//没有命名的函数称作匿名函数
//函数体
};
函数声明:会在执行代码读取之前先读取函数声明,因此可以把声明放在执行代码之后。
x();//right
function x (arg0,arg1,arg2){
//函数体
};
2.递归
function factorial(num){
if(num <= 1){
return 1
}else {
return num * arguments.caller(num-1);//better than factorial(num-1)
//严格模式下:不能访问arguments.caller
//此时该用命名函数
}
}
//命名函数形式:括号把命名函数包起来,然后赋值给factorial
var factorial = (function f(num){
if(num <= 1){
return 1
}else {
return num * f(num-1);//better than factorial(num-1)
}
});
3.闭包与匿名
闭包:可以访问其他函数作用域中的变量的函数。建立闭包,即在一个函数内部创建另一个函数。
原理:内部函数的作用域链包括了外函数以及全局执行环境,当外部函数执行完毕后,只要还有内部函数在引用它的变量,外部函数的活动对象仍然会留在内存里,直到内部函数被销毁。
缺点:闭包会携带更多的作用域,会占用更多的内存。
(1).闭包容易碰到的问题:结果全表示出来是10个[10…]
function createFunctions(){
var result = [];
for (var i=0; i < 10; i++){
result[i] = function(){
return i;
};
}
return result;
}
var funcs = createFunctions();
console.log(funcs[0]);
console.log(i);//10
for(i=0;i<funcs.length;i++){
console.log(funcs[i]());
}
----
最后的结果result=[function,function….]
每个function 是function(){return i; }; 最后返回createFunctions()函数时,i的值是10。结果是10个10
修改:再创建一个匿名函数,把那个闭包包起来,(i)按值传递,把这个匿名函数的结果立即传递给了数组。结果[function,….]
每个function为function(){return x}; 0,1,2….
function createFunctions(){
var result = [];
for (var i=0; i < 10; i++){
result[i] = function(x){
return function(){
return x;
};
}(i);
}
return result;
}
var funcs = createFunctions();
console.log(funcs);
console.log(i);
for(i=0;i<funcs.length;i++){
console.log(funcs[i]());
}
(2).闭包和匿名函数的区别及this的问题:
在于是否访问了其他函数作用域中的变量。
- 匿名函数:其执行环境具有全局性
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
}
alert(object.getNameFunc()()); //"The Window"
-闭包
添加了让闭包能够访问的外部函数的变量,that
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()()); //"MyObject"
4.内存泄漏
function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id;//添加这一句,把副本保存在id这个变量当中,消除循环引用
element.onclick = function(){
alert(id);
};
element = null;//闭包会引用包含函数的整个活动对象,即使不直接引用element,也会一直保存这个引用,所以最后要将其销毁。
}
5.匿名函数模仿块级作用域,私有变量,特权方法
(1)
块级作用域:即私有作用域,如名字所知,就是在一个“块”中定义的变量,离开这个域之外无法再引用。
用以限制过多的全局变量和函数,有助于协同开发
(function (){//匿名函数
//这里是块级作用域
})();//最后的括号会立即调用这个函数,表示生效
(2)
特权方法: 有权访问私有变量函数的共有方法。
方法1:构造函数:创建一个构造函数,然后用this.XXX=function 建立闭包特权方法
方法2:创建静态私有变量:所有实例可以共享这个特权方法
-1)私有域中封装构造函数和相应方法。
-2).静态私有变量..其实没什么大的差别。
(function(){
var name = "";
Person = function(value){
name = value;
};
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function (value){
name = value;
};
})();
var person1 = new Person("Nicholas");
alert(person1.getName()); //"Nicholas"
person1.setName("Greg");
alert(person1.getName()); //"Greg"
var person2 = new Person("Michael");
alert(person1.getName()); //"Michael"
alert(person2.getName()); //"Michael"
//name成为了一个静态的由所有实例共享的属性
//改变一个,会改变所有
6.单例块级以及增强块级
单例块级:创建一个对象,并对某些数据初始化,同时还要公开一些访问这些私有数据的方法
function BaseComponent(){
}
function OtherComponent(){
}
var application = function(){
//private variables and functions
var components = new Array();
//initialization
components.push(new BaseComponent());
//create a local copy of application
var app = new BaseComponent();//增强,适用于单例必须是某种类型的实例,没有本质区别。
//public interface
app.getComponentCount = function(){
return components.length;
};
app.registerComponent = function(component){
if (typeof component == "object"){
components.push(component);
}
};
//return it
return app;
}();