ES6 功能转换ES5
在本章中,我们将看到 ES6 添加的特性。我们还将学习如何使用 BabelJS 将功能编译到 ES5、
以下是我们将在本章中讨论的各种 ES6 特性-
Let + Const
Arrow Functions
Classes
Promises
Generators
Destructuring
Iterators
Template Literalst
Enhanced Object
Default, Rest & Spread Properties
Let + Const
Let 在 JavaScript 中声明一个块作用域局部变量。考虑以下示例以了解 let 的用法。
示例
let a = 1;
if (a == 1) {
let a = 2;
console.log(a);
}
console.log(a);
输出
第一个控制台打印 2 的原因是因为
a 再次使用
let 声明并且仅在
if 块中可用。任何使用 let 声明的变量都只能在声明的块中使用。我们已经使用 let 两次声明了变量 a,但它并没有覆盖 a 的值。
这就是 var 和 let 关键字的区别。当您使用 var 声明变量时,该变量将在函数范围内可用,或者如果声明,则将充当全局变量。
如果一个变量是用 let 声明的,那么该变量在块作用域内是可用的。如果在 if 语句中声明,它将仅在 if 块中可用。这同样适用于 switch、for-loop 等。
我们现在将看到使用 babeljs 在 ES5 中的代码转换。
让我们运行以下命令来转换代码-
npx babel let.js--out-file let_es5.js
从 es6 到 es5 的 let 关键字的输出如下-
让我们使用 ES6
let a = 1;
if (a == 1) {
let a = 2;
console.log(a);
}
console.log(a);
使用 babel 转译为 ES5
"use strict";
var a = 1;
if (a == 1) {
var _a = 2;
console.log(_a);
}
console.log(a);
如果您看到 ES5 代码,let 关键字将替换为
var 关键字。此外,if 块中的变量被重命名为
_a 以具有与使用
let 关键字声明时相同的效果。
常量
在本节中,我们将了解 const 关键字在 ES6 和 ES5 中的作用。范围内也可以使用 const 关键字;如果在外面,它会抛出一个错误。 const 声明的变量的值一旦赋值就不能更改。让我们考虑以下示例以了解如何使用 const 关键字。
示例
let a =1;
if (a == 1) {
const age = 10;
}
console.log(age);
输出
Uncaught ReferenceError: age is not defined at
:5:13
上面的输出会抛出一个错误,因为 const 年龄是在 if 块中定义的,并且在 if 块中可用。
我们将了解如何使用 BabelJS 转换为 ES5、
ES6
let a =1;
if (a == 1) {
const age = 10;
}
console.log(age);
命令
npx babel const.js--out-file const_es5.js
使用 BabelJS 转译为 ES6
"use strict";
var a = 1;
if (a == 1) {
var _age = 10;
}
console.log(age);
在 ES5 中,const 关键字被替换为 var 关键字,如上所示。
箭头函数
与变量表达式相比,箭头函数的语法更短。它也被称为胖箭头函数或 lambda 函数。该函数没有自己的 this 属性。本函数中省略了关键字function。
示例
var add = (x,y) => {
return x+y;
}
var k = add(3,6);
console.log(k);
输出
使用 BabelJS,我们将上述代码转译为 ES5、
ES6-箭头函数
var add = (x,y) => {
return x+y;
}
var k = add(3,6);
console.log(k);
命令
npx babel arrowfunction.js--out-file arrowfunction_es5.js
BabelJS-ES5
使用 Babel 将箭头函数转换为如下所示的变量表达式函数。
"use strict";
var add = function add(x, y) {
return x + y;
};
var k = add(3, 6);
console.log(k);
类
ES6 带有新的类功能。类类似于 ES5 中可用的基于原型的继承。 class 关键字用于定义类。类就像特殊的函数,并且与函数表达式有相似之处。它有一个构造函数,在类内部调用。
示例
class Person {
constructor(fname, lname, age, address) {
this.fname = fname;
this.lname = lname;
this.age = age;
this.address = address;
}
get fullname() {
return this.fname +"-"+this.lname;
}
}
var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
输出
ES6-类
class Person {
constructor(fname, lname, age, address) {
this.fname = fname;
this.lname = lname;
this.age = age;
this.address = address;
}
get fullname() {
return this.fname +"-"+this.lname;
}
}
var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
命令
npx babel class.js--out-file class_es5.js
BabelJS-ES5
使用 babeljs 添加了额外的代码,以使功能适用于与 ES5 中相同的类。BabelJs 确保功能与 ES6 中的功能相同。
"use strict";
var _createclass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Person = function () {
function Person(fname, lname, age, address) {
_classCallCheck(this, Person);
this.fname = fname;
this.lname = lname;
this.age = age;
this.address = address;
}
_createClass(Person, [{
key: "fullname",
get: function get() {
return this.fname + "-" + this.lname;
}
}]);
return Person;
}();
var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
Promises
JavaScript 承诺用于管理代码中的异步请求。
当您管理来自具有依赖性的异步请求的多个回调时,它使生活更轻松并保持代码清洁。 Promise 提供了一种更好的方式来处理回调函数。 Promise 是 ES6 的一部分。默认情况下,当您创建承诺时,承诺的状态为待定。
Promise 分为三种状态-
待定(初始状态)
已解决(成功完成)
被拒绝(失败)
new Promise() 用于构造承诺。 Promise 构造函数有一个参数,它是一个回调函数。回调函数有两个参数——解析和拒绝;
这两个都是内部函数。您编写的异步代码,即 Ajax 调用、图像加载、计时功能将进入回调函数。
如果回调函数中执行的任务成功,则调用resolve函数;否则,会调用带有错误详细信息的拒绝函数。
以下代码行显示了一个 promise 结构调用-
var _promise = new Promise (function(resolve, reject) {
var success = true;
if (success) {
resolve("success");
} else {
reject("failure");
}
});
_promise.then(function(value) {
//once function resolve gets called it comes over here with the value passed in resolve
console.log(value); //success
}).catch(function(value) {
//once function reject gets called it comes over here with the value passed in reject
console.log(value); // failure.
});
ES6 Promise 示例
let timingpromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Promise is resolved!");
}, 1000);
});
timingpromise.then((msg) => {
console.log(msg);
});
输出
ES6-Promises
let timingpromise = new Promise((resolve, reject) => {
setTimeout(function() {
resolve("Promise is resolved!");
}, 1000);
});
timingpromise.then((msg) => {
console.log(msg);
});
命令
npx babel promise.js--out-file promise_es5.js
BabelJS-ES5
"use strict";
var timingpromise = new Promise(function (resolve, reject) {
setTimeout(function () {
resolve("Promise is resolved!");
}, 1000);
});
timingpromise.then(function (msg) {
console.log(msg);
});
对于 Promise,代码在转译时不会改变。我们需要使用 babel-polyfill 才能在较旧的浏览器上工作。有关 babel-polyfills 的详细信息在 babel-poyfill 章节中解释。
Generators
生成器函数和普通的
函数一样。该函数具有特殊的语法 function*,其中带有 * 到函数和要在函数内部使用的
yield 关键字。这意味着在需要时暂停或启动该功能。一旦执行开始,正常功能就不能在两者之间停止。当遇到 return 语句时,它将执行完整的函数或停止。 Generator 在这里的表现有所不同,你可以使用 yield 关键字停止函数,并在需要时通过再次调用 generator 来启动它。
示例
function* generatorfunction(a) {
yield a;
yield a +1 ;
}
let g = generatorfunction(8);
console.log(g.next());
console.log(g.next());
输出
{value: 8, done: false}
{value: 9, done: false}
ES6-生成器
function* generatorfunction(a) {
yield a;
yield a +1 ;
}
let g = generatorfunction(8);
console.log(g.next());
console.log(g.next());
命令
npx babel generator.js--out-file generator_es5.js
BabelJS-ES5
"use strict";
var _marked = /*#__PURE__*/regeneratorRuntime.mark(generatorfunction);
function generatorfunction(a) {
return regeneratorRuntime.wrap(function generatorfunction$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_context.next = 2;
return a;
case 2:
_context.next = 4;
return a + 1;
case 4:
case "end":
return _context.stop();
}
}
}, _marked, this);
}
var g = generatorfunction(8);
console.log(g.next());
console.log(g.next());
Iterators
JavaScript 中的迭代器返回一个具有值的 JavaScript 对象。该对象还有一个名为 done 的标志,它具有 true/false 值。如果它不是迭代器的结尾,则返回 false。让我们考虑一个例子,看看迭代器在数组上的工作。
示例
let numbers = [4, 7, 3, 10];
let a = numbers[Symbol.iterator]();
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
在上面的例子中,我们使用了一个数字数组,并使用
Symbol.iterator 作为索引调用了数组上的一个函数。
我们在数组上使用 next() 得到的输出如下-
{value: 4, done: false}
{value: 7, done: false}
{value: 3, done: false}
{value: 10, done: false}
{value: undefined, done: true}
输出给出一个具有值的对象,并作为属性完成。每个
next() 方法调用都会给出数组中的下一个值,并作为 false 完成。只有当数组中的元素完成时,done 的值才会为真。我们可以使用它来迭代数组。还有更多可用的选项,例如
for-of 循环,其用法如下-
示例
let numbers = [4, 7, 3, 10];
for (let n of numbers) {
console.log(n);
}
输出
当
for-of 循环 使用键时,它会提供数组值的详细信息,如上所示。我们将检查这两种组合,看看 babeljs 如何将它们转译为 es5、
示例
let numbers = [4, 7, 3, 10];
let a = numbers[Symbol.iterator]();
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
let _array = [4, 7, 3, 10];
for (let n of _array) {
console.log(n);
}
命令
npx babel iterator.js--out-file iterator_es5.js
输出
"use strict";
var numbers = [4, 7, 3, 10];
var a = numbers[Symbol.iterator]();
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
console.log(a.next());
var _array = [4, 7, 3, 10];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _array[Symbol.iterator](),
_step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done);
_iteratorNormalCompletion = true) {
var n = _step.value;
console.log(n);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
在 es5 中添加了
for-of 循环的更改。但是 iterator.next 保持原样。我们需要使用
babel-polyfill 使其在旧浏览器中工作。 Babel-polyfill 与 babel 一起安装,同样可以从 node_modules 中使用,如下所示-
示例
<html>
<head>
<script type="text/javascript" src="node_modules/babel-polyfill/dist/polyfill.min.js"></script>
<script type="text/javascript" src="iterator_es5.js"></script>
</head>
<body>
<h1>Iterators</h1>
</body>
</html>
输出
Destructuring
解构属性的行为就像一个 JavaScript 表达式,它从数组、对象中解压缩值。
以下示例将解释解构语法的工作原理。
示例
let x, y, rem;
[x, y] = [10, 20];
console.log(x);
console.log(y);
[x, y, ...rem] = [10, 20, 30, 40, 50];
console.log(rem);
let z = 0;
({ x, y } = (z) ? { x: 10, y: 20 } : { x: 1, y: 2 });
console.log(x);
console.log(y);
输出
上面的代码行显示了如何将值从数组的右侧分配给左侧的变量。带有
...rem 的变量从数组中获取所有剩余的值。
我们还可以使用条件运算符从左侧的对象中分配值,如下所示-
({ x, y } = (z) ? { x: 10, y: 20 } : { x: 1, y: 2 });
console.log(x); // 1
console.log(y); // 2
让我们使用 babeljs 将其转换为 ES5-
命令
npx babel destructm.js--out-file destruct_es5.js
destruct_es5.js
"use strict";
var x = void 0,
y = void 0,
rem = void 0;
x = 10;
y = 20;
console.log(x);
console.log(y);
x = 10;
y = 20;
rem = [30, 40, 50];
console.log(rem);
var z = 0;
var _ref = z ? { x: 10, y: 20 } : { x: 1, y: 2 };
x = _ref.x;
y = _ref.y;
console.log(x);
console.log(y);
Template Literals
模板文字是一个字符串文字,允许在其中使用表达式。它使用反引号(``)而不是单引号或双引号。当我们说字符串内的表达式时,意味着我们可以在字符串内使用变量、调用函数等。
示例
let a = 5;
let b = 10;
console.log(`Using Template literal : Value is ${a + b}.`);
console.log("Using normal way : Value is " + (a + b));
输出
Using Template literal : Value is 15.
Using normal way : Value is 15
ES6-Template Literal
let a = 5;
let b = 10;
console.log(`Using Template literal : Value is ${a + b}.`);
console.log("Using normal way : Value is " + (a + b));
命令
npx babel templateliteral.js--out-file templateliteral_es5.js
BabelJS-ES5
"use strict";
var a = 5;
var b = 10;
console.log("Using Template literal : Value is " + (a + b) + ".");
console.log("Using normal way : Value is " + (a + b));
Enhanced Object Literals
在 es6 中,对象字面量添加的新特性非常好用。我们将通过几个 ES5 和 ES6 中的对象字面量示例-
示例
ES5
var red = 1, green = 2, blue = 3;
var rgbes5 = {
red: red,
green: green,
blue: blue
};
console.log(rgbes5); // {red: 1, green: 2, blue: 3}
ES6
let rgbes6 = {
red,
green,
blue
};
console.log(rgbes6); // {red: 1, green: 2, blue: 3}
如果你看到上面的代码,ES5 和 ES6 中的对象是不同的。在 ES6 中,如果变量名与键相同,我们就不必指定键值。
让我们看看使用 babel 编译成 ES5、
ES6 Enhanced object literal
const red = 1, green = 2, blue = 3;
let rgbes5 = {
red: red,
green: green,
blue: blue
};
console.log(rgbes5);
let rgbes6 = {
red,
green,
blue
};
console.log(rgbes6);
let brand = "carbrand";
const cars = {
[brand]: "BMW"
}
console.log(cars.carbrand); //"BMW"
命令
npx babel enhancedobjliteral.js--out-file enhancedobjliteral_es5.js
BabelJS-ES5
"use strict";
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value, enumerable: true, configurable: true, writable: true
});
} else { obj[key] = value; } return obj;
}
var red = 1,
green = 2,
blue = 3;
var rgbes5 = {
red: red,
green: green,
blue: blue
};
console.log(rgbes5);
var rgbes6 = {
red: red,
green: green,
blue: blue
};
console.log(rgbes6);
var brand = "carbrand";
var cars = _defineProperty({}, brand, "BMW");
console.log(cars.carbrand); //"BMW"
Default, Rest & Spread Properties
在本节中,我们将讨论 default、rest 和 spread 属性。
默认
在 ES6 中,我们可以对函数 params 使用默认参数,如下所示-
示例
let add = (a, b = 3) => {
return a + b;
}
console.log(add(10, 20)); // 30
console.log(add(10)); // 13
让我们使用 babel 将上述代码转译为 ES5、
命令
npx babel default.js--out-file default_es5.js
BabelJS-ES5
"use strict";
var add = function add(a) {
var b = arguments.length > 1 >> arguments[1] !== undefined ? arguments[1] : 3;
return a + b;
};
console.log(add(10, 20));
console.log(add(10));
Rest
Rest 参数以三个点(...)开头,如下例所示-
示例
let add = (...args) => {
let sum = 0;
args.forEach(function (n) {
sum += n;
});
return sum;
};
console.log(add(1, 2)); // 3
console.log(add(1, 2, 5, 6, 6, 7)); //27
在上面的函数中,我们将 n 个参数传递给函数 add。如果是在 ES5 中,要添加所有这些参数,我们必须依赖 arguments 对象来获取参数的详细信息。在 ES6 中,
rest it 有助于用三个点定义参数,如上所示,我们可以遍历它并获得数字的总和。
注意-当使用三个点时,我们不能使用额外的参数,即休息。
示例
let add = (...args, value) => { //syntax error
let sum = 0;
args.forEach(function (n) {
sum += n;
});
return sum;
};
以上代码会出现语法错误。
编译到 es5 如下-
command
npx babel rest.js--out-file rest_es5.js
Babel-ES5
"use strict";
var add = function add() {
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
var sum = 0;
args.forEach(function (n) {
sum += n;
});
return sum;
};
console.log(add(1, 2));
console.log(add(1, 2, 5, 6, 6, 7));
Spread
Spread 属性也有像 rest 一样的三个点。以下是一个工作示例,展示了如何使用 spread 属性。
示例
let add = (a, b, c) => {
return a + b + c;
}
let arr = [11, 23, 3];
console.log(add(...arr)); //37
现在让我们看看上面的代码是如何使用 babel 转译的-
命令
npx babel spread.js--out-file spread_es5.js
Babel-ES5
"use strict";
var add = function add(a, b, c) {
return a + b + c;
};
var arr = [11, 23, 3];
console.log(add.apply(undefined, arr));
Proxies
代理是一个对象,您可以在其中为属性查找、赋值、枚举、函数、调用等操作定义自定义行为。
语法
var a = new Proxy(target, handler);
target 和
handler 都是对象。
target 是一个对象,也可以是另一个代理元素。
handler 将是一个对象,其属性作为函数,在调用时会给出行为。
让我们通过一个例子来尝试理解这些特性-
示例
let handler = {
get: function (target, name) {
return name in target ? target[name] : "invalid key";
}
};
let o = {
name: 'Siya Kapoor',
addr: 'Mumbai'
}
let a = new Proxy(o, handler);
console.log(a.name);
console.log(a.addr);
console.log(a.age);
我们在上面的例子中定义了目标和处理程序,并与代理一起使用。代理返回带有键值的对象。
输出
Siya Kapoor
Mumbai
invalid key
现在让我们看看如何使用 babel 将上述代码转译为 ES5-
命令
npx babel proxy.js--out-file proxy_es5.js
Babel-ES5
'use strict';
var handler = {
get: function get(target, name) {
return name in target ? target[name] : "invalid key";
}
};
var o = {
name: 'Siya Kapoor',
addr: 'Mumbai'
};
var a = new Proxy(o, handler);
console.log(a.name);
console.log(a.addr);
console.log(a.age);