定义函数的两种方式
- 函数声明
function Myfunc(){
//your code
}
函数声明提升:在执行代码时会先读取函数声明,可以把函数调用写在函数声明前面,不会报错。
//先调用函数声明,故不会报错
Myfunc();
function Myfunc(){
//your code
}
- 函数表达式
var MyFunc = function(){
//your code
}
这种方法创建的函数是匿名函数,使用时必须先创建函数,再调用,即调用函数必须放在创建函数后面。
Tips:在把函数当成值来使用时,使用匿名函数。
递归
一个函数通过名字调用他自身。
arguments.callee()指向正在执行函数的指针,或者使用命名函数。
//使用命名函数解决问题
var factorial2 = (function f(num){
if(num <= 1){
return 1;
} else {
return num * f(num-1);
}
});
//以上定义了一个f的命名函数表达式
var anthorfactorial=factorial2;
factorial2 = null;
console.log(anthorfactorial(6));
命名函数:函数如果有名字,就是命名函数
匿名函数:如果函数没有名字就是匿名函数
自调用函数:自己调用自己的函数(function(){console.log("这是函数的自调用");}) ();
闭包
闭包是指有权访问另一函数作用域中变量的函数,即在另一函数内部定义的函数。
闭包的缺点:占用内存,容易造成内存泄漏。
作用域链
一个函数具有一个作用域,在他内部的函数具有自己的作用域,同时也可以访问外部函数的作用域,就构成了作用域链。
作用域链产生了一个副作用:闭包只能取得包含函数中任意变量的最后一个值。
闭包与变量
//获取的是最后一个值
function createFunction(){
var result = new Array();
for(var i=0;i<10;i++){
result[i]=function(){
return i;
};
}
return result;
}
var funcs = createFunction();
//every function outputs 10
for (var i=0; i < funcs.length; i++){
document.write(funcs[i]() + "<br />"); //10,10,10...
}
//加入了一个新的匿名变量,使输出的值是对应的编号
function createFunction1(){
var result = new Array();
for(var i=0;i<10;i++){
result[i]=function(num){
return function(){
return num;
};
}(i); //函数自调用
}
return result;
}
var funcs1 = createFunction1();
//every function outputs it's num
for (var i=0; i < funcs1.length; i++){
document.write(funcs1[i]() + "<br />");
}
关于this对象
this是指包含它的函数作为方法被调用时所属的对象,this对象是在运行时基于函数的执行环境绑定。
匿名函数具有全局性,所以匿名函数的this对象通常是window
改变this的函数:
- call(对象,参数1,参数2…)
- apply(对象,[参数1,参数2…])
- bind(对象,参数1,参数2…)() //返回的是一个函数所以要加括号调用
内存泄漏
在闭包的作用域链里保存着一个html元素的话,会导致该元素无法被销毁。
模仿块级作用域
avascript中没有块级作用域的概念,在函数中定义的变量在整个函数中都可以随处访问。
(function(){
//模仿块级作用域
})();
私有变量
任何在函数中定义的变量都是私有变量,因为不能在函数外部访问这个变量。
Tips:构造函数的缺点:针对每一个实例都会创建同样一组新方法。
原型的缺点:所有变量和函数都是共享的,实例没有私有的对象。
function Myobject(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//特权方法
//用一个闭包,来获取外部函数的变量和方法
this.publicMethod = function(){
console.log(++privateVariable);
return privateFunction();
};
}
var obj=new Myobject();
//使用特权方法来调用私有函数和私有变量
console.log(obj.publicMethod());
//不能在外部调用私有函数
静态私有变量
使用原型方法,并把私有变量放在一个块级里,所有实例都没有私有变量,变量是实例共享的。
(function(){
var name = "";
Person = function(value){
name=value;
};
Person.prototype.getName = function(){
return name;
};
Person.prototype.setName = function(value){
name = value;
};
})();
var per1 = new Person("Nicholas");
console.log("per1: "+per1.getName());
per1.setName("Amy");
console.log("per1: "+per1.getName());
//每个实例没有自己的变量,所有变量都是可共享的。
var per2 = new Person("Greg");
console.log("per2: "+per2.getName());
console.log("per1: "+per1.getName());
模块模式
是为单例创建私有变量和特权方法的。
单例:是以对象字面量的方式来创建单例对象的。
function BaseComponents(){
}
function otherComponents(){
}
var application = function(){
//私有变量和函数
var components = new Array();
components.push(new BaseComponents());
//公共
return {
getComponent : function(){
return components.length;
},
registerComponents : function(component){
if(typeof component == "object"){
components.push(component);
}
}
};
}();
application.registerComponents(new otherComponents());
console.log(application.getComponent()); //2
增强的模块模式
在返回对象之前加入对其增强的代码,这种增强模式适合那些单例必须是某种类型的实例,以及必须添加某些属性和方法对其加以增强。
function BaseComponents(){
}
function otherComponents(){
}
var application = function(){
//私有变量和函数
var components = new Array();
//初始化
components.push(new BaseComponents());
//创建一个application的局部副本
var app = new BaseComponents();
//公共接口
app.getComponent = function(){
return components.length;
};
app.registerComponents = function(component){
if(typeof component == "object"){
components.push(component);
}
};
//返回这个副本
return app;
}();
application.registerComponents(new otherComponents());
application.registerComponents(new BaseComponents());
console.log(application.getComponent()); //3