ES6最棒的新特性

ES6中的默认参数

  • ES5的写法
var link = function (color, height, url) {
    var color = color || 'red'
    var height = height || 50
    var url = url || 'www.baidu.com'
    console.log(color)//blue
    console.log(height)//50
    console.log(url)//www.google.com
}
link('blue', 0, 'www.google.com')
  • 在ES6中,我们可以把默认值直接放进函数签名
var link = function (color = 'red', height = 50, url = "www.baidu.com") {
    console.log(color)//blue
    console.log(height)//0
    console.log(url)//www.google.com
}
link('blue', 0, 'www.google.com')

ES6中的模板表达式

  • ES5的写法
function getMsg(firstName, lastName, id) {
    var name = 'Your name is ' + firstName + ' ' + lastName
    var url = 'http://localhost:3000/api/message/' + id
    return name + ', ' + url
}
console.log(getMsg('Dot', 'Dolby', '12345'))//Your name is Dot Dolby, http://localhost:3000/api/message/12345
  • 在ES6中,在反引号包裹的字符串中使用${NAME}语法来表示模板字符:
function getMsg(firstName, lastName, id) {
    var name = `Your name is ${firstName} ${lastName}`
    var url = `http://localhost:3000/api/message/${id}`
    return `${name}, ${url}`
}
console.log(getMsg('Dot', 'Dolby', '12345'))//Your name is Dot Dolby, http://localhost:3000/api/message/12345

ES6中的多行字符串

  • ES5的写法
var brotherStr1 = '“我好歹认识两个字,写了遗书,还留了一封信呢。”路上,麻子妈和宋老太这样说。\n'
    + '宋老太问:“信上写的什么哪?”\n'
    + '“写的是‘我不是死了,只是走了’。”\n'
    + '并非死别,只是生离。\n'
    + '痛苦与幸福,生不带来,死不带去。\n'

var brotherStr2 = '而他一生所憎恶的,全都令他魂牵梦萦。\n他简直就像石缝里亿万年间挤压而生的一小撮树芽,摇摇欲坠,形容扭曲,但郁郁葱葱。'

console.log(brotherStr1)
// “我好歹认识两个字,写了遗书,还留了一封信呢。”路上,麻子妈和宋老太这样说。
// 宋老太问:“信上写的什么哪?”
// “写的是‘我不是死了,只是走了’。”
// 并非死别,只是生离。
// 痛苦与幸福,生不带来,死不带去。
console.log(brotherStr2)
// 而他一生所憎恶的,全都令他魂牵梦萦。
// 他简直就像石缝里亿万年间挤压而生的一小撮树芽,摇摇欲坠,形容扭曲,但郁郁葱葱。
  • ES6中,只要充分利用反引号。
var brotherStr1 = `“我好歹认识两个字,写了遗书,还留了一封信呢。”路上,麻子妈和宋老太这样说。 
宋老太问:“信上写的什么哪?” 
“写的是‘我不是死了,只是走了’。” 
并非死别,只是生离。 
痛苦与幸福,生不带来,死不带去。`

var brotherStr2 = `而他一生所憎恶的,全都令他魂牵梦萦。
他简直就像石缝里亿万年间挤压而生的一小撮树芽,摇摇欲坠,形容扭曲,但郁郁葱葱。`
console.log(brotherStr1)
// “我好歹认识两个字,写了遗书,还留了一封信呢。”路上,麻子妈和宋老太这样说。 
// 宋老太问:“信上写的什么哪?” 
// “写的是‘我不是死了,只是走了’。” 
// 并非死别,只是生离。 
// 痛苦与幸福,生不带来,死不带去。
console.log(brotherStr2)
// 而他一生所憎恶的,全都令他魂牵梦萦。
// 他简直就像石缝里亿万年间挤压而生的一小撮树芽,摇摇欲坠,形容扭曲,但郁郁葱葱。

ES6中的解构赋值

  • 对象字面量和数组字面量提供了一种简单的定义一个特定的数据组的方法。
    let x = [1, 2, 3, 4, 5];

  • 解构赋值使用了相同的语法,不同的是在表达式左边定义了要从原变量中取出什么变量。

var x = [1, 2, 3, 4, 5];
var [y, z] = x;
console.log(y); // 1
console.log(z); // 2

解构数组

  • 变量声明并赋值 时的解构
var foo = ["one", "two", "three"];
var [one, two, three] = foo;
console.log(one); // "one"
console.log(two); // "two"
console.log(three); // "three"
  • 变量先声明后赋值时的解构
var a, b;
[a, b] = [1, 2];
console.log(a); // 1
console.log(b); // 2
  • 为了防止从数组中取出一个值为undefined的对象,可以为这个对象设置默认值。
var a, b;
[a = 5, b = 7] = [1];
console.log(a); // 1
console.log(b); // 7
  • 在一个解构表达式中可以交换两个变量的值。
var a = 1;
var b = 3;
[a, b] = [b, a];
console.log(a); // 3
console.log(b); // 1
  • 从一个函数返回一个数组是十分常见的情况,解构使得处理返回值为数组时更加方便。在下面例子中,[1, 2] 作为函数的 f() 的输出值,可以使用解构用一句话完成解析。
function f() {
    return [1, 2];
}
var a, b;
[a, b] = f();
console.log(a); // 1
console.log(b); // 2
  • 可以忽略你不感兴趣的返回值:
function f() {
    return [1, 2, 3];
}
var [a, , b] = f();
console.log(a); // 1
console.log(b); // 3
  • 也可以忽略全部返回值
[, ,] = f();
  • 当解构一个数组时,可以使用剩余模式,将数组剩余部分赋值给一个变量。
var [a, ...b] = [1, 2, 3];
console.log(a); // 1
console.log(b); // [2, 3]
  • 注意:如果剩余元素右侧有一个逗号,会抛出语法错误的异常,因为剩余元素必须是数组的最后一个元素。
var [a, ...b,] = [1, 2, 3];
// SyntaxError: rest element may not have a trailing comma
  • ...的扩展应用:...就是脱掉衣服———脱掉数组的外壳
function sort(...arr){
  console.log(arr.sort())
}
sort(3, 1, 5)  //[1, 3, 5]
function max(arr){
  return Math.max(...arr)
}
max([3, 4, 1])  // 4
//类数组对象转数组
let ps = document.querySelectorAll('p');
Array.from(ps).forEach(p=> {
console.log(p.innerText);
});
[...ps].forEach(p=>{console.log(p.innerText)});

解构对象

var o = { p: 42, q: true };
var { p, q } = o;
console.log(p); // 42
console.log(q); // true 
// 用新变量名赋值
var { p: foo, q: bar } = o;
console.log(foo); // 42
console.log(bar); // true 
  • 变量可以先赋予默认值。当要提取的对象没有对应的属性,变量就被赋予默认值。
var { a = 10, b = 5 } = { a: 3 };
console.log(a); // 3
console.log(b); // 5
  • 浏览器很蠢,没有圆括号浏览器会认为等号两边是两个块,圆括号括起来可以让浏览器将对象的解构赋值当做表达式去执行,也就是加了圆括号对象的解构赋值操作可以正确被执行。
let name
let age
{name: name, age: age} = {name: 'jirengu', age: 4}//Uncaught SyntaxError: Unexpected token :
let name
let age
({name: name, age: age} = {name: 'jirengu', age: 4})//{name: "jirengu", age: 4}

ES6中改进的对象表达式

  • ES5的写法
var serviceBase = {
    port: 3000,
    url: 'www.baidu.com'
}
var getAccounts = function () {
    return [1, 2, 3]
}

var accountServiceES5 = {
    port: serviceBase.port,
    url: serviceBase.url,
    getAccounts: getAccounts,
    toString: function () {
        return JSON.stringify(this.valueOf())
    },
    getUrl: function () {
        return 'http://' + this.url + ':' + this.port
    },
    valueOf_1_2_3: getAccounts()
}
console.log(accountServiceES5)
//{ port: 3000,
//   url: 'www.baidu.com',
//   getAccounts: [Function: getAccounts],
//   toString: [Function: toString],
//   getUrl: [Function: getUrl],
//   valueOf_1_2_3: [ 1, 2, 3 ] }
console.log(accountServiceES5.port)//3000
  • 在ES6的对象表达式中,我们把getAccounts: getAccounts简化为getAccounts,并且我们还可以用proto直接设置prototype,我们还可以调用 super 和动态索引(valueOf_1_2_3)
var serviceBase = {
    port: 3000,
    url: 'www.baidu.com'
}
var getAccounts = function () {
    return [1, 2, 3]
}

var accountService = {
    __proto__: serviceBase,
    getAccounts,
    toString() {
        return JSON.stringify((super.valueOf()))
    },
    getUrl() {
        return 'http://' + this.url + ':' + this.port
    },
    ['valueOf_' + getAccounts().join('_')]: getAccounts()
}
console.log(accountService)
// { getAccounts: [Function: getAccounts],
//   toString: [Function: toString],
//   getUrl: [Function: getUrl],
//   valueOf_1_2_3: [ 1, 2, 3 ] }
console.log(accountService.__proto__.port)//3000

ES6中的箭头函数

箭头函数神奇之处在于他会让你写正确的代码。比如,this在上下文和函数中的值应当是相同的,它不会变化,通常变化的原因都是因为你创建了闭包。使用箭头函数可以让我们不再用that = this或者self = this或者_this = this或者.bind(this)这样的代码,这些代码特别丑。

  • ES5中,要先用一个变量保存当前的this值,执行事件时用这个变量才能确保正确的结果
var _this = this
$('.btn').click(function (e) {
    _this.sendData()
})
  • ES6写法,其实写法上就相当于将function(){}换成了()=>{}
$('.btn').click((e) => {
    this.sendData()
})
  • 在ES5中
var logUpperCase = function () {
    var _this = this
    this.string = this.string.toUpperCase()
    return function () {
        return console.log(_this.string)
    }
}
logUpperCase.call({ string: 'es6 rocks' })()
  • 在ES6中我们无需_this,以下两种写法结果是等价的,
    注意,在ES6中你可以合理的把箭头函数和旧式 function 函数混用。当箭头函数所在语句只有一行时,它就会变成一个表达式,它会直接返回这个语句的值。但是如果你有多行语句,你就要明确的使用return。
var logUpperCase = function () {
    this.string = this.string.toUpperCase()
    return () => { return console.log(this.string) }
}
logUpperCase.call({ string: 'es6 rocks' })()
var logUpperCase = function () {
    this.string = this.string.toUpperCase()
    return () => console.log(this.string)
}
logUpperCase.call({ string: 'es6 rocks' })()
  • 在ES5中
var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']
var messages = ids.map(function (value) {
    return 'ID is ' + value // 显式返回
});
  • 在ES6中
var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']
var messages = ids.map(value => `ID is $(value)`)// 隐式返回
  • 在只有一个参数的函数签名中,括号是可有可无的,但是如果多于一个参数时就要加上。
var ids = ['5632953c4e345e145fdf2df8', '563295464e345e145fdf2df9']
var messages = ids.map((value, index, list) => `ID of ${index} element is ${value} `) // 隐式返回

ES6中的Promise

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象,用于处理异步请求。中文含义:诺言,结果:诺言可能兑现,也可能食言。
语法:

new Promise(
    /* executor */
    function(resolve, reject) {...}
);

executor是一个带有 resolve 和 reject 两个参数的函数 。executor 函数在Promise构造函数执行时同步执行,被传递 resolve 和 reject 函数(executor 函数在Promise构造函数返回新建对象前被调用)。resolve 和 reject 函数被调用时,分别将promise的状态改为fulfilled(完成)或rejected(失败)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
如果在executor函数中抛出一个错误,那么该promise 状态为rejected。executor函数的返回值被忽略。

一个 Promise有以下几种状态:

  • pending: 初始状态,不是成功或失败状态。
  • fulfilled: 意味着操作成功。
  • rejected: 意味着操作失败。

Promise原型上有几个重要的方法分别是:catch和then
catch用于添加一个否定(rejection) 回调到当前 promise, 返回一个新的promise。
then用于添加肯定和否定回调到当前 promise, 返回一个新的 promise, 将以回调的返回值 来resolve。

因为Promise.prototype.then和Promise.prototype.catch方法返回promise 对象, 所以它们可以被链式调用。

看个例子:

  • ES5中的写法
setTimeout(function(){
  console.log('Yay!')
  setTimeout(function(){
    console.log('Wheeyee!')
  }, 1000)
}, 1000)

大约1s后打印出Yay!,再过大约1s打印出Wheeyee!

  • ES6写法
var wait1000 =  ()=> new Promise((resolve, reject)=> {setTimeout(resolve, 1000)})
 
wait1000()
    .then(function() {
        console.log('Yay!')
        return wait1000()
    })
    .then(function() {
        console.log('Wheeyee!')
    });

与ES5的写法等价,虽然我现在不会用,但是大家都觉得好,那应该就是好的吧^__^,mark一下,之后继续学习。

块级作用域的let和const

let是一个更新的var,可以让你把变量作用域限制在当前块里。我们用{}来定义块,但是在ES5中这些花括号没有块级作用域的概念。

function testScope(a) {
    var b = 0
    if (a) {
        var b = 1
    }
    { // 让块来的更疯狂
        var b = 100
        {
            var b = 1000
        }
    }
    return b
}
console.log(testScope(true))//1000

这个结果一定不是我们想要的,将var换成let以限制变量的作用域

function testScope(a) {
    let b = 0
    if (a) {
        let b = 1
        // return b//1
    }
    {
        let b = 100
        // return b//100
        {
            let b = 1000
            // return b//1000
        }
    }
    return b
}
console.log(testScope(true))//0

运行结果是0,因为在if块中也有let,相当于每一个let都限制了变量的作用域

如果是以下情况呢?

function testScope(a) {
    let b = 0
    let b = 1
    let b = 2
    return b
}
console.log(testScope(true))

会报错,SyntaxError: Identifier 'b' has already been declared。说明已经用let限制了作用域的同名变量无法被覆盖,换成var b=1同样会报错。

说到const,事情就简单多了。此声明创建一个常量,其作用域可以是全局或本地声明的块,常量不能和它所在作用域内的其他变量或函数重名。为了演示,这里有定义了一堆常量,并且由于作用域的原因,这些定义都是有效的。

function calculateTotalAmount(vip) {
    const amount = 0
    if (vip) {
        const amount = 1
    }
    { // 更多的块
        const amount = 100
        {
            const amount = 1000
        }
    }
    return amount
}
console.log(calculateTotalAmount(true))//0

const声明创建一个值的只读引用。但这并不意味着它所持有的值是不可变的,只是变量标识符不能重新分配。

const MY_AGE = 2
// MY_AGE=7//报错,TypeError: Assignment to constant variable.
// const MY_AGE=3//报错,SyntaxError: Identifier 'MY_AGE' has already been declared
console.log(MY_AGE)//2
if (MY_AGE === 2) {
    let MY_AGE = 5
    console.log(MY_AGE)//5
    var MY_AGE = 4//报错,MY_AGEHUI被提升到全局作用域并引发错误,SyntaxError: Identifier 'MY_AGE' has already been declared
}

ES6中的类

我们都知道JS语言的面向对象编程中没有类的概念,所以类的创建和使用让人身份恼火,我的另一篇博客里有关于面向对象中怎样创建类的介绍,这里不赘述。
ES6中引入的类(classes) 是 JavaScript 基于原型的继承的语法糖。类语法不是向JavaScript引入一个新的面向对象的继承模型,而是提供一个更简单清晰的语法来创建对象并处理继承。

  • 定义类的一种方法是使用一个类声明。使用带有class关键字的类名去声明一个类。
class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
}

注意:变量和函数声明会提升,值不会提升,类声明也不会提升,所以首先要声明一个类才能去访问它,不然会报错。

  • 另一个定义类的方法是类表达式,类表达式可以是被命名的或者匿名的
/* 匿名类 */ 
let Rectangle = class {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

/* 命名的类 */ 
let Rectangle = class Rectangle {
  constructor(height, width) {
    this.height = height;
    this.width = width;
  }
};

同样的,类表达式也不会提升,所以也要先声明类表达式,再去访问它。

一个类只能拥有一个名为 “constructor”的特殊方法。如果类包含多个构造函数的方法,则将抛出 一个SyntaxError。

extends关键字在类声明或类表达式中用于创建一个类作为另一个类的一个子类。如果子类中存在构造函数,则需要在使用“this”之前首先调用super(),构造函数可使用super关键字来调用父类的构造函数。

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(this.name + ' makes a noise.');
    }
}

class Dog extends Animal {
    speak() {
        super.speak();

        console.log(this.name + ' barks');
    }
}

var aaa = new Animal('dot')
aaa.speak()//dot makes a noise.
var bbb = new Dog('blus')
bbb.speak()
//blus makes a noise.
// blus barks

ES6中的模块化

ES6之前JavaScript并没有对模块化有过原生的支持,人们想出来AMD,RequireJS,CommenJS等等,现在终于有import和export运算符来实现了。

ES6中你可以用export来暴露你的类
这是ES5中的module.js文件:

module.exports = {
  port: 3000,
  getAccounts: function() {
    ...
  }
}

在ES5的main.js中,用require('模块')来导入:

var service = require('module.js')
console.log(service.port) // 3000

但是在ES6中,我们用export和import。
比如这是ES6中的module.js文件:

export var port = 3000
export function getAccounts(url) {
  ...
}

在需要引入的main.js文件中,可以用import {名称} from '模块'语法:

import {port, getAccounts} from 'module'
console.log(port) // 3000

或者就直接在main.js中引入所有的变量:

import * as service from 'module'
console.log(service.port) // 3000

参考资料

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

推荐阅读更多精彩内容

  • 一、ES6简介 ​ 历时将近6年的时间来制定的新 ECMAScript 标准 ECMAScript 6(亦称 ...
    一岁一枯荣_阅读 6,051评论 8 25
  • 以下内容是我在学习和研究ES6时,对ES6的特性、重点和注意事项的提取、精练和总结,可以做为ES6特性的字典;在本...
    科研者阅读 3,105评论 2 9
  • ES6(ECMAScript2015)的出现,无疑给前端开发人员带来了新的惊喜,它包含了一些很棒的新特性,可以更加...
    cbw100阅读 15,409评论 3 233
  • ES6特性归纳 ES的全称是ECMAScript,它是JavaScript的规格,JS是ES的一种实现。ES还有J...
    FWHeart阅读 559评论 0 4
  • 一、步骤 二、code
    liyuhong165阅读 4,149评论 0 0