ES6的變量聲明

在ES5中,變量聲明只有var和function以及隱式聲明三種,在ES6中則增加了let,const,import和class四種,以下來(lái)介紹著七種變量的聲明。

var


ES5中最原始的變量聲明,用于聲明變量,其實(shí)JavaScript是弱類(lèi)型語(yǔ)言,對(duì)數(shù)據(jù)類(lèi)型變量要求不太嚴(yán)格,所以不必聲明每一個(gè)變量的類(lèi)型(這就是下面說(shuō)的隱式聲明,當(dāng)然這并不是一個(gè)好習(xí)慣),在使用變量之前先進(jìn)行聲明是一種好的習(xí)慣。

1.作用域

使用var聲明的變量的作用域是函數(shù)作用域(在ES5時(shí)代,只有函數(shù)作用域和全局作用域兩種作用域),在一個(gè)函數(shù)內(nèi)用var聲明的變量,則只在這個(gè)函數(shù)內(nèi)有效。

function test(){
    var a;
    console.log(a);//undefined
}
console.log(a);//ReferenceError: a is not defined    

2.變量聲明提升

用var聲明變量時(shí),只要在一個(gè)函數(shù)作用域內(nèi),無(wú)論在什么地方聲明變量,都會(huì)把變量的聲明提升到函數(shù)作用域的最前頭,所以無(wú)論使用變量在變量聲明前還是聲明后,都不會(huì)報(bào)錯(cuò)(當(dāng)然只是聲明提前,賦值并沒(méi)有提前,所以如果使用在聲明之前,會(huì)輸出undefined,但不會(huì)報(bào)錯(cuò))。

function test(){
    console.log(a);//undefined
    var a=3;
}

隱式聲明


當(dāng)沒(méi)有聲明,直接給變量賦值時(shí),會(huì)隱式地給變量聲明,此時(shí)這個(gè)變量作為全局變量存在。

function test(){
    a=3;
    console.log(a);//3
}
test();
console.log(a);//3

當(dāng)然要注意,隱式聲明的話(huà)就沒(méi)有變量聲明提前的功能了,所以下面的使用是會(huì)報(bào)錯(cuò)的。

function test(){
    console.log(a);//ReferenceError: a is not defined
    a=3;
}

function


用function聲明的是函數(shù)對(duì)象,作用域與var一樣,是函數(shù)作用域。

function test(){
    function a(){
        console.log('d');
    }
    a();//'d'
}
a();//ReferenceError: a is not defined

同樣,function聲明也有變量聲明提升,下面是兩個(gè)特殊的例子:

function hello1(a){
    console.log(a); //[Function: a]
    function a(){}
    console.log(a);//[Function: a]
}
hello1('test');   

function hello2(a){
    console.log(a); //test
    var a=3;
    console.log(a);//3
}
hello2('test');   

這里有涉及到函數(shù)中形參的聲明,我們可以將以上兩個(gè)例子看成:

function hello1(a){
    var a='test;
    console.log(a); //[Function: a]
    function a(){}
    console.log(a);//[Function: a]
}
hello1('test');   

function hello2(a){
    var a='test;
    console.log(a); //test
    var a=3;
    console.log(a);//3
}
hello2('test');   

可以看到函數(shù)對(duì)象的聲明也提前了,但是在形參變量聲明之后(形參的變量聲明在所有聲明之前)。

當(dāng)函數(shù)對(duì)象和普通對(duì)象同時(shí)聲明時(shí),函數(shù)對(duì)象的聲明提前在普通對(duì)象之后。

function test(){    
    console.log(a);//[Function: a]
    function a(){}
    var a;
    console.log(a);//[Function: a]
} 

let


ES6新增的聲明變量的關(guān)鍵字,與var類(lèi)似。

當(dāng)然,與var也有很大區(qū)別:

1.作用域不同

let聲明的變量的作用域是塊級(jí)作用域(之前的js并沒(méi)有塊級(jí)作用域,只有函數(shù)作用域和全局作用域),var聲明的變量的作用域是函數(shù)作用域。

{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1 

2.不存在變量聲明提升

用var聲明變量時(shí),只要在一個(gè)函數(shù)作用域內(nèi),無(wú)論在什么地方聲明變量,都會(huì)把變量的聲明提升到函數(shù)作用域的最前頭,所以無(wú)論使用變量在變量聲明前還是聲明后,都不會(huì)報(bào)錯(cuò)。而let不一樣,與java以及其他語(yǔ)言一樣,let聲明的變量,在未聲明之前變量是不存在的。(js的語(yǔ)法越來(lái)越向java靠攏)

console.log(a); // undefined,但是不報(bào)錯(cuò)。
console.log(b); // ReferenceError: b is not defined.

var a = 2;
let b = 2;  

注意:在使用babel時(shí)可能會(huì)遇到這樣的情況:

console.log(b); //undefined
let b = 2;    

babel在翻譯es6時(shí),似乎直接將let變?yōu)榱藇ar,所以運(yùn)行時(shí)也有變量聲明提升了,但是在Chrome下運(yùn)行時(shí)是正確的。

3.暫時(shí)性死區(qū)

所謂暫時(shí)性死區(qū),意思是,在一個(gè)塊級(jí)作用域中,變量唯一存在,一旦在塊級(jí)作用域中用let聲明了一個(gè)變量,那么這個(gè)變量就唯一屬于這個(gè)塊級(jí)作用域,不受外部變量的影響,如下面所示。

無(wú)論在塊中的任何地方聲明了一個(gè)變量,那么在這個(gè)塊級(jí)作用域中,任何使用這個(gè)名字的變量都是指這個(gè)變量,無(wú)論外部是否有其他同名的全局變量。

暫時(shí)性死區(qū)的本質(zhì)就是,只要一進(jìn)入當(dāng)前作用域,所要使用的變量就已經(jīng)存在了,但是不可獲取,只有等到聲明變量的那一行代碼出現(xiàn),才可以獲取和使用該變量。

暫時(shí)性死區(qū)的意義也是讓我們標(biāo)準(zhǔn)化代碼,將所有變量的聲明放在作用域的最開(kāi)始。

var a = 123;  
{
 console.log(a);//ReferenceError
 let a;
}

4.不允許重復(fù)聲明

在相同的作用域內(nèi),用let聲明變量時(shí),只允許聲明一遍。 (var是可以多次聲明的)

// 正確
function () {
  var a = 10;
  var a = 1;
}
 
// 報(bào)錯(cuò),Duplicate declaration "a"
function () {
  let a = 10;
  var a = 1;
}

// 報(bào)錯(cuò),Duplicate declaration "a"
function () {
  let a = 10;
  let a = 1;
}

const


const用來(lái)聲明常量,const聲明的常量是不允許改變的,只讀屬性,這意味常量聲明時(shí)必須同時(shí)賦值, 只聲明不賦值,就會(huì)報(bào)錯(cuò),通常常量以大寫(xiě)字母命名。

阮一峰大神的書(shū)里說(shuō),在嚴(yán)格模式下,重新給常量賦值會(huì)報(bào)錯(cuò),普通模式下不報(bào)錯(cuò),但是賦值無(wú)效。但是測(cè)試了一下,無(wú)論是嚴(yán)格還是非嚴(yán)格模式,都會(huì)報(bào)錯(cuò)。

const A = 1;
A = 3;// TypeError: "A" is read-only

const和let類(lèi)似,也是支持塊級(jí)作用域,不支持變量提升,有暫時(shí)性死區(qū).

注意:如果聲明的常量是一個(gè)對(duì)象,那么對(duì)于對(duì)象本身是不允許重新賦值的,但是對(duì)于對(duì)象的屬性是可以賦值的。

const foo = {};
foo.prop = 123;

foo.prop// 123

foo = {} // TypeError: "foo" is read-only

import


ES6采用import來(lái)代替node等的require來(lái)導(dǎo)入模塊。

import {$} from './jquery.js'  

$對(duì)象就是jquery中export暴露的對(duì)象。

import命令接受一個(gè)對(duì)象(用大括號(hào)表示),里面指定要從其他模塊導(dǎo)入的變量名。注意:大括號(hào)里面的變量名,必須與被導(dǎo)入模塊對(duì)外接口的名稱(chēng)相同。

如果想為輸入的變量重新取一個(gè)名字,import命令要使用as關(guān)鍵字,將輸入的變量重命名。

import { New as $ } from './jquery.js';

注意,import命令具有提升效果,會(huì)提升到整個(gè)模塊的頭部,首先執(zhí)行。

class


ES6引入了類(lèi)的概念,有了class這個(gè)關(guān)鍵字,當(dāng)然,類(lèi)只是基于原型的面向?qū)ο竽J降恼Z(yǔ)法糖,為了方便理解和開(kāi)發(fā)而已,類(lèi)的實(shí)質(zhì)還是函數(shù)對(duì)象,類(lèi)中的方法和對(duì)象其實(shí)都是掛在對(duì)應(yīng)的函數(shù)對(duì)象的prototype屬性下。

我們定義一個(gè)類(lèi):

//定義類(lèi)
class Person {
  constructor(name, age) {
        this.name = name;
        this.age = age;
  }    
  setSex(_sex) {
        this.sex=_sex;
  }
}  

constructor方法,就是構(gòu)造方法,也就是ES5時(shí)代函數(shù)對(duì)象的主體,而this關(guān)鍵字則代表實(shí)例對(duì)象,將上述類(lèi)改寫(xiě)成ES5格式就是:

function Person(name, age){
        this.name = name;
        this.age = age;
}

Person.prototype. setSex = function (_sex) {
        this.sex=_sex;
}

所以說(shuō),類(lèi)不算什么新玩意,大多數(shù)類(lèi)的特性都可以通過(guò)之前的函數(shù)對(duì)象與原型來(lái)推導(dǎo)。

1.所有類(lèi)都有constructor函數(shù),如果沒(méi)有顯式定義,一個(gè)空的constructor方法會(huì)被默認(rèn)添加(有點(diǎn)類(lèi)似java了)。當(dāng)然所有函數(shù)對(duì)象都必須有個(gè)主體。

2.生成類(lèi)的實(shí)例對(duì)象的寫(xiě)法,與ES5通過(guò)構(gòu)造函數(shù)生成對(duì)象完全一樣,也是使用new命令。

class B {}
let b = new B();

3.在類(lèi)的實(shí)例上面調(diào)用方法,其實(shí)就是調(diào)用原型上的方法,因?yàn)轭?lèi)上的方法其實(shí)都是添加在原型上。

b.constructor === B.prototype.constructor // true

4.與函數(shù)對(duì)象一樣,Class也可以使用表達(dá)式的形式定義。

let Person = class Me {
    getClassName() {
        return Me.name;
    }
};

相當(dāng)于

var Person = function test(){}

5.Class其實(shí)就是一個(gè)function,但是有一點(diǎn)不同,Class不存在變量提升,也就是說(shuō)Class聲明定義必須在使用之前。

全局變量


全局對(duì)象是最頂層的對(duì)象,在瀏覽器環(huán)境指的是window對(duì)象,在Node.js指的是global對(duì)象。

ES5之中,全局對(duì)象的屬性與全局變量是等價(jià)的,隱式聲明或者在全局環(huán)境下聲明的變量是掛在全局對(duì)象上的。

ES6規(guī)定,var命令,function命令以及隱式聲明的全局變量,依舊是全局對(duì)象的屬性;而let命令、const命令、class命令聲明的全局變量,不屬于全局對(duì)象的屬性。

var a = 1;
console.log(window.a) // 1

let b = 1;
console.log(window.b) // undefined

函數(shù)的形參


函數(shù)的形參,隱藏著在函數(shù)一開(kāi)始聲明了這些形參對(duì)應(yīng)的變量。

function a(x,y){}
可以看成  
function a(){
    var x=arguments.length <= 0 || arguments[0] === undefined ? undefined : arguments[0];
    var y=arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
}

當(dāng)然在ES6下默認(rèn)聲明就是用的let了,所以函數(shù)a變成:

function a(){
    let x=arguments.length <= 0 || arguments[0] === undefined ? undefined : arguments[0];
    let y=arguments.length <= 1 || arguments[1] === undefined ? undefined : arguments[1];
}  

所以在ES6中會(huì)有以下幾個(gè)問(wèn)題:

function a(x = y, y = 2) {
  return [x, y];
}

a(); // 報(bào)錯(cuò),給X賦值時(shí)y還未被let聲明。  



function a(x,y) {
  let x;//相當(dāng)于重復(fù)聲明,報(bào)錯(cuò)。
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • let 和 const 命令 let 命令 塊級(jí)作用域 const 命令 頂層對(duì)象的屬性 gl...
    安小明閱讀 1,047評(píng)論 0 0
  • let 命令 塊級(jí)作用域 const 命令 頂層對(duì)象的屬性 global 對(duì)象 let 命令 基本用法 ES6 新...
    嘉奇呦_nice閱讀 1,703評(píng)論 0 2
  • 一、ES6簡(jiǎn)介 ? 歷時(shí)將近6年的時(shí)間來(lái)制定的新 ECMAScript 標(biāo)準(zhǔn) ECMAScript 6(亦稱(chēng) ...
    一歲一枯榮_閱讀 6,212評(píng)論 8 25
  • 繪 | 雁字訣 上面這幾幅圖片,你能想到,其實(shí),我只需要學(xué)會(huì)畫(huà)一個(gè)圓嗎? 你是不是覺(jué)得,自己沒(méi)有繪畫(huà)天賦?沒(méi)有繪畫(huà)...
    Dayan往北飛閱讀 2,228評(píng)論 10 38
  • 01 周六中午,對(duì)門(mén)傳來(lái)爭(zhēng)吵聲。“我沒(méi)說(shuō)要買(mǎi)凈水機(jī),是你剛才說(shuō)試驗(yàn)安裝,看看我家是不是符合這個(gè)型號(hào)的?!笔青従邮煜?..
    安揚(yáng)育兒閱讀 488評(píng)論 3 2

友情鏈接更多精彩內(nèi)容