欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[JavaScript]几个函数的小知识

程序员文章站 2024-02-19 12:36:46
...

函数声明和函数表达式的区别

函数声明

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

关于函数声明,它的一个重要特征就是函数声明提升,意思是在执行代码之前会先读取函数声明。

函数表达式

var functionName = function(arg0, arg1, arg2) {
    //函数体
};

上面这种情况下创建的函数叫做匿名函数。

看下面这段代码,它会导致很多错误,

//这是错的
if(condition){
    function sayHi() {
        console.log("Hi");
    }
}else {
    function sayHi() {
        console.log("hi!!");
    }
}

因为函数声明提升问题,大部分浏览器会返回第二个声明(忽略condition),Firefox会在condition为true时返回第一个声明。

下面使用函数表达式就不会发生这种错误。

//这是对的
var sayHi;

if(condition){
    sayHi = function() {
        console.log("Hi");
    };
}else {
    sayHi = function() {
        console.log("hi!!");
    };
}

还可以把函数作为其他函数的值返回。

function A(propertyName){
    return function(obj1, obj2){
        var value1=obj1[propertyName];
        var value2=obj2[propertyName];
        if(value1<value2){
            return -1;
        }else if(value1>value2){
            return 1;
        }else{
            return 0;
        }
    };
}

递归

递归函数时一个函数通过名字调用自身的情况下构成的!

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

这是一个典型的递归求阶乘的函数。

但是如果我加入这串代码,就会出错

var anotherFactorial  = factorial;
factorial = null;
anotherFactorial(5);//出错!!!

错误原因是return num * factorial(num-1);返回的是factorial,而它已经不是函数了。
改成return num * arguments.callee(num-1);就可以了
在严格模式下,不允许使用arguments.callee,可以使用命名函数表达式来达成相同的结果

作用域链

当某个函数被调用时,会创建一个执行环境及相应的作用域链。然后使用argument和其他命名参数的值来初始化函数的活动对象。

后台的每个执行环境都有一个表示变量的对象——变量对象。全局环境的变量对象始终存在,而像com[are()函数这样的局部环境的变量对象,则只在函数执行的过程中存在。

在创建compare()函数时,会创建一个预先包含全部变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。 当调用compare()函数时,会为函数创建一个执行环境,然后通过赋值函数的[[Scope]]属性中的对象构建起执行环境的作用域链。此后,又有一个活动对象(在此作为变量对象使用)被创建并被推入执行环境作用域链的前端

作用域链本质上是一个指向变量对象的指针列表。

关于this对象

匿名函数的执行环境具有全局性,因此其this对象通常指向window

还有三个一般的规律

  • 对于全局的方法调用,this指向的是全局对象window,即调用方法所在的对象
  • 如果函数作为对象的方法调用,this指向的是这个上级对象,即调用方法的对象
  • 构造函数中的this指向新创建的对象本身