引用 ES6 规范作者 Allen Wirfs-Brock一条最近的推特:
变量提升是一个陈旧且令人困惑的术语。甚至在 ES6之前:变量提升的意思究竟是“提升至当前作用域顶部”还是“从嵌套的代码块中提升到最近的函数或脚本作用域中”?还是两者都有?
受 Allen 启发,本文提出了一种不同的方法来描述变量声明。
可以将声明分为两个方面:
下表总结了不同声明的方式如何处理上述两个方面。
“Duplicates”描述是否可以在同一作用域内声明两次。
“Global prop.”表示一个在 script 中的声明,当全局作用域中被执行时,是否会向全局对象添加属性。
TDZ 表示暂时性死区(稍后解释)。 函数声明在严格模式下是块作用域的(例如在模块内部),但在非严格模式下是函数作用域。
对于JavaScript,TC39 需要决定如果在声明之前访问其直接作用域中的常量会发生什么:
{
console.log(x); // 这里会发生什么?
const x;
}
主要有两种种情况:
第一种不会出现,因为 x 是一个常量,如果打印 undefined,在声明前和声明后它将拥有不同的值,x 就不是常量了。
let 和 const 都会出现第二种情况,就是会报错。进入变量作用域与执行声明之间的这段时间被称为该变量的 临时死区(TDZ):
以下代码说明了临时死区:
if (true) { // 进入 `tmp` 的作用域,TDZ 开始
// `tmp` 未被初始化:
assert.throws(() => (tmp = 'abc'), ReferenceError);
assert.throws(() => console.log(tmp), ReferenceError);
let tmp; // TDZ 结束
assert.equal(tmp, undefined);
}
下一个例子表明临时死区只是 暂时的 (与时间有关):
if (true) { // 进入 `myVar` 作用域,TDZ 开始
const func = () => {
console.log(myVar); // 稍后执行
};
// 我们在 TDZ 中:
// 访问 `myVar` 造成 `ReferenceError`
let myVar = 3; // TDZ 结束
func(); // OK,在 TDZ 外调用
}
即使 func() 位于myVar声明之前使用 myVar 变量,但我们也可以调用func(),前提是必须等到myVar的临时死区结束。
函数声明总是在进入它的作用域时执行,不管它位于作用域的什么位置。这使得能够在函数foo()声明之前调用它:
assert.equal(foo(), 123); // ok,相等
function foo() { return 123; }
提前激活 foo()意味着楼上的代码等价于
function foo() { return 123; }
assert.equal(foo(), 123);
如果用 const 或 let 声明一个函数,它就不会被提前激活:在下面的例子中,你只能在 bar() 声明后调用它。
assert.throws(
() => bar(), // 声明前
ReferenceError);
const bar = () => { return 123; };
assert.equal(bar(), 123); // 声明后
即使函数g()没有提前激活,也可以被前面的函数 f()(在同一作用域内)调用 - 只要遵守以下规则:f() 必须在声明 g() 之后调用
const f = () => g();
const g = () => 123;
// g() 声明后调用 f():
assert.equal(f(), 123);
模块中的函数通常在模块执行完后调用。 因此,在模块中,很少需要担心函数的顺序。
最后,注意提前激活是怎样自动执行以维持上述规则的:当进入一个作用域时,在任何函数被调用前,所有的函数声明都会被先执行。
如果依赖于提前激活机制,在函数声明之前调用函数,那么需要注意的是它不会访问未提前激活的变量。如下:
funcDecl();
const MY_STR = 'abc';
function funcDecl() {
console.log(MY_STR)
}
上述会报错:
如果你在 MY_STR 声明之后调用 funcDecl() 就不会有问题。
我们已经看到提前激活有一个陷阱,你可以在不使用它的情况下获得大部分好处。因此,最好避免提前激活。但我对此说法并非十分认同,如前所述,我经常使用函数声明,因为我喜欢它们的语法。
类声明不会提前激活:
assert.throws(
() => new MyClass(),
ReferenceError);
class MyClass {}
assert.equal(new MyClass() instanceof MyClass, true);
这是为什么? 考虑以下类声明:
class MyClass extends Object {}
extends是可选的,它的操作数是一个表达式。 因此,您可以这样做:
const identity = x => x;
class MyClass extends identity(Object) {}
计算这样的表达式必须在它被引用的地方完成,其它行为都会使人困惑。这解释了为什么类声明不提前激活。
var是在const和let之前声明变量的一种较老的方法。考虑下面的var声明。
var x = 123;
这个声明包含两个部分:
以下代码演示了 var :
function f() {
// 部分提前激活:
assert.equal(x, undefined);
if (true) {
var x = 123;
// 赋值已经执行
assert.equal(x, 123);
}
// 作用域为函数作用域,非块级作用域。
assert.equal(x, 123);
}
本文的目的主要是展示CSS变量是如何工作的。随着Web应用程序变得越来越大,CSS变得越来越大,越来越多,而且很多时候都很乱,在良好的上下文中使用CSS变量,为您提供重用和轻松更改重复出现的CSS属性的机制。
Sass和Less这样的预处理器,让我们的CSS代码保持良好的结构和可维护性。像变量、混合(mixins)、循环控制等特性,增强了动态编写CSS的能力,从而减少重复代码,也加快了我们开发速度。
原生css 中变量的使用,这个重要的 CSS 新功能,所有主要浏览器已经都支持了。本文全面介绍如何使用它,你会发现原生 CSS 从此变得异常强大。声明变量的时候,变量名前面要加两根连词线(--),var()函数用于读取变量。
JavaScript中var、let、const区别?js中let和const都是es5版本新的命名规范,在此之前定定义一个变量只能用var。我们可以把let和const看做是为了弥补var的一些不足而新设计出来的
引擎在读取js代码的过程中,分为两步。第一个步骤是整个js代码的解析读取,第二个步骤是执行。在JS代码执行之前,浏览器的解析器在遇到 var 变量名 和function 整个函数 提升到当前作用域的最前面。
很早直接就了解到CSS变量相关的内容,奈何之前使用价值不高(很多主流浏览器不兼容),最近发现主流浏览器都已经支持了这一变化,CSS变量就像JS的变量,每个类名或者花括号就像一个function,里面的变量只有上下文以内可以获取,这就让CSS有了更多可能性。
var是全局声明,let是块级作用的,只适用于当前代码块;var变量会发生变量提升,let则不会进行变量提升;var 会造成重复赋值,循环里的赋值可能会造成变量泄露至全局
解构赋值官方解释:按照一定的模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。变量的解构赋值就是一种写法,掌握了这种写法可以让我们在书写 javascript 代码时可以更加的简单,迅捷。
JS中的变量是保存在栈内存中的:1.基本数据类型的值直接在栈内存中存储;2.值与值之间是独立存在的,修改一个变量不会影响其他变量;对象是保存到堆内存中的,每创建一个新的对象
这篇文章总结七种办法来交换a和b的变量值 。最最最简单的办法就是使用一个临时变量了 ,最后我的方案是利用了ES6的解构赋值语法 ,它允许我们提取数组和对象的值,对变量进行赋值
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!