1.块级作用域绑定

var声明及变量提升(Hoisting)机制

先看例子

function getValue (condition){
  if(condition){
    var value = 'blue';
    // 其他代码
    return value
  } else {
    return value
  }
}

在函数或全局作用域中,使用 var 来声明的变量,无论在代码的哪里进行声明,都会被当作在当前作用域顶部声明的变量,这就是我们常说的提升(Hoisting)机制。

例:

function getValue (condition){
  var value
  if(condition){
    value = 'blue';
    // 其他代码
    return value
  } else {
    // 此处访问变量value值为 undefined
    return value
  }
  // 此处访问变量value值为 undefined
}

变量value的声明被提升到了顶部,这就意味着else语句中也可以访问到该变量并且由于还未进行初始化,所以访问到的值为 undefined,变量提升需要一些时间来进行习惯和熟悉,避免因为误解而产生bug。

块级声明

ES6引入的块级作用域来强化对变量生命周期的控制,块级声明用于声明在指定块的作用域之外无法访问的变量。块级作用域存在于:

  • 函数内部
  • 代码块中(字符{和}之间区域)

let 声明

let 声明的语法和 var 相同。但使用 let 代替 var 就可以把变量的作用域限制在当前的代码块中。由于 let 声明不会被提升,因此通常将 let 声明语句放在封闭代码块的顶部,以便整个代码块都可以访问。
例:


function getValue (condition) {
    if(condition){
      let value = 'blue';
      // 其他代码
      return value;
    } else {
      // 变量value在此处不存在
      return null;
    }
    // 变量value在此处不存在
}

现在这个getValue函数的运行结果更像C语言。变量value改由关键字let进行声明后,不再被提升至函数顶部。执行流离开if块会立即被销毁,如果condition为false就永远不会声明并初始化value。

禁止重声明

例:

var count = 30;

let count = 40;

这段代码由于count被声明了两次,第一次用的是var 第二次用的是 let。如果作用域里已经存在某个标识符,此时在进行let声明,就会抛出错误信息

例:

var count = 30;

if (condition) {
  let count = 40;
}

因为此处的let是在if的代码块内声明了新变量count,因此不会抛出错误。内部代码块里的count会遮蔽全局作用域中的count,后者只能在if代码块之外才能访问到。

const 声明

ECMAScript 6 标准还提供了 const 关键字。 使用const关键字声明的是常量,其值一旦被设定后不可更改,因此,每个通过 const 声明的常量必须进行初始化

const maxItems = 30;

const name;

这里在声明 maxItems 时进行了初始化操作, 而声明 name 时没有赋值,因此执行后者会抛出语法错误。

const 与 let

const 与 let 都是块级声明,所以常量也只是在当前的代码块有效,一旦执行到代码块外会立即被销毁,常量同样也不会被提升到作用域顶部。

  if(condition){
      const maxItems = 5;
      // 其他代码
  }
// 此处无法访问 maxItems

在这段代码中,在 if 语句中声明常量 maxItems ,语句执一结束,maxItems 即刻被销毁,在代码块外访问不到这个常量。

与 let 相似,在同一个作用域用 const 声明已经存在的标识符也会导致语法错误,无论该标识符是使用的 var(在全局或函数作用域中),还是 let(在块级作用域中)声明的。

var message = 'hello!';
let age = 25;

// 这两条语句都会抛出错误
const message = 'goodbye';
const age = 30;

后两条 const 声明语句本身没问题,但由于前面用 var 和 let 声明了两个同名变量,结果代码就无法执行了。

尽管相似之处很多,但 const 声明与let声明有一处很大的不同,即无论在严格模式还是非严格模式下,都不可以为 const 定义的常量再进行赋值,否则会抛出错误。

const maxItems = 5;

// 抛出语法错误
maxItems = 30;

ECMAScript6 中的常量与其他语言中的很像,此处定义的maxItems不可以再被赋值。但是对象有所不同,对象中的值可以进行修改。

用 const 声明对象

const person = {
  name: 'Sherry'
};

// 可以修改对象属性的值

person.name = 'Nocte'

// 抛出语法错误
person = {
  name:'Nocte'
}

在这段代码里,绑定 person 的值是一个包含了一个属性的对象,改变person.name 的值,不会抛出任何错误,因为修改的是 person 包含的值。如果直接给 person 赋值,即需要改变 person 的绑定,就会抛出错误。切记,const 声明不允许修改绑定,但允许修改绑定的值。

临时死区(Temporal Dead Zone 后续简称为 TDZ)

与 var 不同,let 和 const 声明的变量不会被提升到作用域顶部,如果在声明之前访问这些变量,即使是使用相对安全的 typeof 操作符也会触发饮用错误。

if(condition){
  console.log(typeof value); // 饮用错误
  let value = 'Sherry'
}

由于 console.log(typeof value) 语句会抛出错误,因此用 let 定义并初始化变量 value 的语句不会执行。此时的 value 还位于 JavaScript 社区所谓的"临时死区"(Temporal Dead Zone)或TDZ中。虽然ECMAScript标准并没有明确提到TDZ,但人们却常用它来描述 let 和 const 的不提升效果。TDZ导致的声明位置的微妙差异对于 let 和const 是一样的。

JavaScript 引擎在扫描代码发现变量声明时,要么将他们提升至作用域顶部(var声明),要么将生命放到TDZ中(let和const声明)。访问TDZ中的变量或常量会触发运行时的错误。只有执行过声明语句后,才会从TDZ中移除,然后可以正常访问。

由上一个例子可见,即便是不易出错的 typeof 操作符也无法阻挡引擎抛出错误。但在 let 声明的作用域外对该变量使用typeof则不会报错。
例:

console.log(typeof value); 

if(condition){
  let value = 'Sherry'
}

typeof 是声明在变量 value 的代码块外执行的,此时 value 并不存在TDZ中。这也就意味着不存在 value 这个绑定,typeof最终返回"undefined"。TDZ只块级绑定的特性之一


钟楠@好乐互娱

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343