ES6 爲了保持兼容性,var 命令和 function 命令聲明的全局變量,依舊是頂層對象的屬性;es6
另外一方面規定,let 命令、const 命令、class 命令聲明的全局變量,不屬於 window 的屬性。瀏覽器
也就是說,從ES6開始,全局變量將逐步與頂層對象的屬性脫鉤安全
瀏覽器頂層對象指的是 window 對象ide
Node頂層對象指的是 global 對象,但其餘環境都不支持函數
window
對象應該有實體含義,指的是瀏覽器的窗口對象ui
爲了可以在各類環境,都能取到頂層對象,如今通常是使用 this變量。this
全局環境中,this 會返回頂層對象。可是,Node 模塊和 ES6 模塊中,this 返回的是當前模塊。
函數裏面的 this,若是函數不是做爲對象的方法運行,而是單純做爲函數運行,this 會指向頂層對象。
可是,嚴格模式下,這時 this 會返回 undefined。
無論是嚴格模式,仍是普通模式,new Function('return this')(),老是會返回全局對象。
可是,若是瀏覽器用了CSP(Content Security Policy,內容安全政策),那麼 eval、new Function 這些方法均可能沒法使用。spa
綜上所述,很難找到一種方法,能夠在全部狀況下,都取到頂層對象。下面是勉強能夠使用的方法code
var getGod = function () { if (typeof global !== 'undefined'){ return global; }; if (typeof window !== 'undefined'){ return window; }; if (typeof self !== 'undefined'){ return self; }; throw new Error('unable to locate global object'); }; var God = getGod();
如今有一個提案,在語言標準的層面,引入global做爲頂層對象。對象
也就是說,在全部環境下,global都是存在的,均可以從它拿到頂層對象。
墊片庫system.global模擬了這個提案,能夠在全部環境拿到global
// CommonJS的寫法 var global = require('system.global')(); // ES6模塊的寫法 import getGlobal from 'system.global'; const global = getGlobal();
參考: http://es6.ruanyifeng.com/#docs/let
ES6 聲明變量的六種方法
let age = 22;
// 報錯 function () { let a = 10; var a = 1; } // 報錯 function () { let a = 10; let a = 1; } function func(arg) { let arg; // 報錯 } function func(arg) { { let arg; // 不報錯 } }
做用域
"use strict";
if (true) { var v = 0; let l = 0; const c = 0; function f() { console.log('I am inside!'); }; }; console.log(v); // 0 console.log(l); // Uncaught ReferenceError: l is not defined console.log(c); // Uncaught ReferenceError: c is not defined f(); // Uncaught TypeError: f is not a function
變量 x 使用 let 命令聲明,因此在聲明以前,都屬於x的「死區」,只要用到該變量就會報錯。
所以,typeof 運行時就會拋出一個 Reference Error。
做爲比較,若是一個變量根本沒有被聲明,使用 typeof 反而不會報錯
在沒有 let 以前,typeof 運算符是百分之百安全的,永遠不會報錯。有了 let ,如今這一點不成立了
window.addEventListener("DOMContentLoaded", function(){ 'use strict';function bar(x = y, y = 2) { return [x, y]; } console.log(bar(1, 2)); // 正常: let x=1; let y=2; console.log(bar()); // 報錯 let x=y; /* y 的變量死區 */ let y=2; }, false);
if(true){ typeof x; // Reference Error let x; }
var tmp = 123; if (true) { tmp = 'abc'; // Reference Error let tmp; // }
let a = 123; if(true){ // 塊做用域 let a = 456; }; console.log(a); // 123
/**************************/ for(){} for(var in ){} switch(x){} while(1){}
// 三個按鍵 for(let i=0; i< btns.length; i++){ btn[i].onclick = function(){ alert(i+1); // 每次按鍵都會打印本身的索引 }; }; // let i =0 // let i =1 // let i =2
/**** <div id="test_box"> <div></div> <div></div> <div></div> </div> ****/ window.addEventListener("DOMContentLoaded", function(){ 'use strict'; var divs = document.getElementById("test_box").getElementsByTagName("div"); /* for(let i=0; i<divs.length; i++){ divs[i].onclick = function(){ console.log(i+1); }; }; 能夠理解成: 就至關於: ****/ function add1(){ let i=0; divs[i].onclick = function(){ console.log(i+1); // 1 }; }; function add2(){ let i=0; i += 1; divs[i].onclick = function(){ console.log(i+1); // 2 }; }; function add3(){ let i=0; i += 1; i += 1; divs[i].onclick = function(){ console.log(i+1); // 3 }; }; add1(); add2(); add3(); /**** 不能理解成下面這個樣子 function addEvent(){ let i=0; divs[i].onclick = function(){ console.log(i+1); // 3 }; i += 1; divs[i].onclick = function(){ console.log(i+1); // 3 }; i += 1; divs[i].onclick = function(){ console.log(i+1); // 3 }; }; ****/ }, false);
const PI = 3.1415926;
聲明一個常量,不可被更改
不會被預處理,不存在聲明提高
不能重複聲明 // Identifier 'a' has already been declared
在將一個 對象 聲明爲常量時,只能保證 這個常量永遠指向這個對象,而仍是可以操做這個對象的屬性
const foo = {}; // 爲 foo 添加一個屬性,能夠成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另外一個對象,就會報錯 foo = {}; // TypeError: "foo" is read-only
若是真的想 連對象的屬性都不可寫,則必須使用 Object.freeze()
除了將對象自己凍結,對象的屬性也應該凍結。
下面是一個將對象完全凍結的函數
function freezeObj(obj){ Object.freeze(obj); Object.keys(obj).forEach(function(attr){ if ( typeof obj[attr] === 'object' ) { freezeObj(obj[attr]); }; }); };