是的,有一些差异,尽管实际上它们通常并不大。
还有第四种方法,从ES2015(ES6)开始,还有另外两种方法。我在最后添加了第四种方式,但是在#1之后插入了ES2015方式(您会看到原因),因此我们有:
var a = 0; // 1let a = 0; // 1.1 (new with ES2015)const a = 0; // 1.2 (new with ES2015)a = 0; // 2window.a = 0; // 3this.a = 0; // 4
这些陈述解释了
#1var a = 0;
这将创建一个全局变量,该变量也是全局对象的属性,我们可以像
window在浏览器上一样(或通过
this非严格代码通过全局作用域访问)来访问它。与其他某些属性不同,该属性无法通过删除
delete。
用规范的术语来说,它在全局环境的对象EnvironmentRecord_上创建一个标识符绑定。这使它成为全局对象的属性,因为全局对象是全局环境对象环境记录的标识符绑定所在的位置。这就是为什么该属性不可删除的原因:它不仅是一个简单的属性,还是一个标识符绑定。
绑定(变量)是在第一行代码运行之前定义的(请参见
var下面的“何时发生”)。
请注意,在IE8和更早版本上,on上创建的属性
window不可 枚举
(不会显示在
for..in语句中)。在IE9,Chrome,Firefox和Opera中,它是枚举的。
#1.1let a = 0;
这将创建一个 不是 全局对象属性的全局变量。从ES2015开始这是新事物。
用规范术语来说,它在声明性环境记录上为全局环境而不是对象环境记录创建一个标识符绑定。全球环境是具有开裂环境记录,一个对所有旧的东西就是那张在全局对象(独特的 对象
为所有新的东西,环境记录),另一个(
let,
const,和所创造的功能
class)不继续使用全局对象。
绑定是在其封闭块中的任何分步代码执行之前创建的(在这种情况下,在任何全局代码运行之前),但是在分步执行到达该语句之前,它无法以任何方式
访问
let。一旦执行到达
let语句,就可以访问该变量。(见“当
let和
const发生”的。)
#1.2const a = 0;
创建一个全局常量,它不是全局对象的属性。
const完全一样,
let除了必须提供一个初始化程序(
=value一部分),并且一旦创建常量就无法更改其值。在幕后,这很像,
let但是在标识符绑定上带有一个标志,表明其值无法更改。使用
const可以为您做三件事:
- 如果您尝试分配给常量,则使其成为解析时错误。
- 记录其对于其他程序员的不变性。
- 让Javascript引擎在不会更改的基础上进行优化。
#2a = 0;
这将在全局对象上 隐式 创建一个属性。由于它是普通属性,因此可以将其删除。我建议您 不
要这样做,以后再读您的代码的人可能会不清楚。如果使用ES5的严格模式,则执行此操作(将其分配给不存在的变量)是错误的。这是使用严格模式的几种原因之一。
有趣的是,再次在IE8和更早版本上,创建的属性不可 枚举 (不会显示在
for..in语句中)。这很奇怪,特别是在下面的#3中。
#3window.a = 0;
这将使用
window引用全局对象的全局对象(在浏览器上;某些非浏览器环境具有等效的全局变量,例如
global在NodeJS上)在全局对象上显式创建一个属性。由于它是普通属性,因此可以将其删除。
在IE8和更早版本以及我尝试过的所有其他浏览器上,此属性 都是 可枚举的。
#4this.a = 0;
就像#3一样,除了我们通过引用全局对象
this而不是引用global
window。但是,这在严格模式下将不起作用,因为在严格模式下,全局代码
this没有对全局对象的引用(而是具有值
undefined)。
删除属性
“删除”或“删除”是什么意思
a?正是这样:通过
delete关键字完全删除属性:
window.a = 0;display("'a' in window? " + ('a' in window)); // displays "true"delete window.a;display("'a' in window? " + ('a' in window)); // displays "false"delete完全从对象中删除属性。你不能做到这一点与特性加入到
window通过间接
var时,
delete要么悄悄地忽略或抛出一个异常(取决于Javascript实现,以及是否你在严格模式)。
警告
:IE8再次出现(可能是更早的版本,而IE9-IE11处于损坏的“兼容性”模式):
window即使您允许,它也不允许您删除对象的属性。更糟糕的是,尝试时会引发异常(在IE8和其他浏览器中尝试此实验)。因此,从
window对象中删除时,您必须具有防御性:
try { delete window.prop;}catch (e) { window.prop = undefined;}这会尝试删除该属性,如果引发异常,它将做第二件事,并将属性设置为
undefined。
这 仅
适用于该
window对象,并且仅(据我所知)适用于IE8和更早的版本(或处于“兼容”模式的IE9-IE11)。其他浏览器可以删除
window属性,但要遵守上述规则。
何时var
发生
通过该
var语句定义的变量是在运行上下文中的任何逐步代码运行之前创建的,因此该属性早于该
var语句存在。
这可能会造成混淆,所以让我们看一下:
display("foo in window? " + ('foo' in window)); // displays "true"display("window.foo = " + window.foo); // displays "undefined"display("bar in window? " + ('bar' in window)); // displays "false"display("window.bar = " + window.bar); // displays "undefined"var foo = "f";bar = "b";display("foo in window? " + ('foo' in window)); // displays "true"display("window.foo = " + window.foo); // displays "f"display("bar in window? " + ('bar' in window)); // displays "true"display("window.bar = " + window.bar); // displays "b"现场示例:
display("foo in window? " + ('foo' in window)); // displays "true"display("window.foo = " + window.foo); // displays "undefined"display("bar in window? " + ('bar' in window)); // displays "false"display("window.bar = " + window.bar); // displays "undefined"var foo = "f";bar = "b";display("foo in window? " + ('foo' in window)); // displays "true"display("window.foo = " + window.foo); // displays "f"display("bar in window? " + ('bar' in window)); // displays "true"display("window.bar = " + window.bar); // displays "b"function display(msg) { var p = document.createElement('p'); p.innerHTML = msg; document.body.appendChild(p);}如您所见,符号
foo在第一行之前定义,但符号未定义
bar。该
var foo ="f";语句所在的地方实际上有两件事:定义符号,它发生在代码的第一行运行之前;并对该符号进行赋值,该操作会在分步流程中的直线处发生。这被称为“
var提升”,因为
varfoo零件已移动(“提升”)到示波器的顶部,但
foo = "f"零件仍保留在其原始位置。
当let
和const
发生
let并且在几个方面
const有所不同
var。与该问题相关的方式是,尽管它们定义的绑定是在任何分步代码运行之前创建的,但是直到到达or
语句之后,才能访问该绑定。
let``const
因此,在运行时:
display(a); // undefinedvar a = 0;display(a); // 0
这将引发错误:
display(a); // ReferenceError: a is not definedlet a = 0;display(a);
let与
const区别的其他两种方式与
var问题并不真正相关,分别是:
var
始终适用于整个执行上下文(整个全局代码,或者贯穿在它出现的功能函数代码),但let
并const
仅在适用 块 在那里出现。也就是说,var
具有功能(或全球)的范围,但let
并const
有块范围。var a
在相同的上下文中重复是没有害处的,但是如果您有let a
(或const a
),则具有另一个let a
或aconst a
或avar a
是语法错误。
这是一个示例,该示例演示了该操作
let并
const在该块中的任何代码运行之前立即在其块中生效,但是直到
letor
const语句才能访问:
var a = 0;console.log(a);if (true){ console.log(a); // ReferenceError: a is not defined let a = 1; console.log(a);}请注意,第二个
console.log失败,而不是
a从块外部访问。
离题:避免使全局对象混乱(window
)
该
window对象的属性变得非常混乱。只要有可能,强烈建议不要增加混乱。而是将符号包装在一个小包装中,并将最多一个符号导出到
window对象。(我经常不将任何符号导出到该
window对象。)您可以使用函数包含所有代码以包含符号,并且如果您愿意,该函数可以是匿名的:
(function() { var a = 0; // `a` is NOT a property of `window` now function foo() { alert(a); // alerts "0", because `foo` can access `a` }})();在该示例中,我们定义一个函数并立即执行它(
()最后是)。
以这种方式使用的函数通常称为作用域函数。在作用域函数定义的,因为他们是作用域函数可以访问的变量中定义的函数关闭了数据



