var和let用法类似,let相对于var函数作用域引入块级作用域
{var a = 10;let b = 20;
}a // 10
b // b is not defined.
改进var变量提升带来的问题,引入暂时性死区概念,绑定所在区域,不会受外界影响
// var
console.log(foo); // 输出undifined
var foo = 2;// let
console.log(bar); // 报错 ReferenceError
let bar = 2;
var tmp = 123;
if(true){console.log(tmp) // ReferenceErrortypeof tmp; // ReferenceErrortmp = 'abc'; // ReferenceErrorlet tmp; // 绑定此区域,先于声明之前的使用和赋值会报错
}
不允许重复声明变量,不能在函数内部重新声明参数
// 报错
function func(){
let a = 10;
var a = 10;
}// 报错
function func(arg) {let arg;
}
func()// 不报错
function func(arg) {{let arg;}
}
func()
ES6的块级作用域, 是得变量不存在提升
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date();function f() {console.log(tmp);if (false) {var tmp = 'hello world';}
}f(); // undefined
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello';for (var i = 0; i < s.length; i++) {console.log(s[i]);
}console.log(i); // 5
上面代码中,变量i
只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
块级作用域代替了以前常用的匿名立即执行函数表达式(匿名 IIFE )
// IIFE写法
(function(){Var tmp = ...;
})();// 块级作用域写法
{let tmp = ...;
}
const 命令
const声明一个只读的常量。一旦声明,常量的值就不能改变。所以只声明不赋值会报错。
const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.
const和let一样都不存在变量提升,都不允许重复声明,都不可以在声明前使用。
const 的本质: const 实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址保存的数据不得改动,因为简单的数据类型,值就保存在指向的那个内存地址,所以相当于常量,但是对于复合类型的数据(对象和数组),变量指向的内存中地址,保存的只是指向实际数据的指针,const只能保证这个指针式固定的,但是它指向的数据结构是不是可变的,就完全不能控制了,因此,将一个对象声明为敞亮必须小心了。
const foo = {};
// foo添加属性
foo.prop = 123;
foo.prop // 123
// 将foo指向另一个对象,就会报错
foo = {}; // TypeError: 'foo' is read-onlyconst arr = [];
arr.push('Hello');
a.length = 0;
a = ['Dave'] // 报错,可以操作不能再赋值
如果想冻结对象本身,需要Object.freeze方法
const foo = Object.freeze({});
// 常规模式下,下面一行代码不起作用,
// 严格模式下,会报错 'use strict'
foo.prop = 123;
对象和对象的属性都冻结的函数,递归
var cosntantize = (obj)=>{Object.freeze(onj);Object.keys(obj).forEach((key,i)=>{if(typeof(obj[key]==='object'){cosntantize(obj[key]);})})
}
浏览器中指window对象,在Node中指global对象,ES5之中,顶层对象的属性与全局变量是等价的。
window.a = 1;
a //1
a = 2
window.a // 2
顶层对象的属性与全局变量挂钩,被认为是JacaScript语言设计的最大败笔,有几大弊端
1、没法在编译时就报出变量未声明的错误,只有在运行时才知道(全局变量可能是又顶层对象的属性创造,而属性创造是动态的)
2、程序会因为手写失误,不自觉创造一个全局变量
3、顶层对象的属性到处可以读写,不利于模块化编程
4、window是一个有实体概念的对象指的就是浏览器窗口对象,但是说顶层对象是有实体的对象是不合适的
ES6为了改变这一点,但是又兼顾兼容性,规定var和function声明的全局变量,依然是顶层对象的属性,另一方面规定let、const 、class命令声明的全局变量,不属于顶层对象的属性,从ES6开始,全局变量将逐渐与顶层对象属性脱钩。
var a = 1;
// 如果Node的REPL环境,可以写成global.a
// 或者this.a
window.a // 1
this.a // 1let b =1;
window.b // undifined
this.b // undifined
Javascript语言存在一个顶层对象,它提供全局环境(即全局作用域), 所有代码都是在这个谎精中运行,但是顶层对象在各种实现里面是不统一的
比如
为了同样的代码都能取到同样的顶层度喜庆,现在一般用this变量,但是有局限。
全局环境中,this会返回顶层对象,但是Node模块和ES6模块中,this返回的是当前的模块。
函数里面的this,如果函数不是做为对象的方法运行,而是单纯做为函数运行,this会执行顶层对象,但是,严格模式下,会返回undifined。
不管是严格模式,还是普通模式,new Function('return this')()
,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval
、new Function
这些方法都可能无法使用。
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。
// 方法一
(typeof window!=='undifined'? 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');
};
ES2020 在语言标准的层面,引入globalThis
作为顶层对象。也就是说,任何环境下,globalThis
都是存在的,都可以从它拿到顶层对象,指向全局环境下的this
。
垫片库global-this
模拟了这个提案,可以在所有环境拿到globalThis
本文发布于:2024-01-30 13:52:48,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170659397120458.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |