目录:
  • 作用域
    • 作用域分类
    • LHS&RHS
    • 声明提升
    • 变量提升
  • 函数
    • 函数定义
    • 箭头函数
    • 函数名
    • 函数参数
    • 函数提升

作用域:

众所周知,js作用域分为两类:全局作用域和局部(函数)作用域。

  • 全局作用域:即在script定义的变量。
  • 局部作用域:在函数内部定义的变量。

js规定了函数内部可以访问全局变量,而外部无法访问局部变量。

理解作用域:

var a = 10;

上方代码的赋值会执行两个操作,首先编译器会在当前作用域创建一个变量(若变量已经声明过,则会忽略该声明);然后运行时引擎会在作用域中查询该变量,如果能够找到就对其进行赋值。

LHS和RHS:

还是上方实例,引擎在查询时,会对变量进行LHS查询或者RHS查询。

  • LHS:(赋值规则):变量出现在赋值操作符的左侧。如果当前作用域和上层作用域找不到该变量,则会悄悄地把它注册为全局变量。
  • RHS:(访问规则):变量出现在赋值操作符的右侧。如果当前作用域和上层作用域找不到该变量,此时会报错。
LHS和RHS有什么用:

为什么区分LHS和RHS有很重要呢?
考虑一下代码:

function foo(a){
    console.log(a+b);
    b = a;
}
foo(2);

当执行函数第一条语句时,a和b显然时RHS,此时找不到b,因此是未定义;而当执行LHS查询时,找不到b,则会注册一个全局变量。

声明变量

  • var:由var声明的变量属于全局变量,在函数内声明则是局部变量。
  • let,由let声明的变量属于块级变量,即大括号。所以大括号之外的区域不可访问。
  • const:由const声明的变量也属于块级变量,且由它声明的变量会锁定,不可以进行重新赋值,但可以被更改。

变量提升:

var定义的全局变量会进行提升,移动到最前面。

console.log(a) //undefined
var a = 10;

上方代码执行结果为undefined原因就是变量进行了提升,变成了这样:

var a;
console.log(a);
a = 10;

函数:

函数实际上是对象,每个函数都是Function实例,而函数名就是指向函数对象的指针。

函数定义:

  • 函数声明:(最后没有分号)
function sayHello(){
    let message = "hello!"
    return message;
}
  • 函数表达式:(最后有分号)
let sayHello = function(){
    let message = "hello!"
    return message;
};
  • 构造函数:(不推荐)
let sayHello = new Function(){
    let message = "hello!"
    return message;
}

函数名:

函数名就是指向函数的指针,因此一个函数可以有多个名称。

function sum(num1,num2){
    return num1+num2;
}
let sum1 = sum();

但下面的赋值代表着什么呢?

let sum2= sum;

是给将该函数赋值给了sum2吗?显然不是。上文已经提到,函数就是对象。

使用不带括号的函数名会访问函数指针,指向相同的函数,且不会执行该函数。

函数参数:

JavaScript参数有所不同,它不关心参数的多少、类型, 因为在函数内部,参数表现为一个数组。因此有了arguments
arguments可以访问到传递给函数的所有参数,它是一个伪数组,例如:

      function a(num) {
        for (let i = 0; i < arguments.length; i++) {
          console.log(arguments[i]);
        }
      }
      a(1, 2, 3, 4);

函数提升:

除了var会提升之外,函数也会提升。并且同时存在变量提升和函数提升时,函数优先。
具名函数才会提升

fun(); //1
function fun() {
    console.log(1);
}

foo(); //报错,TypeError
var foo = function bar() {
    console.log(1);
};

上方代码分别使用函数声明和函数表达式进行定义函数,所得结果为什么不同呢?

因为函数表达式会当成变量提升,因此实际上是var foo,因此会报错。由此可知,
函数声明会全部提升,函数表达式只会提升变量

var foo = function () {
    console.log(1);
};
function foo() {
    console.log(2);
}
foo(); //2

刚才已经提到函数表达式只会对变量提升,因此,上方代码就是定义foo变量,并有两个相同函数名的函数,最后结果为2,可以知道JS中没有函数重载的概念,相同函数名会被覆盖

console.log(a);  //函数
var a = 10;
function a() {
    console.log("fun");
}

当函数和变量同名时,执行结果为函数,因此变量和函数同时存在时,函数优先并且同名会被覆盖。

立即调用函数(IIFE):

类似于函数声明,将函数包裹再括号中,模拟块级作用域。

(function () {
 for (var i = 0; i < count; i++) {
 console.log(i);
 }
})();
更多内容请看:IFTS