【前端17_JS】ES 6:新的變量聲明 let 、對象凍結、解構賦值、暫時性死區 TDZ、惰性求值、模板字符串


簡介

  • 2015年6月17日,ECMAScript 6發佈正式版本,即ECMAScript 2015。
  • ES6 是繼 ES5 之後的一次主要改進,ES6 增添了許多必要的特性,例如:模塊和類,以及一些實用特性,例如Maps、Sets、Promises、生成器(Generators)等。
  • 儘管 ES6 做了大量的更新,但是它依舊完全向後兼容以前的版本,標準化委員會決定避免由不兼容版本語言導致的“web體驗破碎”。結果是,所有老代碼都可以正常運行,整個過渡也顯得更爲平滑,但隨之而來的問題是,開發者們抱怨了多年的老問題依然存在。

let 聲明變量

let 是新的變量聲明

  • 如果聲明的位置是在代碼塊中,那麼變量只能在代碼塊裏有用
  • 代碼塊,類似於 iffor 循環 等等。
	if(true){
        let a = 1;
    }
    console.log(a);

    //Uncaught ReferenceError: a is not defined

變量不提升

不像 var ,這個沒有變量提升
所以,必須先聲明,再使用

	console.log(b);
    let b;

    //Uncaught ReferenceError: Cannot access 'b' before initialization

暫時性死區 TDZ

全稱:temporal dead zone

聲明變量之前不允許使用

	if(true){
        /*TDZ start*/
        typeof temp;
        let temp;/* TDZ end*/

        console.log(temp);
    }
    
	//Uncaught ReferenceError: Cannot access 'temp' before initialization
  • 注意 TDZ 的區域,從代碼塊開始,到定義完變量之後,這一小段是 TDZ,
  • 引申:在 es6 中 typeof 不是絕對安全了
	//多看代碼,加深理解
	var c = 1;
    function test() {
        console.log(c);
        if(true){
            //這個c只是在if中有效
            let c = 10;
        }
    }
    test()

    //1
	//跟上一個對比
	var c = 1;
    function test() {
        console.log(c);
        if(true){
            //這裏有變量提升
           var c = 10;
        }
    }
    test()

    //undefined
	//這個要注意一下
	var a = 1;
    function test() {
        console.log(a);
        
        //條件是false
        if(false){
            /*先進去if中探索一下是否有 var 聲明,然後再去判斷語句*/
            /*這個if在剛開始還是進去的,遇到var也還會提升,只是語句在執行的時候,沒有進入if*/
            var a = 10;
        }
    }
    test();
    
    //undefined
  • 這裏有個情況
	let x;
	//這把{x}當作了代碼塊,解決這個問題的話,整體加圓括號
    {x} = {x:1}
    console.log(x);
    //Uncaught SyntaxError: Unexpected token '='
	//解決方法
	let x;
    //{x} = {x:1}
    ({x} = {x:1});
    console.log(x);

    //1

const 靜態變量 (常量*)

有如下屬性

  • 不允許重複聲明
  • 聲明的時候賦值
  • 聲明之後不允許修改
  • let 的作用域一個德行,都是代碼塊裏有效

實質

  • const 實際上保證的並不是變量的值不得改動,而是變量指向的那個內存地址不得改動
  • 對於 簡單類型 的數據(數值,字符串,布爾值),存在 中,值就保存在變量指向的那個內存地址。
  • 對於 複雜對象(主要是對象和數組),變量指向的內存地址存在 中,保存的是指向,指向的數據怎麼變,它管不到

引申

  • 棧:大小固定,自動分配,能由系統自動釋放掉
  • 堆:可變大小,不能自動釋放掉

對象凍結

用到了 Object.freeze(); 方法

	const obj = Object.freeze(
        {name:"張三"}
    );
  • 建議前面寫上 const,因爲如果你這樣,之後也能改變指向,如果你用了 const,就改變不了了
	//用var,聲明不變的量,也不安全
	var obj = Object.freeze(
        {name:"張三"}
    );
    obj = {};
    console.log(obj);

    //{}
	//使用const聲明
	const obj = Object.freeze(
        {name:"張三"}
    );
    obj = {};
    console.log(obj);

    //Uncaught TypeError: Assignment to constant variable.
  • 凍結之後,如果修改的話,是不會報錯的,但是也不會修改
	const obj = Object.freeze(
	        {name:"張三"}
	    );
	    obj["name"] = "小子";
	    console.log(obj);
	
	    //{name: "張三"}


解構賦值

起步

  • 簡單的解構賦值如下
	let [a,b,c] = [1,2,3];
    console.log(a);
    console.log(b);
    console.log(c);

    //1
    //2
    //3
  • 也可以用來當作函數的實參、形參,而且 解構賦值 有個好處,可以傳 ""undefinednullfalse 這些東西。
	//例子1:普通給默認值的方法
	//如果你傳的值是undefined等,他是走默認值0的,而我們希望走的是undefined
	function test_bad(val) {
        val = val || 0;
        console.log(val);
    }
    test_bad("");
    test_bad(undefined);
    test_bad(null);
    test_bad(false);

    //0
    //0
    //0
    //0
	//例子1的對比,優化
	//如果你傳來的不是嚴格的 undefined,那麼就會走默認值
	function test_good([a,b,c = 0,d = 4,e]) {
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);

    }
    test_good([false,null,"",undefined,"undefined"]);

    //false
    //null
    //
    //4
    //undefined

…arr

先來一個例子,慢慢理解一下

  • ...arr 一定要保證是在後面,因爲它只能解析從某個地方到 數組尾部
	//不能這樣:let[...arr,a] = ["ar",2,3,4];
	
	let[a,...arr] = ["ar",2,3,4];
    console.log(a);
    console.log(arr);
    
    //ar
    //(3) [2, 3, 4]
  • 如果沒有值得話,就會生成一個空數組
	let[a,b,...arr] = ["ar"];
	    console.log(arr)
	    //Array(0)
  • 也可以遍歷字符串
  • 可以設置默認值,如果嚴格等於undefined,那麼就走默認值(底層是 ===
	//嚴格等於 undefined,走默認的值
	let [a = 100,b = "poi"] = [undefined];
    console.log(a);
    console.log(b);
    //100
    //poi
	
	//不嚴格等於 undefined ,走賦值
	let [a = 100,b = "poi"] = ["undefined"];
    console.log(a);
    console.log(b);
    //undefined
    //poi
	//再來一個引申
	var a = undefined;
    var b = "undefined";
    //0 == 1
    console.log(a == b);
    //兩等都不行了,三等就更沒戲了
    console.log(a === b);
    //false
    //false
  • 還能承接傳來的參數,這個叫做 rest
	function test(...arr) {
        console.log(arr);
    }
    test(1,2,3,4)

	//(4) [1, 2, 3, 4]

…[] 數組拓展運算符

  • 這個就相當於 rest 的逆運算,一個是聚合,一個是拆散,...[1,2,3] 會被拆成 1 2 3
	var f1 = (a,b,c,d) => {
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        
        //1
        //2
        //3
        //4
    };
    f1(1,...[2,3,4]);
  • 這個功能就很強大了,可以跟選擇器結合使用
<body>
        <div>1</div>
        <div>2</div>
        <div>3</div>
</body>
<script>
    console.log(...document.querySelectorAll("div"));
</script>

傳參

  • 而且與 rest 不同的是,可以不用放到最後
	//1.解析的時候和rest不同的是,可以不用放到最後
    function f1(a,b,c,d,e) {
        console.log(a,b,c,d,e);
    }
    //[2,3,4]放到了參數們的中間,而rest必須放到後面才能正常使用
    arr1 = [1,...[2,3,4],5];
    //es5傳參
    f1.apply(null,arr1);
    //1,2,3,4,5
    
	//es6
    f1(...arr1);
    //1,2,3,4,5

找最大值

	var arr1_1 = [10,2,4654,789,56,6,131,32,];

    //es5的寫法
    console.log(Math.max.apply(null,arr1_1));
    //4654
    
    //es6的寫法
    console.log(Math.max(...arr1_1));
    //4654

與三目運算符結合

	var x = 2;
    var arr2 = [
        ...(x == 1?[1,2,3]:[4,5,6]),
        "x"
    ];
    console.log(arr2);
    //(4) [4, 5, 6, "x"]

空的話,不會報錯,控制檯裏就沒有它的打印信息

	var arr3 = [];
    console.log(...arr3);

模擬深複製

	const a3 = [3,4,5];
    //2.模擬深複製
    const a4 = [...a3];
    console.log(a4);
    //(3) [3, 4, 5]

模擬 concat

	var arr3_1 = [1,2,3];
    var arr3_2 = [4,5,6];
    
    console.log(arr3_1.concat(arr3_2));
    //(6) [1, 2, 3, 4, 5, 6]
    
    console.log([...arr3_1,...arr3_2]);
    //(6) [1, 2, 3, 4, 5, 6]

結構解析

  • 對象解析當中根據 key 來解析
  • let {匹配模式:變量}
	let {c,a}  = {b:"6666",a:"555"};
    console.log(a);
    console.log(c);

    //555
    //undefined
  • 數組相當於一個特殊的對象,可以用 下標 當作 key 值去解析
	/*數組的結構解析*/
    var arr = ["dsada","ewq",'zxcvc',16,18,"135"];
    let {1:fir,[arr.length-1]:last} =  arr;
    console.log(fir);
    console.log(last);
    //ewq
    //135

詳細步驟

	//目的:我想解析shuai
    var obj = {
        foo:['ufo',{sss:"shuai"}]
    };
    /*結構解析*/
    /*第一步:等號左右類型要一樣*/
    let {} = obj;

    /*第二步:添加匹配模式foo*/
    let {foo} = obj;

    /*第三步,這個時候b就代表了對象,數組的話就不需要匹配模式,隨便一個符號佔着茅坑找位置就行*/
    let {foo:[a,b]} = obj

    /*第四步:把b變成括號,然後再用匹配模式sss,來進入對象中*/
    let {foo:[a,{sss}]} = obj;

    /*第五步:你可以給sss賦值變量l,然後輸出l就可以了*/
    let {foo:[a,{sss:l}]} = obj;
    console.log(l);
	//覺得你行了?來試試這個,少年,解析girl
	var sister = [{age:[18,{sex:"girl"}]}];    
  • 加深理解接着玩 ,console 也能解析
	/*console是個對象,他有log方法,我把log方法解析出來*/
    let {log} = console;
    log("111");

    //111
	/*對象 = 對象,把 math 對象中的屬性承接出來,放到 PI 中,因爲 PI 是屬性值,所以打印就好
    * 如果是函數體的話就給參數調用*/
    const {PI} = Math;
    console.log(PI);
	
	////3.141592653589793
	//let {匹配模式:變量}

    //默認是let {foo:foo} = {foo:"cszsdad"};
    let {foo:fooValue} = {foo:"cszsdad"};
    
    console.log(fooValue);
    
    //cszsdad
  • 結構解析也能分析繼承的
	Person.prototype.name = "lsl";
    function Person() {

    }
    var p = new Person();
    let {name:n} = p;
    console.log(n);
    
    //lsl
  • 理解了之後自己玩了一個比較瑟琴的
	//給你們答案,不唯一
	var sister = [{age:[18,{sex:"girl"}]}];   
	let [{age:[a,{sex:x}]}] = sister;
    console.log(x);

惰性求值

	function f() {
        throw new Error("this is error");
    }
    /*惰性求值*/
    /*如果有值得話,除了undefined,就一直不走默認的*/
    let [x = f()] = [1];
    console.log(x);
    //1
	function f() {
        throw new Error("this is error");
    }
    //這樣就走了默認的
    let [x = f()] = [undefined];
    /*let [x = f()] = [1];*/
    console.log(x);
    
    //Uncaught Error: this is error

模板字符串

  • 優點:不需要我們拼接變量(原生的不是得用 + 來拼接成很長的句子嘛)
  • 符號:`` (TAB上面的那個~)
  • 想在模板字符串中插入變量的話用 ${}
  • 還是函數調用的另一種形式
	//函數調用,括號變成``也可以
	alert `4`;
	//模板字符串的簡單使用
	const obj = {
       name:18,
       age:"xiaopang",
       habit:"sing",
   };
	var str = `my name is ${obj.name} ,age is ${a}`;
	console.log(str);
	
	//my name is 18 ,age is xiaopang
  • 如果你非要在模板字符串中打出 `` 這個符號,那麼可以用轉義字符 \
	//轉移字符
	var str1 = `\`\``;
    console.log(str1);
    
    //``
  • 這個還可以插標籤,可以進行變量的運算,注意寫法、還可以插入方法,而且還會 解析換行,你怎樣寫,就會在頁面上解析成相應的樣子,包括換行,空格。
	//綜合應用
	var x = 5;
    var arr = [1,2,3,4,5];
    //插入標籤,運算,arr.reverse()方法,對象引用
    $("#test").html(`
        <ul>
            <li style="font-size: ${x + 40}px;">1</li>
            <li>22\`\`</li>
            <li>${arr.reverse()}</li>
            <li>${obj.name + x}</li>
        </ul>
    `)

網頁裏是這樣的

  • 如果當作實參的話,字符串裏穿插變量,那麼形參中可以接到如下的東西
	var xx = 1;
    var yy = 2;
    var zz = 3;
    function show (a,b,c,d,e) {
        /*這個a是實參中所有字符串的字段,並放到數組中*/
        console.log(a);
        console.log(b);
        console.log(c);
        console.log(d);
        console.log(e);
    }
    show `this  ${xx}  is  ${yy} a ${zz}  iu`;
    //(4) ["this  ", "  is  ", " a ", "  iu", raw: Array(4)]
    //1
    //2
    //3
    //undefined
    
    
    function show1 (a,...arr) {
        console.log(a);
        console.log(arr);
    }
    /*如果變量放到了第一個,前面沒有字符串,那麼a[0]會被解析成空字符串*/
    show1 `${xx}  is  ${yy} a ${zz} this`;
    //["", "  is  ", " a ", " this", raw: Array(4)]
    //(3) [1, 2, 3]

	//解釋:
    /*最前面的和最後面的變量,在這裏是${xx}和${zz}*/
    //最前面的變量${xx},看它的前面,有字符串那麼就拿,如果沒有就會拿空
    //最後面的變量${zz},看他的後面,有字符串那麼就拿,如果沒有就會拿空

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章