定义函数有两种方式:函数声明,函数表达式
函数声明
function functionName(){
//函数体
}
函数声明的一个重要特征:函数声明提升,在执行代码前会先读取函数声明。这意味着 将函数声明放在调用他的语句后面;
函数表达式:var functionName = function(){}
递归
递归函数是一个函数通过名字调用自身的情况下构成的
非严格模式下,可以写作:
var factorial(num){
if(num <=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
}
严格模式下,可以通过命名函数表达式来达到相同的结果
var factorial = (function f(num){
if(num <= 1){
return 1;
}else {
return num*f(num-1);
}
})
闭包
闭包指的是有权访问另一个函数作用域中的变量的函数;
闭包会携带包含它的函数作用域,因此会占用更多内存,因此要慎重使用闭包
闭包和变量
闭包只能取得包含函数中任何变量的最后一个值。闭包所保存的是整个变量对象,而不是某个特殊的变量
function createFun(){
var result = new Array();
for(var i = 0;i < 10;i++){
result[i] = function(){
return i;
}
}
return result;
}
会发现所有的i都会10;
解决方案:
function createFun(){
var result = new Array();
for(var i = 0;i < 10;i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
关于this对象
this 对象运行时基于函数的执行环境绑定:在全局函数中this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象;不过匿名函数的执行环境有全局性,因此其this通常指向window;
var name = "window";
var object = {
name: "My Object",
getNameFunc: function(){
var that = this;
return function(){
return that.name;
}
}
}
console.log(object.getNameFunc());//"My Object"
var name = "window";
var object = {
name: "My Object",
getNameFunc: function(){
return this.name;
}
}
object.getName();//"My Object"
(object.getName)();//"My Object"
(object.getName = object.getName)();//"window"
内存泄漏
防止内存泄漏
function assignHandler(){
var element = document.getElementById("someElement");
var id = element.id;
element.onclick = function(){
console.log(id);//若直接应用element,会造成无法释放element
}
element = null;
}
模仿块级作用域
js没有块级作用域的概念。这意味着块语句中定义的变量,实际上是在包含函数中而非语句中创建的;js从不会告诉你是否多次声明了同一个变量,遇到这种情况,它只会对后续的声明视而不见(不过,会执行后续声明中的变量初始化);
匿名函数可以用来模仿块级作用域避免这个问题
(function(){ })();
function(){ }();//会报错,function是函数声明的开始,函数声明后面不能跟圆括号,而函数表达式后面可以跟圆括号
这是一个立即调用的匿名函数,将函数声明包含在一对圆括号中,表示实际上是一个函数表达式,这种做法可以减少闭包占用的内存问题,因为没有指向匿名函数的引用,只要函数执行完毕,就可以销毁其作用域链了。
我们应该尽量向全局作用域中少添加变量和函数
私有变量
定义在函数中的变量,都可以认为是私有变量,私有变量包括函数的参数,局部变量、函数内部定义的其他函数
把有权访问私有变量和私有函数的公有方法称为特权方法,
在构造函数中定义特权方法的缺点:构造函数会使每个实例都创建同一组新方法,使用静态私有变量可以避免这个问题
静态私有变量
(function (){
var privateVariable = 10;
function provateFunction(){
return false;
}
//构造函数,声明构造函数时没有使用函数声明(会创建成局部变量,也没有使用var ,因为初始化未经声明的变量,会创造一个全局变量;但是在严格模式下会导致错误)
MyObject = function(){};
MyObject.prototype.publicMethod = function(){
privateVariable ++;
return provateFunction();
}
})();
但是同样会造成每个实例都没有自己的私有变量,即在prototype上操作的属性会变成一个静态的、由所有实例共享的属性;
模块模式
为单例创建私有变量和特权方法,
增强的模块模式
var application = function(){
//私有变量和函数
var compents = new Array();
//初始化
compents.push(new BaseComponent);
//创建application 的一个局部副本
var app = new BaseComponent();
//公共接口
app.getComponentCount = fucntion(){
return compents.length;
}
app.registerComponent = function(compent){
if(typeof compent === "object"){
compents.push(compent);
}
}
return app;
}