let const關鍵字定義變數、塊作用域
阿新 • • 發佈:2018-11-11
let 宣告的變數只能在它所在的程式碼中有效
{
let a=10;
var b=1;
}
console.log(a);
console.log(b);
for迴圈 中let變數
var a=[]; for(let i=0; i< 10; i++){ //每一次迴圈的變數i其實都是一個新的變數 //for迴圈的一個特別之處,就是設定迴圈變數的那部分是一個父作用域,而迴圈體內部是一個單獨的子作用域。 a[i] = function () { console.log(i); }; } a[6](); a[5](); // console.dir(a[5]); // console.dir(a[6]);
函式內部的變數i與迴圈變數i不在同一個作用域,有各自單獨的作用域
for(let i=0; i< 3;i++){
let i = 'abc';
console.log(i);
}
//上面的例子證明了: 函式內部的變數i與迴圈變數i不在同一個作用域,有各自單獨的作用域。
//let 宣告的變數不存在"變數提升"! console.log(foo); var foo = 2; //let的情況 //console.log(bar); //報錯 bar is not defined let bar = 2;
暫時性死區TDZ temporal dead zone
好習慣:在使用變數之前一定要先宣告!
//暫時性死區TDZ temporal dead zone TDZ var tmp = 123; if(true){ //TDZ開始 //tmp = 'abc'; //ReferenceError 報錯 //TDZ結束 let tmp; } //ES6規定,如果區塊中存在let 和const命令,這個區塊對這些命令宣告的變數,一開始就形成了封閉作用域,凡是在宣告之前就使用這些變數,就會報錯。 //"暫時性死區"也意味著typeof不再是一個百分之百安全的操作 typeof x; let x; //在沒有let 之前,typeof運算子是百分之百安全的,現在不成立了。 //所以呢, 好的習慣是:在使用變數前一定要先宣告!!! function bar(x=2, y=x) { //function bar(x=y, y=2) { //報錯了y未定義 return [x,y]; } bar(); //ES6 規定暫時性死區; let, const語句不出現變數提升
不允許重複宣告
//不允許重複宣告; 不允許重複宣告
function func() {
let a = 10;
var a = 1;
}
func();
function func() {
let a = 10;
let a = 1;
}
func(); //呼叫就報錯
//不能在函式內部重新宣告引數
function func(arg) {
let arg; //報錯
}
function func(arg) {
{
let arg; //不報錯
}
}
塊級作用域
ES5 只有全域性作用域和函式作用域,沒有塊級作用域,會出現場景
一: 內層變數可能覆蓋外層變數
//一: 內層變數可能覆蓋外層變數
var tmp = new Date();
function f(){
console.log(tmp);
//if(false){
if(true){
console.log('b:',b);
//var tmp = 'hello world';
let tmp = 'hello world';
var b=3;
}
console.log(tmp);
console.log('b:',b);
}
f();
//用來計數的迴圈變數洩露為全域性變數。
var s = 'hello';
for(var i =0; i< s.length; i++){
console.log(s[i]);
}
console.log(i);
ES6塊級作用域
function f1() { //let n = 5; var n = 5; if(true){ let n = 10; //var n = 10; } console.log(n); //5 } f1();
ES6允許作用域任意巢狀 外層作用域無法讀取內層作用域的變數 內層作用域可以定義外層作用域的同名變數 {{{{ let insane = 'Hello world'; {let insane = 'Hello'} }}}}
塊級作用域的出現,使得廣泛應用的立即執行函式表示式不再必要 (function () { var tmp = "..."; })(); //塊級作用域寫法 { let tmp = "..." }
ES6中規定塊級作用域中,可以宣告函式,函式的行為類似於let ,在塊級作用域外不可引用 實際上ES6瀏覽器中://node 中也是這樣 --允許在塊級作用域內宣告函式 ---函式宣告類似於var ,即會提升到全域性作用域或函式作用域的頭部 ---同時,函式宣告還會提升到所在的塊級作用域的頭部
//所以以下會報錯
function f() {
console.log('I am outside!');
}
(function () {
console.log(f);
console.log(typeof f);
console.dir(f);
//if(false){
if(true){
//重複宣告一次函式f
// function f() { //註釋掉看看
// console.log('I am inside!')
// }
}
f();
}());
考慮到環境導致的行為差異太大,應該避免在塊級作用域內宣告函式,如果確實需要,應該寫成函式表示式。!
//小細節,如果想在塊級作用下宣告函式,必須有大括號;不重要的知識點
const
宣告一個只讀的常量,一旦宣告,常量的值就不能改變
const 一旦宣告,就必須馬上初始化
const foo=123;
if(true){ const MAX = 5; } //console.log(MAX) // 報錯 MAX is not defined 注意, const宣告的常量也是不提升,同樣存在暫時性死驅,只能在宣告的位置後面使用。 const 宣告的常量,也與let 一樣不可重複宣告 var message = "Hello!"; let age = 25; //以下兩行都會報錯 //const message = "Goodbye!"; //const age = 30;
const 本質 只能保證 指向的地址是固定的, ;簡單的型別資料(數值,字串,布林值)就儲存在變數指向的那個記憶體地址,因此等於常量; const foo = {}; foo.prop = 123; foo.prop //將foo指向另一個物件就會報錯 //foo = {} const a = []; a.push('hello'); //可執行 a.length = 0; //可執行 //a = ['Dave']; //報錯
確實想把物件凍結,怎麼做?
const foo = Object.freeze({name: 'zhaosi', age : 29, order :{}}); foo.prop = 123; //不起作用; 嚴格模式下,該行會報錯。 console.log(foo); foo.age = 40; //不可修改; 不起作用,也不報錯 console.log(foo); foo.order.num = 3; //還是能修改的,還是不徹底的呀! console.log(foo); //{ name: 'zhaosi', age: 29, order: { num: 3 } }
徹底凍結該怎麼做?
//寫一個凍結函式
var constantize = (obj) =>{
Object.freeze(obj);
Object.keys(obj).forEach((key, i) => {
if(typeof obj[key] === 'object'){
console.log('free');
constantize(obj[key]);
}
})
}
var dongjie = {name : 'liang', age : 28, info :{num : 3}}
dongjie.info.num =5;
constantize(dongjie);
//Object.freeze(dongjie);
dongjie.info.num = 8; //怎麼沒凍住 info呢?
dongjie.age = 22;
console.log(dongjie);
ES6宣告變數的六種方式 //var function let const import class 頂層物件的屬性 在瀏覽器環境中指的是 window 物件; Node 指的是 global 物件; ES5 中 頂層物件 ==== 全域性變數 ES6中 var function 宣告的的全域性變數, 依舊是頂層物件的屬性; let , const , class 宣告的全部變數不屬於頂層物件的屬性。 // var a = 1; //console.log(global.a); //undefined node 中 console.log(window.a); //1 瀏覽器 let b = 1; //console.log(global.b); //undefined node中 console.log(window.b); //undefined 瀏覽器
// //global 物件
var getGlobal = function () {
if(typeof self !== 'undefined'){
return self;
}
if(typeof window !== 'undefined'){
return window;
}
if(typeof global !== 'undefined'){
return global;
}
}
console.log(getGlobal());
參考: http://es6.ruanyifeng.com/#docs/let