JavaScript ES6 语法学习

文章目录 收缩

定义变量

在ES6之前,通过var关键字来定义变量,ES6中引入了另外两个声明变量的关键字:constlet

const

被 const 声明的变量不能被重新赋值或重新声明。换句话说,它将不能再被改变。你可以使用它创建不可变数据结构,一旦数据结构被定义好,你就不能再改变它了。

// 这种写法是不可行的
const helloWorld = 'hello,world';
helloWorld = 'Bye Bye';

使用 const 声明的变量不能被改变,但是如果这个变量是数组或者对象的话,它里面持有的内容可以被更新。

// 这种写法是可行的
const helloWorld = {
text: 'hello,world'
};
helloWorld.text = 'Bye Bye';

阅读更多关于 ES6 const 的内容

let

被关键字 let 声明的变量可以被改变。

// 这种写法是可行的
let helloWorld = 'hello,world';
helloWorld = 'Bye Bye';

当一个变量需要被重新赋值的话,应该使用 let 去声明它。
阅读更多关于 ES6 let 的内容

变量的解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
一个简单的例子:

// ES5
var a = 1;
var b = 2;
var c = 3;

// ES6
let [a, b, c] = [1, 2, 3];

对象的解构赋值:

const user = {
firstname: 'Robin',
lastname: 'Wieruch',
};

// ES5
var firstname = user.firstname;
var lastname = user.lastname;
console.log(firstname + ' ' + lastname);
// output: Robin Wieruch

// ES6
const { firstname, lastname } = user;
console.log(firstname + ' ' + lastname);
// output: Robin Wieruch

箭头函数

JavaScript ES6 引入了箭头函数。箭头函数表达式比普通的函数表达式更加简洁。

// function expression
function () { ... }
// arrow function expression
() => { ... }

如果箭头函数只有一个参数,可以移除掉参数的括号,但是如果有多个参数或者没有参数,就必须保留这个括号。

// allowed 
item => { ... }
// allowed 
(item) => { ... }
// not allowed 
item, key => { ... }
// allowed 
(item, key) => { ... }

下面举例比较说明ES5和ES6。
例如循环一个数组,ES5的写法如下:

<div id="root"></div>
<script>
var list = [
    {
        title:'MySQL常用语句',
        url:'http://www.884358.com/mysql-sqls/',
    },
    {
        title:'JavaScript ES6 语法学习',
        url:'http://www.884358.com/javascript-es6/',
    }
];

var html = '<ul>';
list.map(function(item){
    html += '<li><a href="'+item.url+'">'+item.title+'</a></li>'; 
});
html += '<ul>';
document.getElementById('root').innerHTML = html;

ES6的写法如下:

<div id="root"></div>
<script>
const list = [
    {
        title:'MySQL常用语句',
        url:'http://www.884358.com/mysql-sqls/',
    },
    {
        title:'JavaScript ES6 语法学习',
        url:'http://www.884358.com/javascript-es6/',
    }
];

let html = '<ul>';
list.map(item => {
    html += '<li><a href="'+item.url+'">'+item.title+'</a></li>'; 
});
html += '<ul>';
document.getElementById('root').innerHTML = html;
</script>

简洁函数体

函数体只有一条语句或者是表达式的时候{}可以省略,会自动返回语句执行的结果,或者是表达式的结果。

//allowed
let fun1 = (x,y) => {return x + y};
//allowed
let fun1 = (x,y) => x + y;

函数体不止一条语句或者表达式时,{}不可以省略。

let fun2 = (x,y) => {
    console.log(x,y);
    return x + y;
};

箭头函数的this指向

一个普通的函数表达式总会定义它自己的this对象。但是箭头函数表达式仍然会使用包含它的语境下的this对象。箭头函数中的this继承自外围父作用域。
以下示例中,两个按钮执行点击事件后,打印的this不一样,btn1打印的this是其本身,而btn2打印的this是window

<input type="button" value="按钮1" id="btn1">
<input type="button" value="按钮2" id="btn2">
<script>
let btn1 = document.getElementById('btn1');
let btn2 = document.getElementById('btn2');
btn1.onclick = function(){
    console.log(this);
}
btn2.onclick = () => {
    console.log(this);
}
</script>

阅读更多关于箭头函数的内容

对象初始化

ES6 中,可以通过简写属性更加简洁地初始化对象。当对象中的属性名与变量名相同时,可以省略变量名:

const name = 'Robin';
const user = { 
    name: name, 
};

以上代码可以简写为:

const name = 'Robin';
const user = { 
    name, 
};

另一个简洁的辅助办法是简写方法名。在 ES6 中,你能更简洁地初始化一个对象的方法。

// ES5
var userService = {
    getUserName: function (user) {
        return user.firstname + ' ' + user.lastname;
    },
};
// ES6
const userService = {
    getUserName(user) {
        return user.firstname + ' ' + user.lastname;
    },
};

最后值得一提的是可以在 ES6 中使用计算属性名。当为一个对象动态地根据 key 分配值时便会涉及到。

// ES5
var user = {
    name: 'Robin',
};
// ES6
const key = 'name';
const user = {
    [key]: 'Robin',
};

高阶函数与柯里化

高阶函数

高阶函数满足下面的条件之一:
函数作为参数被传递或者
函数可以作为返回值被返回

let addFun = (x,y,f) => f(x) + f(y)
console.log(addFun(-1,5,Math.abs))
//结果为:6

柯里化

把接受多个参数的函数变换成接受一个单一参数的函数,并且返回(接受余下参数而且返回结果的)新函数的技术。
例如要求两个数字的和,我们写了一个常规的函数:

let addFun = (a,b) => a + b
console.log(addFun(1,2))

以上addFun函数需要传入两个参数。
改为传一个参数:

let addFun = a => b => a + b
console.log(addFun(1)(2))

以上例子就是柯里化写法,将参数变换成一个,延迟函数参数的传入。

柯里化特点

延迟参数传递,参数复用
代码短小,优雅,函数化,有点不好理解

Object.assign()

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.assign(target, ...sources)

参数:
target:目标对象。sources:源对象。
返回值:
目标对象

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。

//复制一个对象
const obj = { a: 1 };
const copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }

//合并对象
const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };

const obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1);  // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。

//合并具有相同属性的对象
const o1 = { a: 1, b: 1, c: 1 };
const o2 = { b: 2, c: 2 };
const o3 = { c: 3 };

const obj = Object.assign({}, o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }

扩展操作符(展开语法)

展开语法(Spread syntax), 可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。(注: 字面量一般指 [1, 2, 3] 或者 {name: “mdn”} 这种简洁的构造方式)

在函数调用时使用展开语法

function myFunction(x, y, z) {
    console.log(x+y+z);
}
var args = [0, 1, 2];
myFunction(...args);  //3

构造字面量数组时使用展开语法

var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2];
console.log(arr3); //[0, 1, 2, 3, 4, 5]

构造字面量对象时使用展开语法

var obj1 = { foo: 'bar', x: 42 };
var obj2 = { foo: 'baz', y: 13 };

var clonedObj = { ...obj1 };
// 克隆后的对象: { foo: "bar", x: 42 }

var mergedObj = { ...obj1, ...obj2 };
// 合并后的对象: { foo: "baz", x: 42, y: 13 }

更多关于展开语法的内容

立即执行函数

概念

声明一个函数,并马上调用这个匿名函数就叫做立即执行函数;也可以说立即执行函数是一种语法,让你的函数在定义以后立即执行;
立即执行函数的创建步骤,看下图:

写法

//写法一:
(function(){
//code
}())

//写法二:
(function (){
//code
})()

作用

  • 不必为函数命名,避免了污染全局变量
  • 立即执行函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量
  • 封装变量

立即执行函数的参数

(function(j){
//代码中可以使用j
})(i)

如果立即执行函数中需要全局变量,全局变量会被作为一个参数传递给立即执行函数(上例中的i就是一个全局变量,i代表的是实参,j是i在立即执行函数中的形参)。

更多关于立即执行函数:https://www.jianshu.com/p/b10b6e93ddec

Promise 对象

概念

Promise 对象:代表了未来某个时间将要发生的事件(通常是一个异步操作)
有了promise对象,可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(俗称“回调地狱”)
ES6的Promise是一个构造函数,用来生成promise实例

promise对象的3个状态

  • pending:初始化状态
  • fullfilled:成功状态
  • rejected:失败状态

基本用法

下面代码创造了一个promise实例。

let promise = new Promise((resolve, reject)=> {
  // ... some code

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve函数的作用是,将promise对象的状态从“未完成”变为“成功”(即从 pending 变为 fullfilled),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

promise实例生成以后,可以用then方法分别指定fullfilled状态和rejected状态的回调函数。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

DEMO:

function timeout(ms) {
    return new Promise((resolve, reject) => {
        setTimeout(resolve, ms, '执行成功');
        // setTimeout(reject, ms, '执行失败');
    });
}

timeout(0).then((msg) => {
    //调用resolve时执行
    console.log(msg);
}).catch((msg)=>{
    //调用reject时执行
    console.log(msg);
})

async 函数

ES2017 标准引入了 async 函数,使得异步操作变得更加方便。真正意义上解决异步回调的问题,同步流程表达异步操作
语法:

async function foo(){
    await 异步操作;
    await 异步操作;
}

特点:
1、返回的总是Promise对象,可以用then方法进行下一步操作
2、语义上更为明确,使用简单

DEMO:

写法一:

function promiseFunc()
{
    return new Promise((resolve,reject)=>{
        setTimeout(()=>{
            console.log('2秒后执行')
            let data = '异步执行结果'
            resolve(data)
        },2000)

    });
}

(async ()=>{
    console.log('开始执行')
    let result = await promiseFunc()
    console.log('result:',result)
    console.log('执行结束')
})()

写法二:

let promise = new Promise((resolve,reject)=>{
    setTimeout(()=>{
        console.log('2秒后执行')
        let data = '异步执行结果'
        resolve(data)
    },2000)

});

(async ()=>{
    console.log('开始执行')
    let result = await promise
    console.log('result:',result)
    console.log('执行结束')
})()

当程序执行到await时会阻塞,等待后面函数执行结果,这个函数返回的是Promise对象,Promise对象有三种状态,只有当状态变为成功或失败这两种状态中的一个时,程序才会执行下一步。

更多关于ES6的资料:
《阮一峰:ECMAScript 6 入门

发表评论

电子邮件地址不会被公开。 必填项已用*标注