//let用法类似于var 但是声明的变量只在代码块中有效 注:只有在声明之后才能被使用,不同于var,不存在变量提升
{
let a =10;
var b = 11;
}
//a is not defined
//b 1
//const 声明一个只读的常量,一旦声明,常量的值就不能改变注:只有在声明之后才能被使用,不存在变量提升
const PI = 3.1415926;
//PI 3.1415926
PI = 3;
// TypeError:Assignment to constant variable
//const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心
const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only
//上面代码中,常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错
//上面代码中,常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错。
Object.freeze()
//Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
var obj = {
name:'abc',
age:14,
dsc:'this is aaa'
}
var obj_2 = obj;
obj_2.age = 16;
console.log(obj); //{name: "abc", age: 16, dsc: "this is aaa"}
var obj_3 = Object.freeze(obj);
obj_3.age = 20;
obj_3.data = 'sssssssss';
console.log(obj); //{name: "abc", age: 14, dsc: "this is aaa"}
//使用了Object.freeze() 方法,不可以操作原来的obj。
// 顶层对象的属性
// 顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。
window.a = 1;
a // 1
a = 2;
window.a // 2
// 上面代码中,顶层对象的属性赋值与全局变量的赋值,是同一件事。
// 顶层对象的属性是到处可以读写的,这非常不利于模块化编程。另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。
// ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。
var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
let b = 1;
window.b // undefined
// 上面代码中,全局变量a由var命令声明,所以它是顶层对象的属性;全局变量b由let命令声明,所以它不是顶层对象的属性,返回undefined。
// JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都是在这个环境中运行。但是,顶层对象在各种实现里面是不统一的。
// 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
// 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
// Node 里面,顶层对象是global,但其他环境都不支持。
// 同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。
// 全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
// 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
// 不管是严格模式,还是普通模式,new Function('return this')(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。
// 综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
// 方法一
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
// 方法二
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
// 现在有一个提案,在语言标准的层面,引入globalThis作为顶层对象。也就是说,任何环境下,globalThis都是存在的,都可以从它拿到顶层对象,指向全局环境下的this。
// 垫片库global-this模拟了这个提案,可以在所有环境拿到globalThis。