ECMAScript入门(一):ECMAScript简介、babel、let、const、作用域相关。

本文深入讲解ES6(ECMAScript 2015)的新特性,包括let和const声明、块级作用域、const常量、ES6声明变量的六种方法及顶层对象属性的变化。并介绍了Babel转码器如何帮助开发者在不支持ES6的环境中编写ES6代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ECMAScript入门(一)

一、ECMAscript简介:

1.ECMAScript和JavaScript的关系:

前者是后者的规格,后者是前者的实现。

2.ES6和ECMAScript2015的关系:

版本命名方式改变了。ES6实际上就是ES2015.也可指新一代script标准,囊括ES2015、16、17

3.语法提案的批准流程

Stage 0 - Strawman(展示阶段)
Stage 1 - Proposal(征求意见阶段)
Stage 2 - Draft(草案阶段)
Stage 3 - Candidate(候选人阶段)
Stage 4 - Finished(定案阶段)

4.ECMAScript历史:

1997年发布第一版,1999年第三版,第四版失败原因是太激进,但其中很多激进部分被6继承,因此可以看做6是从此开始。第五版变动不大是由3.1改名而来,但是正是发布是09年。15年6月6正是成为标准,从四算起15年。

5.部署进度:

可通过一个GitHub链接查询浏览器的ES6支持情况。
node环境支持度更高,可通过以下代码查看。

// Linux & Mac
$ node --v8-options | grep harmony

// Windows
$ node --v8-options | findstr harmony

6.Babel转码器:

Babel是一个ES6转码器,其功能是将ES6代码转为ES5,这意味着可以用ES6写代码而不用考虑浏览器的ES6支持情况。

// npm安装Babel CLI 和 env preset(根据你支持的环境自动决定适合你的 Babel 插件的 Babel preset):
npm install --save-dev babel-cli babel-preset-env
// 创建 .babelrc 文件(或使用 package.json)
{
  "presets": ["env"] //转码规则
  "plugins":[] //插件
}

也可以限定所要支持的浏览器版本,这样变异的代码包更小。browserslist 支持的有效的查询格式

{
  "presets": [
    ["env", {
      "targets": {
        "browsers": ["last 2 versions", "safari >= 7"]
      }
    }]
  ]
}
// Babel只转换语法,可以使用babel-polyfill支持新的全局变量,例如Promise、新的原生方法如String.padStart(left-pad)
npm install --save-dev babel-polyfill
//方便起见,你可以使用"node": "current" 来包含用于运行Babel的Node.js最新版所必需的polyfills和transforms
{
  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
    }]
  ]
}

二、let和const命令:

1.let命令

基本用法:
{
  let a = 10;
  var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

let声明的是所在块作用域内有效,用let不存在变量提升。for中每次let是新生成但是能记住上次值是因为JavaScript引擎内部记住了,此外设置循环部分是父作用域,循环体内部是子作用域。eg.

for (let i = 0; i < 3; i++) {
  let i = 'abc';
  console.log(i);
}
// abc
// abc
// abc
暂时性死区(TDZ):

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。暂时性死区说明typeof不再是百分百安全操作。

不允许重复声明:

let不允许在相同作用域内,重复声明同一个变量。

function func() {
  let a = 10;
  var a = 1;
}

// 报错
function func() {
  let a = 10;
  let a = 1;
}
// 报错

因此,不能在函数内部重新声明参数。

function func(arg) {
  let arg;
}
func() // 报错

function func(arg) {
  {
    let arg;
  }
}
func() // 不报错

2.块级作用域:

块级作用域的作用:

避免内层覆盖外层,避免循环变量泄露为全局变量。

let为ES6带来了块级作用域

ES6允许块级作用域任意嵌套,外层无法读取内层。有了let就不用使用IIFE了。
IIFE( 立即调用函数表达式)是一个在定义时就会立即执行的 JavaScript 函数。
这是一个被称为 自执行匿名函数 的设计模式,主要包含两部分。第一部分是包围在 圆括号运算符() 里的一个匿名函数,这个匿名函数拥有独立的词法作用域。这不仅避免了外界访问此 IIFE 中的变量,而且又不会污染全局作用域。
第二部分再一次使用 () 创建了一个立即执行函数表达式,JavaScript 引擎到此将直接执行函数。
ES6中块级作用域内声明的函数类似于let。所以应该用函数表达式。
另外,还有一个需要注意的地方。ES6 的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。

// 不报错
'use strict';
if (true) {
  function f() {}
}

// 报错
'use strict';
if (true)
  function f() {}

3.const命令

声明一个只读常量,一旦声明不能改变。,声明同时必须赋值,也有块级作用域。声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。同一块内不能重复声明。
本质上const是浅控制不可变。冻结对象应该用Object.freeze方法(添加新属性不起作用,严格报错)。
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。

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

ES6 声明变量的六种方法
var function let const import class

4.顶层对象的属性

顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。ES5 之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a // 1

a = 2;
window.a // 2

ES6 为了改变这一点,一方面规定,为了保持兼容性,var命令和function命令声明的全局变量,依旧是顶层对象的属性;另一方面规定,let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。也就是说,从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

5.global对象

ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的:
浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window。
浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self。
Node 里面,顶层对象是global,但其他环境都不支持。

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性:
全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
不管是严格模式,还是普通模式,new Function(‘return this’)(),总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。
综上所述,很难找到一种方法,可以在所有情况下,都取到顶层对象。下面是两种勉强可以使用的方法。

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

现在有一个提案,在语言标准的层面,引入global作为顶层对象。也就是说,在所有环境下,global都是存在的,都可以从它拿到顶层对象。

垫片库system.global模拟了这个提案,可以在所有环境拿到global。

// CommonJS 的写法
require('system.global/shim')();

// ES6 模块的写法
import shim from 'system.global/shim'; shim();
上面代码可以保证各种环境里面,global对象都是存在的。

// CommonJS 的写法
var global = require('system.global')();

// ES6 模块的写法
import getGlobal from 'system.global';
const global = getGlobal();

上面代码将顶层对象放入变量global。

文档是读阮一峰ECMAScript入门教程后的提炼总结。感恩阮大佬开源共享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值