javascript学习 – 作用域,变量提升,函数提升

发布于 2021-07-02  231 次阅读


JavaScript中作用域

在 JavaScript 中, 作用域为可访问变量,对象,函数的集合。

ECMAScript6之后新增了块级作用域的概念,对应let关键字
除此之外还有全局作用域,函数作用域。

块级作用域

由 { } 包括,if语句和for语句里面的{ }也属于块作用域。let声明的变量只在当前块内有效。

全局作用域

变量在函数外定义,即为全局变量,全局变量在页面关闭后销毁。
实际上,全局变量是全局对象的属性。在网页中,(译注:缺省的)全局对象是 window ,所以你可以用形如 window.variable 的语法来设置和访问全局变量。
全局变量有 全局作用域: 网页中所有脚本和函数均可使用。

函数作用域(又称为局部作用域)

变量在函数内声明,变量为局部作用域。
局部变量:只能在函数内部访问,函数执行完毕后销毁。
(函数参数也使用函数作用域)

var

var声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问
捕获变量容易令人误解

for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}
//setTimeOut()会在若干秒延时后执行一个函数

函数执行在若干秒之后,是在for循环之后触发的,但由于变量i作用域是全局的,故而在循环之后都运行的为i=10之后的函数。

一个通常的解决方法是使用立即执行的函数表达式(IIFE)来捕获每次迭代时i的值:

for (var i = 0; i < 10; i++) {
    // capture the current state of 'i'
    // by invoking a function with its current value
    (function(i) {
        setTimeout(function() { console.log(i); }, 100 * i);
    })(i);
}

多次声明同一个变量并不会报错

function sumMatrix(matrix: number[][]) {
    var sum = 0;
    for (var i = 0; i < matrix.length; i++) {
        var currentRow = matrix[i];
        for (var i = 0; i < currentRow.length; i++) {
            sum += currentRow[i];
        }
    }

    return sum;
}

var i多次在for循环内声明并不会报错

let

let声明的为块作用域变量,块作用于变量在包含它们的块或for循环之外是不能访问的

变量提升

JavaScript 变量的另一个不同寻常的地方是,你可以先使用变量稍后再声明变量而不会引发异常。这一概念称为变量提升;JavaScript 变量感觉上是被“提升”或移到了函数或语句的最前面。但是,提升后的变量将返回 undefined 值。因此在使用或引用某个变量之后进行声明和初始化操作,这个被提升的变量仍将返回 undefined 值。

/**
 * 例子1
 */
console.log(x === undefined); // true
var x = 3;
/*=======================等效于如下========================*/
var x;
consle.log(x === undefined);
x = 3;


/**
 * 例子2
 */
// will return a value of undefined
var myvar = "my value";

(function() {
  console.log(myvar); // undefined
  var myvar = "local value";
})();
/*===================等效于如下=========================*/
var myvar = "my value"
(function(){
    var myvar;
    console.log(myvar);//undefined
    myvar = "local value"
})

在 ECMAScript 6 中,let(const)同样会被提升变量到代码块的顶部但是不会被赋予初始值。在变量声明之前引用这个变量,将抛出引用错误(ReferenceError)。这个变量将从代码块一开始的时候就处在一个“暂时性死区”,直到这个变量被声明为止。

console.log(x); // ReferenceError
let x = 3;

函数提升

对于函数来说,只有函数声明会被提升到顶部,而函数表达式不会被提升。

/* 函数声明 */

foo(); // "bar"

function foo() {
  console.log("bar");
}


/* 函数表达式 */

baz(); // 类型错误:baz 不是一个函数

var baz = function() {
  console.log("bar2");
};

Go Big or Go Home