一、块级作用域

  1、为什么需要块级作用域?

  ES5中只有全局作用域和函数作用域,带来很多不合理的场景。

  (1)内层变量可能会覆盖外层变量;   

var tem = new Date();
function f(){
console.log(tmp);
if(false) {
var tmp = "hello world";
}
}
f(); //undefined

  变量提升导致了内层的tmp变量覆盖了外层的tmp变量。

  (2)用来计数的循环变量泄露为全局变量;

var s = "hello";
for(var i=0; i<s.length; i++) {
console.log(s[i]);
}
console.log(i); //

  2、ES6的块级作用域:

  (1)let为JavaScript新增了块级作用域;外层代码不受内层代码的影响。

function f() {
let n=5;
if(true) { let n=10; }
console.log(n); //5
}

  (2)ES6允许块级作用域任意嵌套;

{{{
{let insane = "hello world"}
console.log(insane); // 报错
}}}

  (3)内层作用域可以定义外层作用域的同名变量;

{{{
{let insane = "hello world"}
let insane = "hello world"
}}}

  (4)块级作用域 与 函数声明;

  函数本身的作用域在其所在的块级作用域之内;

function f() { console.log('I am outside!') }
(function () {
if(false) {
function f() { console.log('I am inside!') } // 重复声明一次函数f
}
f();
}());

  上述代码在ES5中运行,会得到 I am inside!   因为ES5 存在变量声明提升,不管进不进入if代码,在if内声明的函数f会被提升到当前作用域的顶部 ;

// ES5 环境
function f() { console.log('I am outside!'); }
(function () {
function f() { console.log('I am inside!'); } //提升到当前作用域的顶部
if (false) {
}
f();
}());

  但是在ES6中运行,会得到 I am outside!  因为ES6 块级作用域内声明的函数类似于let,对作用域之外没有影响。

  但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,!!!!!

  ES6 在附录 B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
    1、允许在块级作用域内声明函数。
    2、函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
    3、同时,函数声明还会提升到所在的块级作用域的头部。
  注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。
 
// 浏览器的 ES6 环境
function f() { console.log('I am outside!'); }
(function () {
var f = undefined;
if (false) {
function f() { console.log('I am inside!'); }
}
f();
}());
// Uncaught TypeError: f is not a function

  因此,考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。

二、let 命令

  1、仅在块级作用域内有效; 【for循环的计数器 很适合用let命令】

  let 命令用于声明变量, 与var类似, 但是所声明的变量只在let命令的代码块内有效,不受外部影响。

{
let a = 10;
var b = 20;
}
a //a is not defined
b //20

  2、不存在变量提升;变量一定在声明后使用,否则会报错。

console.log(foo);   //报错
let foo = 5;

  3、暂时性死区;

  在代码块内,使用let命令声明变量之前,该变量都是不可用的,语法上称为暂时性死区(temporal dead zone 简称TDZ)

if (true) {
// TDZ开始
tmp = 'abc'; // ReferenceError
console.log(tmp); // ReferenceError
let tmp; // TDZ结束 console.log(tmp); // undefined
tmp = 123;
console.log(tmp); //
}

  暂时性死区的本质:只要已进入当前作用域,变量就已经存在了,但是不可获取;只有等到声明变量的那一行代码出现,就可以获取和使用该变量。

  以下是一些比较隐蔽的“死区”:

function bar (x=y, y=2) {
return [x,y];
}
bar(); // 报错 此时x的默认值为参数y,而y此时还没有声明,属于“死区”
function bar (x=2, y=x) {
return [x,y];
}
bar(); //[2,2]

  4、不允许重复声明;

//报错
function(){
let a=1;
var a=2;
}
//报错
function(){
let b=1;
let b=2;
}
//报错
function fun(arg){
   let arg; //报错 不能再函数内部重新声明参数
}

三、const命令

  1、const用来声明常量, 一旦声明其值就不会改变;

const PI = 3.1415;
PI // 3.1415
PI = 3;
// TypeError: Assignment to constant variable.

  2、const一旦声明就必须立即初始化;

const foo;
// SyntaxError: Missing initializer in const declaration

  3、const只在声明所在的块级作用域内有效;

  4、const声明的常量也不会提升,同样存在暂时性死区,只能先声明后使用;

  5、const也不可以重复声明常量;

  6、const本质:

    const实际保证的并不是变量的值不能改动,而是变量指向的那个内存地址不能改动。

    对于简单数据类型(数字,字符串,布尔值),值就保存在变量指向的那个内存地址,因此等同于常量;

    对于复合类型的数据(对象,数组),变量指向的内存地址,const只能保证这个地址是不变的,至于它指向的数据结构是不是可变就不能控制了。

const foo = {};
// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123
// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

  7、若想冻结对象,应该使用object.freeze方法;

const foo = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

  8、冻结对象本身以及对象属性:

var constantize = (obj) => {
Object.freeze(obj);
Object.keys(obj).forEach( (key, value)=> {
if( typeof obj[key] === 'object' ) {
constantize( obj[key] ); // 递归
}
} )
}

  9、ES6声明变量的六种方法:

    ES5提供了两种: var命令 、function命令

    ES6新增了四种: let命令、 const命令、 import命令、 class命令

四、全局对象的属性

  全局对象 又称顶层对象,在浏览器环境指的是window对象, 在Node.js中指的是global对象。

  在ES5中,全局对象的属性 和 全局变量是等价的;

window.a = 9;
a // b=6;
window.b //

  ES6对此做了新的规定:

   1、考虑兼容性,var和function声明的全局变量 依旧是全局对象的属性;

   2、let、const、class 声明的全局变量 不属于全局对象的属性;

var a = 1;
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // let b = 1;
window.b // undefined

五、全局对象(顶层对象)的扩展:

  ES5的顶层对象,在各种实现里是不统一的:

    浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。

    浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。

    Node 里面,顶层对象是global,但其他环境都不支持。

下面有两种勉强的方法,使同一段代码能够在各种环境,都能取到顶层对象:

//方法一:
( typeof window != 'undefined'
? window
: ( typeof process === 'object' &&
tyoeof 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');
}

ES6标准入门 第二章:块级作用域 以及 let和const命令的更多相关文章

  1. ES6入门一:块级作用域(let&const)、spread展开、rest收集

    let声明 const声明 块级作用域 spread/rest 一.let声明与块作用域 在ES6之前,JavaScript中的作用域基本单元就是function.现在有了let就可以创建任意块的声明 ...

  2. 关于阮大神的es6标准入门第一章

    题记:之前在10月份的时候写过阮大神的es6的第一章,但是由于那段时间项目组的动荡,所以也没有什么后续,导致我现在对es6基本都忘的差不多了,不过,现在换了新公司,最近也没什么任务,所以现在开始重新写 ...

  3. ES6标准入门 第一章:简介

    ECMAScript 6 是JavaScript 语言的下一代标准:发布于2015年,又称为ECMAScript 2015. ECMAScript 与 JavaScript 的关系:前者是后者的规范, ...

  4. 12.24 ES6浅谈--块级作用域,let

    第一部分:ES6新增了块级作用域,let关键字用于声明变量,相较于var而言,let关键字不存在声明提前. 1.ES6真正的出现了块级作用域,使用双花括号括住并在其中用let声明变量,会存在暂时性死区 ...

  5. ECMAScript概述及浅谈const,let与块级作用域

    ECMAScript可以看作javascript的标准规范,实际上javascript是ECMAScript的一门脚本语言,ECMAScript只提供了最基本的语言JavaScript对ECMAScr ...

  6. 《浏览器工作原理与实践》<09>块级作用域:var缺陷以及为什么要引入let和const?

    在前面我们已经讲解了 JavaScript 中变量提升的相关内容,正是由于 JavaScript 存在变量提升这种特性,从而导致了很多与直觉不符的代码,这也是 JavaScript 的一个重要设计缺陷 ...

  7. 《ES6标准入门》(阮一峰)--2.let 和 const 命令

    1.let命令 基本用法 let只在命令所在的代码块内(花括号内)有效. for循环的计数器,就很合适使用let命令. //var var a = []; for (var i = 0; i < ...

  8. Javascript高级编程学习笔记(25)—— 函数表达式(3)模仿块级作用域

    昨天写了闭包 今天就来聊聊块级作用域的事情 在绝大多数编程语言中,都有块级作用域这个概念 什么是块级作用域呢? 前面我们在刚开始讲的时候说过,JS中的大括号(不在赋值运算符的后面)表示代码块 块级作用 ...

  9. ECMAScript6 入门教程 初学记录let命令 块级作用域

    一.基本语法-let命令 (1)ES6新增了let命令,用来声明变量.所声明的变量,只在let命令所在的代码块内有效. 循环的计数器,就很合适使用let命令.计数器i只在for循环体内有效,在循环体外 ...

随机推荐

  1. 远程连接mysql出现1130的错误

    数据库权限不足 连接数据以后执行以下命令 GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY '您的数据库密码' WITH GRANT OP ...

  2. linux系统特殊权限位 suid、sgid、sticky

    linux系统特殊权限位 suid.sgid.stickysuid 使任意用户获得用文件属主相同的权限,sgid使用户获得与文件属组相同的权限(通过sgid获得的权限等同于同一用户组的权限) 表示方法 ...

  3. Educational Codeforces Round 55 (Rated for Div. 2) B. Vova and Trophies (贪心+字符串)

    B. Vova and Trophies time limit per test2 seconds memory limit per test256 megabytes inputstandard i ...

  4. 牛客练习赛14 E - 无向图中的最短距离 (bfs+bitset)

    一个链接:https://ac.nowcoder.com/acm/contest/82/E来源:牛客网 无向图中的最短距离 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 262144 ...

  5. [每日一学]apache camel|BDD方式开发apache camel|Groovy|Spock

    开发apache camel应用,最好的方式就是tdd,因为camel的每个组件都是相互独立并可测试的. 现在有很多好的测试框架,用groovy的Spock框架的BDD(行为测试驱动)是比较优秀和好用 ...

  6. Tengine + Lua + GraphicsMagick 实现图片自动裁剪/缩放

    http://my.oschina.net/eduosi/blog/169606

  7. delphi exec error 错误处理

    有时引用了三方jar后报错 [Exec Error] The command "PATH ..."" exited with code 1 解决方法 1.检测jar文件路 ...

  8. React Native 中 static的navigationOptions中的点击事件不能用this

    想在某个页面中设置导航栏,title + 左右按钮(按钮上肯定需要有事件) static navigationOptions = ({ navigation, navigationOptions }) ...

  9. UE4联网游戏中让不同的客户端生成不同的Pawn类型

    效果描述 一个服务器,两个客户端,让他们连接后分别生成不同的Pawn,并且在不同的位置生成. 意义 这是个项目需求,但是我发现如果能够彻底理解并制作出这个功能,会对虚幻4内置的网络功能以及一些重要的G ...

  10. qcom Android Camera【转】

    本文转载自:http://blog.csdn.net/Wilsonboliu/article/details/54949196 1.总体架构 Android Camera 框架从整体上看是一个 cli ...