ECMAScript 6新特性简记
ECMAScript 6.0是JavaScript语言的2015年6月的发布版。
一.let和const命令
let:
用来声明变量,用法类似于var
,但是只在let
命令所在的代码块内有效。var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); //const:
声明一个只读的常量。对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const
命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。const foo = {};
foo.prop = 123; foo.prop;//
foo = {}; // TypeError: "foo" is read-only注:对于
let
和const
来说,变量一旦声明过就不能再重新声明;但var可以
二.变量的解构赋值
- 数组解构赋值:这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
let [x, y, ...z] = ['a'];
x; // "a"
y; // undefined
z; // [] - 对象的解构赋值
let { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbblet foo;
({foo} = {foo: 1}); - 字符串解构赋值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o" - 函数参数的解构赋值
function add([x, y]){
return x + y;
} add([1, 2]); //
三.字符串的扩展
- 模板字符串(template string):用反引号(`)标识,它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量(写在
${}
之中)const tmpl = addrs => `
<table>
${addrs.map(addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')}
</table>
`; const data = [
{ first: '<Jane>', last: 'Bond' },
{ first: 'Lars', last: '<Croft>' },
]; console.log(tmpl(data));
// <table>
//
// <tr><td><Jane></td></tr>
// <tr><td>Bond</td></tr>
//
// <tr><td>Lars</td></tr>
// <tr><td><Croft></td></tr>
//
// </table>
四.数组的扩展
- Array.from():用于将类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)转为真正的数组
Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x); Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]
五.函数的扩展
- 默认值与解构赋值的默认值结合起来使用
function fetch(url, { body = '', method = 'GET', headers = {} }) {
console.log(method);
} fetch('http://example.com', {})
// "GET" fetch('http://example.com')
// 报错
function fetch(url, { method = 'GET' } = {}) {
console.log(method);
} fetch('http://example.com')
// "GET"
注:函数的length属性返回没有指定默认值的参数个数
- rest参数(...变量名):rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中,rest 参数之后不能再有其他参数
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
} var a = [];
push(a, 1, 2, 3) - 扩展运算符(...):扩展运算符好比 rest 参数的逆运算,将一个数组转为用逗号分隔的参数序列
console.log(...[1, 2, 3])
// 1 2 3 console.log(1, ...[2, 3, 4], 5)
// 1 2 3 4 5 [...document.querySelectorAll('div')]
// [<div>, <div>, <div>] - 箭头函数:如果箭头函数的代码块部分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回
var getTempItem = id => ({ id: id, name: "Temp" });
箭头函数使用说明:
(1)函数体内的this
对象,就是定义时所在的对象,而不是使用时所在的对象。
(2)不可以当作构造函数,也就是说,不可以使用new
命令,否则会抛出一个错误。
(3)不可以使用arguments
对象,该对象在函数体内不存在。如果要用,可以用Rest参数代替。
(4)不可以使用yield
命令,因此箭头函数不能用作Generator函数。
- 尾调用优化
尾调用(Tail Call)指函数最后一步调用另一个函数。函数调用自身,称为递归;函数尾调用自身,称为尾递归。 递归非常耗费内存,因为需要同时保存成千上百个调用帧,很容易发生“栈溢出”错误(stack overflow)。但对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
} factorial(5) //
上面代码是一个阶乘函数,计算n的阶乘,最多需要保存n个调用记录,复杂度 O(n) 。如果改写成尾递归,只保留一个调用记录,复杂度 O(1) 。
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
} factorial(5, 1) //
下为fibonacci 递归调用:
function Fibonacci (n) {
if ( n <= 1 ) {return 1}; return Fibonacci(n - 1) + Fibonacci(n - 2);
} Fibonacci(10); //
// Fibonacci(100)
// Fibonacci(500)
// 堆栈溢出了
使用尾递归优化过的fibonacci 算法如下:
function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {
if( n <= 1 ) {return ac2}; return Fibonacci2 (n - 1, ac2, ac1 + ac2);
} Fibonacci2(100) //
Fibonacci2(1000) // 7.0330367711422765e+208
Fibonacci2(10000) // Infinity
在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。
func.arguments
:返回调用时函数的参数。func.caller
:返回调用当前函数的那个函数。
尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。在正常模式下或者那些不支持该功能的环境中,采用“循环”换掉“递归”,减少调用栈,就不会溢出。
function sum(x, y) {
if (y > 0) {
return sum(x + 1, y - 1);
} else {
return x;
}
} sum(1, 100000)
// Uncaught RangeError: Maximum call stack size exceeded(…)
蹦床函数(trampoline)可以将上述递归执行转为循环:
function trampoline(f) {
while (f && f instanceof Function) {
f = f();
}
return f;
} function sum(x, y) {
if (y > 0) {
return sum.bind(null, x + 1, y - 1);
} else {
return x;
}
} trampoline(sum(1, 100000))
//
蹦床函数并不是真正的尾递归优化,下面的实现才是:
function tco(f) {
var value;
var active = false;
var accumulated = []; return function accumulator() {
accumulated.push(arguments);
if (!active) {
active = true;
while (accumulated.length) {
value = f.apply(this, accumulated.shift());
}
active = false;
return value;
}
};
} var sum = tco(function(x, y) {
if (y > 0) {
return sum(x + 1, y - 1)
}
else {
return x
}
}); sum(1, 100000)
//
六.对象的扩展
- 属性的简洁表示法:属性名可为变量名, 属性值可为变量的值
var foo = 'bar';
var baz = {foo};
baz // {foo: "bar"} // 等同于
var baz = {foo: foo}; 属性名表达式
var lastWord = 'last word'; var a = {
'first word': 'hello',
[lastWord]: 'world'
}; a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
七.Set和Map数据结构
- Set:类似于数组,但是成员的值都是唯一的,没有重复的值
// 去除数组的重复成员
[...new Set(array)] - Map:类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
var map = new Map([
['name', '张三'],
['title', 'Author']
]); map.size //
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"
八.Proxy
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
- this问题:目标对象内部的
this
关键字会指向 Proxy 代理,这时this可
绑定原始对象const target = new Date('2015-01-01');
const handler = {
get(target, prop) {
if (prop === 'getDate') {
return target.getDate.bind(target);
}
return Reflect.get(target, prop);
}
};
const proxy = new Proxy(target, handler); proxy.getDate() //
九.Reflect
Reflect对象一共有13个静态方法:
Reflect.apply(target,thisArg,args)
Reflect.construct(target,args)
Reflect.get(target,name,receiver)
Reflect.set(target,name,value,receiver)
Reflect.defineProperty(target,name,desc)
Reflect.deleteProperty(target,name)
Reflect.has(target,name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
Reflect.get(target, name, receiver)
var myObject = {
foo: 1,
bar: 2,
get baz() {
return this.foo + this.bar;
},
}; var myReceiverObject = {
foo: 4,
bar: 4,
}; Reflect.get(myObject, 'baz', myReceiverObject) //- 使用-Proxy-实现观察者模式
const person = observable({
name: '张三',
age: 20
}); function print() {
console.log(`${person.name}, ${person.age}`)
} observe(print);
person.name = '李四';
// 输出
// 李四, 20 const queuedObservers = new Set(); const observe = fn => queuedObservers.add(fn);
const observable = obj => new Proxy(obj, {set}); function set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
queuedObservers.forEach(observer => observer());
return result;
}
十.Promise
Promise 是异步编程的一种解决方案,比传统的解决方案回调函数和事件更合理强大。
let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
}); promise.then(function() {
console.log('Resolved.');
}); console.log('Hi!'); // Promise
// Hi!
// Resolved
十一.Iterator和for...of循环
Iterator的作用有三个:
- 为各种数据结构,提供一个统一的、简便的访问接口
- 使得数据结构的成员能够按某种次序排列
- 创造了一种新的遍历命令
for...of
循环,Iterator接口主要供for...of
消费
const arr = ['red', 'green', 'blue']; for(let v of arr) {
console.log(v); // red green blue
} const obj = {};
obj[Symbol.iterator] = arr[Symbol.iterator].bind(arr); for(let v of obj) {
console.log(v); // red green blue
}
十二.Generator
形式上,Generator 函数是一个普通函数,但是有两个特征:
function
关键字与函数名之间有一个星号- 函数体内部使用
yield
语句,定义不同的内部状态
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
yield 1;
yield 2;
yield 3;
}; [...myIterable] // [1, 2, 3]
Generator函数的this
function* g() {
this.a = 11;
} g.prototype.hello = function () {
return 'hi!';
}; let obj = g(); obj instanceof g // true
obj.hello() // 'hi!'
obj.a // undefinedGenerator 函数:可以暂停执行和恢复执行,可以作为异步编程的完整解决方案——函数体内外的数据交换和错误处理机制
function* gen(x){
try {
var y = yield x + 2;
} catch (e){
console.log(e);
}
return y;
} var g = gen(1);
g.next();
g.throw('出错了');JavaScript 语言的 Thunk 函数:Thunk 函数将多参数函数替换成一个只接受回调函数作为参数的单参数函数
// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback); // Thunk版本的readFile(单参数版本)
var Thunk = function (fileName) {
return function (callback) {
return fs.readFile(fileName, callback);
};
}; var readFileThunk = Thunk(fileName);
readFileThunk(callback);
十三.async函数
async 函数是Generator 函数的语法糖,返回一个 Promise 对象,可以使用then
方法添加回调函数。 async 函数return
语句返回值或抛出异常,Promise 对象状态发生变化,then和catch
方法回调函数捕获处理。正常情况下,await
命令后面是一个 Promise 对象,如果不是,会被转成一个立即resolve
的 Promise 对象。
async function f() {
await Promise.reject('出错了');
} f()
.then(v => console.log(v))
.catch(e => console.log(e))
// 出错了
十四.Class
基本上,ES6的class
可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class
写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的constructor(x, y)
this.color = color;
} toString() {
return this.color + ' ' + super.toString(); // 调用父类的toString()
}
}
原生构造函数无法继承
ECMAScript的原生构造函数大致有下面这些: Boolean(),Number(),String(),Array(),Date(),Function(),RegExp(),Error(),Object()
- Class的取值函数(getter)和存值函数(setter)
class MyClass {
constructor() {
// ...
}
get prop() {
return 'getter';
}
set prop(value) {
console.log('setter: '+value);
}
} let inst = new MyClass(); inst.prop = 123;
// setter: 123 inst.prop
// 'getter' - Class 的 Generator 方法:方法之前加上星号(
*
),就表示该方法是一个 Generator 函数class Foo {
constructor(...args) {
this.args = args;
}
* [Symbol.iterator]() {
for (let arg of this.args) {
yield arg;
}
}
} for (let x of new Foo('hello', 'world')) {
console.log(x);
}
// hello
// world - Mixin模式的实现
function mix(...mixins) {
class Mix {} for (let mixin of mixins) {
copyProperties(Mix, mixin);
copyProperties(Mix.prototype, mixin.prototype);
} return Mix;
} function copyProperties(target, source) {
for (let key of Reflect.ownKeys(source)) {
if ( key !== "constructor"
&& key !== "prototype"
&& key !== "name"
) {
let desc = Object.getOwnPropertyDescriptor(source, key);
Object.defineProperty(target, key, desc);
}
}
}
十五.Module
ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict"
。
严格模式主要有以下限制:
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用
with
语句 - 不能对只读属性赋值,否则报错
- 不能使用前缀0表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错
- 不能删除变量
delete prop
,会报错,只能删除属性delete global[prop]
eval
不会在它的外层作用域引入变量eval
和arguments
不能被重新赋值arguments
不会自动反映函数参数的变化- 不能使用
arguments.callee
- 不能使用
arguments.caller
- 禁止
this
指向全局对象 - 不能使用
fn.caller
和fn.arguments
获取函数调用的堆栈 - 增加了保留字(比如
protected
、static
和interface
)
export 命令和import命令:export命令定义了模块的对外接口,通过import命令加载模块
// circle.js export function area(radius) {
return Math.PI * radius * radius;
} export function circumference(radius) {
return 2 * Math.PI * radius;
} // main.js
import * as circle from './circle'; console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));- 模块的整体加载:星号(
*
)指定一个对象,所有输出值都加载在这个对象上面import * as circle from './circle';
export default 命令:为模块指定默认输出
// export-default.js
export default function () {
console.log('foo');
} // import-default.js
import customName from './export-default';
customName(); // 'foo'模块的继承
// circleplus.js export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}浏览器的模块加载
<script type="module" src="foo.js"></script>
浏览器对于带有
type="module"
的<script>
,都是异步加载外部脚本,不会造成堵塞浏览器。对于外部的模块脚本(上例是foo.js
),有几点需要注意:- 该脚本自动采用严格模块。
- 该脚本内部的顶层变量,都只在该脚本内部有效,外部不可见。
- 该脚本内部的顶层的
this
关键字,返回undefined
,而不是指向window
。
- 循环加载:ES6处理“循环加载”与CommonJS有本质的不同,是动态引用,如果使用
import
从一个模块加载变量(即import foo from 'foo'
),那些变量不会被缓存,而是成为一个指向被加载模块的引用// a.js // 这一行建立一个引用,
// 从`b.js`引用`bar`
import {bar} from './b.js'; export function foo() {
// 执行时第一行输出 foo
console.log('foo');
// 到 b.js 执行 bar
bar();
console.log('执行完毕');
}
foo(); // b.js // 建立`a.js`的`foo`引用
import {foo} from './a.js'; export function bar() {
// 执行时,第二行输出 bar
console.log('bar');
// 递归执行 foo,一旦随机数
// 小于等于0.5,就停止执行
if (Math.random() > 0.5) {
foo();
}
} 跨模块常量:
const
声明的常量只在当前代码块有效,如果想设置跨模块的常量(即跨多个文件),可以采用下面的写法// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4; // test1.js 模块
import * as constants from './constants';
console.log(constants.A); //
console.log(constants.B); // // test2.js 模块
import {A, B} from './constants';
console.log(A); //
console.log(B); //
十六.SIMD(Single Instruction/Multiple Data):单指令/多数据
SIMD 提供12种数据类型,总长度都是128个二进制位。
- Float32x4:四个32位浮点数
- Float64x2:两个64位浮点数
- Int32x4:四个32位整数
- Int16x8:八个16位整数
- Int8x16:十六个8位整数
- Uint32x4:四个无符号的32位整数
- Uint16x8:八个无符号的16位整数
- Uint8x16:十六个无符号的8位整数
- Bool32x4:四个32位布尔值
- Bool16x8:八个16位布尔值
- Bool8x16:十六个8位布尔值
- Bool64x2:两个64位布尔值
每种数据类型被x
符号分隔成两部分,后面的部分表示通道数,前面的部分表示每个通道的宽度和类型。比如,Float32x4
就表示这个值有4个通道,每个通道是一个32位浮点数。
var a = SIMD.Float32x4(1, 2, 3, 4);
var b = SIMD.Float32x4(5, 6, 7, 8);
var c = SIMD.Float32x4.add(a, b); // Float32x4[6, 8, 10, 12]
参考:http://es6.ruanyifeng.com/ (由于原作内容太多,为精简,也为实际开发备料,以及日后再次查阅之用)
ECMAScript 6新特性简记的更多相关文章
- ECMAScript 6新特性简介
目录 简介 ECMAScript和JavaScript的关系 let和const 解构赋值 数组的扩展 函数的扩展 简介 ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言 ...
- ECMAScript 2021 新特性
ECMAScript 2021 新特性 refs https://codeburst.io/exciting-features-of-javascript-es2021-es12-1de8adf655 ...
- ECMAScript 6新特性(1)数组篇
数组现有的方法: .concat():连接两个或更多的数组,并返回结果. .join():把数组的所有元素放入一个字符串.元素通过指定的分隔符进行分隔. .pop():删除并返回数组的最后一个元素 . ...
- ECMAScript 6 | 新特性
新特性概览 参考文章: http://www.cnblogs.com/Wayou/p/es6_new_features.html ——————————————————————————————————— ...
- ECMAScript 6新特性介绍
箭头函数 箭头函数使用=>语法来简化函数.在语句结构上和C#.Java 8 和 CoffeeScript相似,支持表达式和函数体. . =>`操作符左边为输入的參数.而右边则是进行的操作以 ...
- ECMAScript 6 新特性-set。const
一.let命令是es6新增的特性,作用与var命令类似,声明变量,不同之处在于声明的变量的作用域为块级作用域.引入let后带来了很多新的特性. 1作用域,es5之前之后函数作用域和全局作用域,let的 ...
- Ecmascript 6新特性
声明变量由var变成let.let实际上为JavaScript新增了块级作用域.let与var相比具有的特性有 1.不允许重复声明一个变量 var a=5; var a=7; let b=6; let ...
- ECMAScript 5 新特性
Strict模式 开启strict: 在文件头部,或者在一个function头部内,添加‘use strict’或者“use strict”. Strict模式的限制,以及违反时出现的异常: 新定制了 ...
- ECMAScript 6新特性之Proxy
ECMAScript 6中新增了一个全局构造函数:Proxy.该构造函数能够接收两个參数:一个目标对象.一个处理对象. 代码演示样例: var target = {}; var handler = { ...
随机推荐
- java学习笔记IO之File类
File类总结 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Times } p.p2 { margin: 0.0px 0.0px 0.0p ...
- 简单的调用OpenCV库的Android NDK开发 工具Android Studio
前言 本博客写于2017/08/11, 博主非专业搞安卓开发, 只是工作的需要倒腾了下Android NDK相关的开发, 博文中有什么不正确.不严格的地方欢迎指正哈 本文后续也许还会有删改, 就 ...
- hdu 5288||2015多校联合第一场1001题
pid=5288">http://acm.hdu.edu.cn/showproblem.php?pid=5288 Problem Description OO has got a ar ...
- Android 当打开“开发人员模式”中的“不保留活动”后,程序应当怎么保持正常执行
Android 当打开"开发人员模式"中的"不保留活动"后,程序应当怎么保持正常执行咧. .? 在这几天,我一直在纠结这个问题.从发现,程序出现这个问题,是由于 ...
- ArcGIS教程:创建特征
摘要 创建由输入样本数据和一组栅格波段定义的类的 ASCII 特征文件. 使用方法 · 输出特征文件应使用扩展名 .gsg. · 输入栅格波段和输入栅格或要素样本数据必须具有重叠范围.将仅为公共区域计 ...
- Win32界面 主函数分析
WinMain即(函数运行入口): p { margin-bottom: 0.25cm; line-height: 120% } int WINAPI WinMain (HINSTANCE hinst ...
- 数据库——MongoDB——>Java篇
MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB 是一个介于关系数据库和非关系数据库之间的产 ...
- mac与centos下redis的安装与配置
前言 最近在用redis,下面简单写一下mac和centos下redis的安装与配置方法. 安装 mac下面 安装命令:brew intall redis 运行命令:brew services sta ...
- spring-boot学习笔记之Conditional
今天看了@Conditional,自己根据以下文章练了下,根据自己的理解操作的 转载出处:http://wiselyman.iteye.com/blog/2213054 17. ...
- 《程序设计语言——实践之路》【PDF】下载
程序设计语言--实践之路>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230382240 内容简介 本书在美国大学已有使用了十余年,目前被欧 ...