這裏主要介紹let和const的使用方法閉包
介紹兩種新的聲明對象的方法以前,先介紹ES6中新增的塊級做用域app
能夠簡單理解爲,用一對花括號括起來的區域即爲塊級做用域,例如for、if、switch裏的花括號,能夠嵌套ide
若是在全局環境下,默認也是一個塊級做用域,不過這個塊比較特殊,也就是不存在離開塊級做用域的問題函數
但建立對象時的一對花括號不算塊級做用域spa
子級塊級做用域能夠訪問到父級塊級做用域中的變量3d
特別注意,for語句中的()也是一個塊級做用域,然後面的{}則是()的子級的塊級做用域code
也就是說,能夠在for語句的執行語句塊中,訪問到for語句()裏用let聲明的變量,而出了for語句則沒法訪問該變量對象
上面也介紹了一些let的使用方法和特點,即:blog
1.做用於塊級做用域中遞歸
2.能夠被嵌套於其內部的子級的塊級做用域訪問到
此外,let和var兩種聲明方式還有如下的區別:
使用var能夠在同一塊級做用域中屢次聲明同名的變量,且再次聲明不賦值時,變量的值不變
而使用let,只能夠在同一塊級做用域中聲明一次同名變量,再次聲明就會報錯,在不一樣的塊級做用域中不存在該問題
let聲明後沒有賦值,默認該變量值爲undefined
let聲明的變量不會被有聲明提早的現象,必須在聲明後再調用,不然報錯
ES6中,let聲明的同名變量在聲明時產生一個封閉的做用域,其如下的子級塊級做用域沒法訪問到該變量,這個現象即暫存死區
能夠利用let聲明的塊級做用域,形成和閉包一樣的效果
for(let i=1;i<=10;i++){ var btn = document.createElement("button"); btn.innerText = i; btn.onclick = function(){ console.log(i); } document.body.appendChild(btn); }
ES6中新增的另外一種聲明方法爲const,能夠用來聲明常量
這裏的常量若是是基本類型,其值聲明後不可改變
若是是引用類型,則能夠修改內部的屬性、方法,只要不修改其變量名指向的引用類型地址便可
此外,const還和let有衆多相同的特性,例如:
1.同一塊級做用域中,不可重複聲明
2.沒有變量提高(沒有預解析)
3.只在當前的塊級做用域中能夠被訪問到
若是用const聲明引用類型,其屬性值是能夠改變甚至添加的
若是不但願屬性值和屬性名改變,也不但願擴充新的屬性名和屬性值,須要用Object.freeze()方法
ES6中提供了const來聲明常量,那ES6以前又是如何聲明常量的呢?
Object對象的seal方法,可讓聲明過的對象沒法擴展,即沒法添加新的屬性/方法,但能夠修改已有的屬性值
defineProperty方法能夠傳入三個參數:要修改的對象,要修改的屬性名,要修改的屬性值
其中要修改的屬性值能夠設置其value(值)以及writable(是否可寫),注意writable的屬性設置是不可逆的(即後續沒法再次從新設置)
綜上能夠發現,Object對象的seal方法和defineProperty方法加起來才實現freeze方法(即對象屬性不可擴展,同時對象屬性不可更改)
用以上的seal和defineProperty方法,來封裝一個同freeze功能相同的方法
注意這裏須要考慮到對象內部嵌套對象的可能性,須要用遞歸
//模擬freeze方法 //思路:傳入一個對象,先遍歷對象中的全部屬性,讓其每一個屬性的written都變成false //最後對整個對象用seal方法,讓對象不可擴展 function frozen(obj){ //遍歷整個對象 for(let i in obj){ //若是該屬性值是對象,用遞歸,繼續讓其沒法擴展和沒法修改 //修復函數類型能夠被修改的bug if(obj[i] instanceof Object && typeof obj[i] != "function"){ frozen(obj[i]); } //若是屬性值不是對象,則設置其不可更改 else{ //須要明確屬性值不是原型鏈上的 if(obj.hasOwnProperty(i)){ Object.defineProperty(obj,i,{ writable:false }) } } } //最後對整個對象用seal讓其不可擴展 Object.seal(obj); } var xm = { age:18, name:"xiaoming", language:{ chinese:"fluent", english:"master" }, say:function(){ console.log("hello"); } } frozen(xm);