JavaScript学习——函数表达式

function fuctionName(arg0,arg1,arg2){
//函数体
}

不要这样做

if(condition)
function sayHi(){
alert("Hi");
}
else{
function sayHi(){
alert("Yo");
}
}

ECMAScript中属于无效语句。

可以这样做

var sayHi;
if(condition){
sayHi=function(){
alert("Hi");
};
}
else{
sayHi=function(){
alert("Yo");
};
}

1.递归

function factorial(num){
if(num<=1){
return 1;
}
else{
return num*arguments.callee(num-1);
}
}

但在严格模式无法使用arguments.callee,可以这样做

var factorial = (function f(num){
if(num<=1){
return 1;
}else{
return num*f(num-1);
}
});

这种方式在严格非严格都行得通。

2.闭包

闭包是指有权访问另一个函数作用域中的变量的函数。创建闭包的常见方式就是在一个函数内部创建另一个函数

function createComparisonFunction(propertyName){
return function(object1,object2){
var value1=object1[propertyName];
var value2=object2[propertyName];
if(value1<value2)
{
return -1;
}
else if(value1>value2)
{

return 1;
}
else{
return 0;
}
};
}

2.1闭包与变量

function createFunctions(){
    var result=new Array();
    for(var i=0;i<10;i++){
    result[i]=function(){
        return i;
    };
    }
    return result;
}

每个函数都返回10,因为每个函数的作用域链中都草村这createFunctions()函数的活动对象,所以他们引用的都是同一个变量i。当createFunctions()函数返回后,变量i的值是10,此时每个函数都引用着保存变量i的同一个变量对象,所以都是10。我们可以通过创建另一个匿名函数强制让闭包的行为符合预期

function createFunctions(){
    var result=new Array();
    for(var i=0;i<10;i++){
        result[i]=function(num){
            return function(){
                return num;
            };
        }(i);
    }
return result;
}

 2.this对象

在全局函数中,this等于window,而当函数被作为某个对象的方法调用时,this等于那个对象。不过匿名函数的执行具有全局性,因此其this对象通常只想window,但有时由于编写闭包的方式不同,这一点可能不会那么明显。

var name="The Window";
var object={
name:"My Object";
getNameFunc:function(){
return fuction(){
return this.name;
};
}
};
alert(object.getNameFunc()());//"The Window"

由于代码创建了一个全局变量name,有创建了一个包含name属性的对象。这个对象还包含一个方法getNameFunc(),它返回一个匿名函数,而匿名函数又返回this.name。由于getNameFunc()返回一个函数,因此调用object.getNameFunc()()就会立即调用它并返回函数。每个函数在被调用时都会自动取得两个特殊变量:this和arguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。不过,把外部作用域中的this对象保存在一个闭包能够访问到的变量里,就可以让闭包访问对象。

var name="The Window";
var object={
name:"My Object";
getNameFunc:function(){
var that=this;
return fuction(){
return that.name;
};
}
};
alert(object.getNameFunc()());//"My Object"

2.3内存泄漏

如果闭包作用域链中保存着一个HTML元素,那么就意味着该元素将无法被销毁。

function assignHandler(){
var element=document.getElementById("someElement");
element.onclick=function(){
alert(element.id);
};
}

以上代码创建了一个作为element元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element的引用数。只要匿名函数存在,element的引用数至少也是1,因此占用的内存就永远不会被回收。

function assignHandler(){
var element=document.getElementById("someElement");
var id=elemt.id;
element.onclick=function(){
alert(id);
};
element=null;
}

3.模仿块级作用域

JavaScript从来不会告诉你是否多次声明了用一个变量,遇到这种情况,它只会对后续的声明视而不见(不过,它会执行后续声明中的变量初始化。)匿名函数可以用来模仿块级作用域并避免这个问题。

用作块级作用域(私有作用域)的匿名函数的语法如下

(function()){
//这里是块级作用域
})();
function outputNumbers(count){
(function(){
for (var i=0;i<count;i++){
alert(i);
}
})();
alert(i)//错误!
}

因为在匿名函数中定义任何变量,都会在执行结束时被销毁。

(function(){
var now=new Date();
if(now.getMonth()==0&&now.getDate()==1){
alert("Happy new year!");
}
})();

这段代码可以确定那一天是1月1日,如果到了这一天,就会向用户祝贺新年的消息。其中now现在是匿名函数中的局部变量,而我们不必在全局作用域中创建它。

4.私有变量

严格来讲,JavaScript中没有私有成员的概念;所有对象属性都是公有的。不过,倒是有一个私有变量的概念。任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量。私有变量包括函数的参数、局部变量和在函数内定义的其他函数。

我们把有权访问私有变量和私有函数的公有方法称为特权方法。

function MyObject(){
//私有变量和私有函数
var privateVariable = 10;
function privateFunction(){
return false;
}
//特权方法
this.publicMethod = function(){
privateVariable++;
return privateFunction();
};
}

 这个模式在构造函数内部定义了所有私有变量和函数。然后,又继续创建了能够访问这些私有成员的特权方法。

利用私有和特权成员,可以隐藏那些不应该被直接修改的数据

function Person(name){
this.getName=function(){
return name;
};
this.setName = function(value){
name=value;
};
}
var person = new Person("Nicholas");
alert(person.getName());//"Nicholas"
person.setName("Greg");
alert(person.getName());//"Greg"

setName和getName都是特权方法,但优缺点,就是必须使用构造函数模式来达到这个目的,构造函数模式的缺点就是针对每个实例都会创建同样一组新方法,而使用静态私有变量来实现特权方法可以解决。

4.1静态私有变量

(function(){
//私有变量和私有函数
var privateVariable=10;
function privateFunction(){
return false;
}
//构造函数
MyObject =function(){
};
//公有/特权方法
MyObject.prototype.publicMethod=function(){
privateVariable++;
return privateFunction();
};
})();

这个模式创建了一个私有作用域,并在其中封装了一个构造函数及相应的方法。

(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"

4.2模块方式

前面的模式是用于为自定义类型创建私有变量和特权方法的。而道格拉斯所说的模块模式则是为单例创建私有变量和特权方法。所谓单例(singleton),指的就是只有一个实例对象。

var singleton={
name:value,
method:function(){
//这里是方法的代码
}
};

模块模式通过为单例添加私有变量和特权方法能够使其得到增强

var singleton=function(){
//私有变量和私有函数
var privateVariable=10;
function privateVariable(){
return false;
}
//特权/公有方法和属性
return{
publicProperty:true,
publicMethod:fucntion(){
privateVariable++;
return privateFunction();
}
};
}();

4.3增强的模块模式

var singleton=function(){
//私有变量和私有函数
var pribateVariable=10;
function privateFunction(){
return fasle;
}
//创建对象
var object=new CustomType();
//添加特权/公有属性和方法
object.publicProperty=true;
object.publicMethod=function(){
privateVariable++;
return privateFunction();
};
//返回对象
return object;
}();
原文地址:https://www.cnblogs.com/pilee/p/3447640.html