函数表达式

一、函数表达式与函数声明有何不同?

二、怎么进行递归调用

三、什么是闭包?

四、闭包有什么作用?

  • 模仿块级作用域
  • 创建私有变量

 

一、函数表达式与函数声明有何不同?

1、函数声明在执行时会提升到执行环境的头部,而函数表达式不会。

funName()  //可以执行,不会报错,因为funName已经提升的执行环境的头部
function funName(){
    alert("hello");
}
funName()  //报错:Uncaught TypeError: funName is not a function at index.js:1
var funName=function(){
    alert("hello");
}

2、在if...else...语句中使用函数声明创建函数会转化以函数表达式的方式进行创建,所以funName在执行时不会提升到头部。

//正确
var
condition=false; if(condition){ function funName(){ alert("hello"); } }else{ function funName(){ alert("hi"); } } funName();
//错误,index.js:10 Uncaught TypeError: funName is not a function at index.js:10
funName();
var condition=false; if(condition){ function funName(){ alert("hello"); } }else{ function funName(){ alert("hi"); } }

二、怎么进行递归调用?

这是我们正常的递归使用方法。

function addNums(num){
    if(num===1){
        return 1;
    }else{
        return num+addNums(num-1);
    }
}

var sum=addNums(10);
console.log(sum);  //返回55

由于函数是引用类型的实例,所以我们可以对所提供的指针进行操作。现在我们把上述进行一个改变

function addNums(num){
    if(num===1){
        return 1;
    }else{
        return num+addNums(num-1);
    }
}

var addOtherNums=addNums;//把addNums赋值给addOtherNums
addNums=null;//把addNums设置为空

var sum=addOtherNums(10);
console.log(sum);//报错:index.js:5 Uncaught TypeError: addNums is not a function 

因为addNums已经变为null,所以在执行中无法找到该函数。现在,我们用arguments.callee来代替addNums

function addNums(num){
    if(num===1){
        return 1;
    }else{
        return num+arguments.callee(num-1);
    }
}

var addOtherNums=addNums;
addNums=null;

var sum=addOtherNums(10);
console.log(sum);//55,可以正常使用

因为arguments.callee属性指向当前正在执行的函数本身,所以无论变量怎么改变都不会影响。

三、什么是闭包?

创建一个函数时,都会生成一个作用域链,该作用域链包含该函数的活动变量以及包含该函数的环境的作用域链。

当我们在函数addClose内部定义了一个匿名函数,执行后返回匿名函数并赋值给变量add10。

虽然函数addClose执行完毕销毁了,但是匿名函数依旧被引用,所以作用域链还存在,还可以访问add10的属性,这个就是闭包。

换而言之,闭包是当函数执行完而被销毁时,其作用域依旧可以被引用。

function addClose(){
    var num=10;
    return function(args){
         return args+num;
    }
}
var add10=addClose();
console.log(add10(10));//20

addClose方法执行完毕后被销毁了,但是add10可以继续调用num这个变量。

四、闭包有什么作用?

1、模仿块级作用域。

js只有全局作用域和函数作用域,没有块级作用域。在其他语言中,for循环执行完毕后,变量i会被销毁,但是由于js没有块级作用域,所以在for循环后依旧可以调用。

function forEach(){
    for(var i=0;i<10;i++){
         console.log(i);//0-9
    }
    console.log(i);//10
}

forEach();

我们可以用(function(){....})来包含循环体,这样变量i在函数执行完毕后就销毁了,除非赋值给其他外部变量end_i

function forEach(){
    var end_i;
    (function(){
       for(var i=0;i<10;i++){
            console.log(i);//1-9  
       }                   //执行完成后,匿名函数已经被销毁,所以变量i已经不能调用
       end_i=i;
    })()
    console.log(end_i);//10
}

forEach();

 

2、创建私有变量

在js中,是没有私有属性的,所有属性都可以直接使用

使用构造函数模式来创建,每个对象都互不影响,但是无法进行方法复用,每个实例都创建addNums和getNums方法。

function MyObject(){
    var nums=10;

    this.addNums=function(){
        nums++;
    }

    this.getNums=function(){
        return nums;
    }
}

var myobject1=new MyObject();
myobject1.addNums();
console.log(myobject1.getNums());//11
var myobject2=new MyObject();
myobject2.addNums();
myobject2.addNums();
myobject2.addNums();
console.log(myobject2.getNums());//13

使用原型模式来创建,但每个实例都会影响nums

(function(){

    var nums=10;

    MyObject=function(){
    }
    
    MyObject.prototype.addNums=function(){
        nums++;
    }

    MyObject.prototype.getNums=function(){
        return nums;
    }

})()

var myobject1=new MyObject();
myobject1.addNums();
console.log(myobject1.getNums());//11
var myobject2=new MyObject();
myobject2.addNums();
myobject2.addNums();
myobject2.addNums();
console.log(myobject2.getNums());//14

可以根据实际情况选择创建的类型。

 

 

 

posted on 2020-10-11 17:59  大树_学习前端  阅读(76)  评论(1)    收藏  举报