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

js03--函数、函数作用域!

程序员文章站 2024-03-17 16:43:40
...

函数

  • 函数,又叫做方法,是使用者利用其性质和其他语句相结合达到相应目的工具。一个函数定义(也称为函数声明,或函数语句)由一系列的function关键字组成,依次为:
    • 函数的名称。
    • 函数参数列表,包围在括号中并由逗号分隔。
    • 定义函数的 JavaScript 语句,用大括号{}括起来。
  • 就像下面这样:

function square(number) {
  return number * number;
}
  • 函数square使用了一个参数,叫作number。这个函数只有一个语句,它说明该函数将函数的参数(即number)自乘后返回。函数的return语句确定了函数的返回值。
    return number * number;

函数声明与执行

  • 函数有三种基本的声明方式:”大众法”,”表达式法”,”对象法”。
  • 为什么会被分为以上三种呢?根据声明提升规则的影响;根据调用方式不同等。具体声明提升规则我会在后面详细解释。

“大众法”

  • 就如上面刚开始的介绍一样,中规中矩的格式进行声明。

    函数声明操作符function + 函数的名称() + 一对花括号包裹自己的作用域{函数体}


function functionName(){

}
  • 执行也非常简单,直接functionName()就可以调用函数。

“表达式法”

  • 所谓表达式法就是把函数像个值一样通过算式表达式传给一个变量!

var square = function(number) { 
    return number * number; 

};
var x = square(4); // x gets the value 16
  • 当然,使用了函数的表达式自然要遵守表达式的声明规则,同时,这两种方法声明函数自然不是为了看起来不一样那么简单,这就涉及到了js的声明提升机制,后面我会仔细的解释这一机制。
  • 另外一点需要注意的就是,既然把函数给了一个变量,即将函数体给了这个变量,那么这个变量就代表函数了,就是函数的名称,因此表达式后面的函数起不起名字根本无所谓!为了更加规范和减少代码量,当然是不起啦!

立即执行函数

  • 这是函数的一个另类,在其他语言里,就相当于声明后立刻调用一样,作用大小根本就是看环境,而且基本可以被正常的声明方式所代替,但是据我想在知识能力了解,多用于闭包和实现一些特殊功能!而闭包作为js一大特性,立即执行函数的地位也变得微妙起来。

(function logHello(){
    console.log("hello word!")
})();

不一样的参数

  • 学过其他语言的同学就知道,在众多非直译式脚本语言里,函数都有一个名气很大的特性,重载和多肽,在对象里面还有覆盖一说!但是js里是没有重载函数的!
  • 为什么没有重载呢?

    1. 这个和js的解析方式有关,引擎每次加载js脚本的时候会将声明和执行体分开,并按照先后顺序进行排列,同css的优先级一样,这些声明也有一个优先级顺序,后出现的函数或者变量优先级就会更高,覆盖前面的声明!
    2. 宽松的调用方式。js中函数调用只管你的函数名对不对,实际参数个数和类型它都不管,后面它自己还要做一个只能转换和比对,然后将参数传递进去!
  • 我们来看一个例子


function addNum(num){
    return num+100;
}
function addNum(num){
    return num+200;
}
console.log(addNum(100)); //300
  • 如果这样看不够明显,那么来看下面这个例子:

var addNum = function(num){
    return num+100;
};

addNum = function(num){
    return num+200;
};
console.log(addNum(100)); //300

如果有些时候看不懂,你把它转换为另一种表现方式,你会发现,这个其实非常明显,第一个例子的声明顺序在生命提升和引擎解析的结果和第二个例子按照表达式方法的声明方式顺序和结果如出一辙!

arguments 和 this

  • 函数有两个内部属性这里只做简单介绍,因为新的标准中arguments已经声明垂危即将废弃,不管是出于性能原因还是什么的,反正是要废弃了!而this的作用不是一言两语能够简单概述的,后面的某一节我会仔细的详细的解释this的具体用法!及其强大!
  • arguments配合callee方法是函数用于调用自身的,一个阶层函数的递归调用例子足以解释:

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

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

作用域

  • 和其他编程语言类似,js里的作用域规则也是简单明了的。一个花括号包裹的,就是其内部所有变量和方法的执行环境。每一个执行环境关联了一个变量对象,这些被关联的,充当着边界的作用,使内部的成员可以访问外部的环境或者说作用域,而外部却不能访问内部的变量或者方法成员!这个也是形成闭包的一大原因!
  • 每个函数或者对象都拥有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入一个环境栈中,而在执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
  • 当代码在一个执行环境中执行时,会创建一个变量对象有关的作用域链。作用域链的存在是为了明确区分不同环境下变量和方法的访问权限。

var color = "blue";

function changeColor() {
    var anotherColor = "red";

    function swapColor() {
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;

        //这里可以访问color、anotherColor和tempColor
        console.log(color + anotherColor + tempColor);
    }
    //这里可以访问color和anotherColor,但不能访问tempColor
    // console.log(tempColor); //tempColor is not defined
    console.log(color);//blue
    console.log(anotherColor);//red
    swapColor(); //redbluered
}
//这里只能访问color
console.log(color);//blue
// console.log(anotherColor);//anotherColor is not defined
// console.log(tempColor); //tempColor is not defined
changeColor();
  • 就像这样形成了一个作用域链

    windows─────────────────────────────────┐  等级 低
        │                                   │   │
        ├───color                           │   │
        └───changeColor() ──────────────────┤   │
                    │                       │   │
                    ├─anotherColor          │   │
                    └─swapColors()──────────┤  \│/
                        │                   │   v
                        └───tempColor───────┘  等级 高
    
  • 等级高的变量或者方法可以看见等级低的内容,就像情报局一样!详细的执行步骤我会在声明提升里为大家解释引擎的工作机制。

没有块级作用域

  • 在其他的语言中,会有块级作用域一说,和函数作用域一样,一但最后一次对变量或者函数进行调用,紧接着就会将作用域内的变量或者函数进行销毁。在js中的函数当然会执行类似的销毁,但是不要忘记了另外的一个家族同样包括”{ }”一对大括号!那就是js的语句!如:if……else,while,for等等;
  • 在其他语言中,这些语句在使用完变量之后,且后面再也不会用到该变量的时候,就会对这些变量进行销毁,但是js不一样,不是因为不销毁,而是这些语句被放到了这个作用域的外层作用域去了!看下面:
if(true){
    var color="blue";
}
consolr.log(color); //blue

像上面这样,在其他大多数编程语言里是不允许的,尤其是类C语言,因为他们拥着自己的块级作用域,就像小狗的窝也是自己的窝,自己的窝是神秘而又不可侵犯的!
+ js中也有销毁,但是也有躲避销毁延长生命期的办法,那就是闭包!请看最后部分!

闭包和声明提升感觉有点多,我将咋下一节笔记中详细讲述!