在 **ES 6** 中,可以直接把默认值放在函数声明中:
//新的 JavaScript 定义方式
function fun2(height = 50, color = “red”, url = “http://www.baidu.com”){
…
}
在 **ES 6** 中,声明函数时,可以为任意参数指定默认值,在已指定默认值的参数后还可以继续声明无默认值的参数。
function fun3(height = 50, color = “red”, ur1){}
在这种情况下,只有在没有为 height 和 color 传值,或者主动为它们传入 undefined 时才会使用它们的默认值。
在 **ES 5** 中,无论在函数定义中声明了多少形参,都可以传入任意数量的参数,在函数内部可以通过 arguments 对象接收传入的参数。
function data(){
console.log(arguments);
}
data(“li”,“cc”;
在 **ES 6** 中引入了 rest 参数,在函数的命名参数前添加了3个点,用于获取函数的实参。rest 参数是一个数组,包含自它之后传入的所有参数,通过这个数组名就可以逐一访问里面的参数。
function data(…args){
console.log(args);
}
data(“苹果”,“香蕉”,“橘子”);
rest参数必须放到参数最后位置
function fn(a, b,…args){
console.log(a);
console.log(b);
console.log(args);
}
fn(100, 200, 300, 400, 500, 600);
### 4. 解构赋值
在 **ES 5** 中,如果需要从某个对象或者数组中提取需要的数据赋给变量,可以采用如下方式:
let goods = {
name : “苹果”,
city : “烟台”,
price : “烟台”
}
//提取对象中的数据赋给变量
let name = goods.name;
let city = goods.city;
let price = goods.price;
//提取数组中的数据赋给变量
let arr= [100, 200, 300, 400];
let a1 = arr[0], a2 = arr[1], a3 = arr[2], a4 =arr[3];
在 **ES 6** 中,通过使用解构赋值的功能,可以从对象和数组中提取数值,并对变量进行赋值数
#### 对象解构
对象解构的方法是在一个赋值操作符的左边放置一个对象字面量。
let goods = {
name : “苹果”,
city : “烟台”,
price : “烟台”
}
//使用解构赋值的功能
let {name,city,price} = goods;
如果变量已经声明了,之后想要用解构语法给变量赋值,则需要把整个解构赋值语句放到圆括号中。
let goods = {
name : “苹果”,
city : “烟台”,
price : “烟台”
}
//先声明变量,然后解构赋值
let name,city,price;
({name,city,pzice}= goods) ;
#### 数组解构
因为没有对象属性名的问题,所以数组解构相对比较简单,使用方括号即可。
let arr = [100,200, 300, 400];
let [a1,a2,a3,a4] = arr;
由于变量值是根据数组中元素的顺序进行选取的,因此,如果需要获取指定位置的元素值,可以只为该位置的元素提供变量名。
let arr = [100,200,300,400];
//获取第 4 个位置的元素
let [,a4] = arr;
console.log(a4); //输出 400
和对象解构不同,如果为已经声明过的变量进行数组解构赋值,不需要把整个解构赋值语句到一个圆括号中。
let arr =[100,200,300,400];
let a1, a2, a3, a4;
[a1, a2, a3, a4] = arr;
### 5. 展开运算符
展开运算符(Spread Operator)也是3个点,允许一个表达式在某处展开。展开运算符在多个参数(用于函数调用)、多个元素(用于数组字面量)或者多个变量(用于解构赋值)的地方可以使用。
#### 在函数调用中使用展开运算符
在 **ES 5** 中可以使用 apply 方法将一个数组展开成多个参数:
function test(a, b,c) {}
var args = [100, 200, 300};
test.apply(null, args);
上面的代码中,把args数组当作实参传递给了a、b和c。
在 **ES 6** 中可以更加简洁地来传递数组参数:
function test(a,b,c) {}
var args = [100, 200, 300];
test(…args) ;
这里使用展开运算符把 args 直接传递给 test 函数。
#### 在数组字面量中使用展开运算符
在 **ES 6** 中,可以直接加一个数组并合并到另一个数组中:
var arr1 = [‘a’, ‘b’, ‘c’];
var arr2 = […arr1, ‘d’, ‘e’]; //[‘a’,‘b’,‘c’,‘d’,‘e’]
展开运算符也可以用在 push 函数中,可以不需要再使用 apply 函数来合并两个数组:
var arr1 = [‘a’, ‘b’, ‘c’];
var arr2 = [‘d’, ‘e’];
arrl.push(…arr2); //[‘a’,‘b’,‘c’,‘d’,‘e’]
#### 用于解构赋值
解构赋值也是 **ES 6** 中新添加的一个特性,这个展开运算符可以用于部分情景:
let [argl,arg2,…,arg3]=[1, 2, 3, 4];
argl //1
arg2 //2
arg3 //[‘3’, ‘4’]
展开运算符在解构赋值中的作用跟之前的作用看上去是相反的,它将多个数组项组合成了一个新数组。
不过要注意,解构赋值中的展开运算符只能用在最后。
let [arg1,…,arg2,arg3] = [1, 2, 3, 4]; //报错
#### 类数组对象变成数组
展开运算符可以将一个类数组对象变成一个真正的数组对象:
var list = document.getElementsByTagName(‘div’);
var arr = […list];
list 是类数组对象,这里通过使用展开运算符使其变成了数组。
### 6. 增强的对象文本
**ES 6** 添加了一系列功能来增强对象文本,从而使得处理对象更加轻松。
#### 通过变量进行对象初始化
在 **ES 5** 中,对象的属性通常是由具有相同名称的变量创建的。例如:
var
a = 100,b = 200, c = 300;
obj = {
a : a,
b : b,
c : c
};
// obj.a = 100, obj.b = 200, obj.c = 300
在 **ES 6** 中,简化如下:
const
a = 100, b = 200, c = 300;
obj = {
a
b
c
};
#### 简化定义对象方法
在 **ES 5** 中,定义对象的方法需要 function 语句。例如:
var lib = {
sum : function(a, b) { return a + b;},
mult : function(a, b) { return a * b;}
};
console.log( lib.sum(100, 200)); // 300
console.log( lib.mult(100, 200)); // 20000
在 **ES 6** 中,定义对象的方法简化如下:
const lib = {
sum(a, b) { return a + b; },
mult(a, b) { return a * b; }
};
console.log( lib.sum(100,200));// 300
console.log( lib.mult(100, 200));//20000
这里不能使用 **ES 6** 的箭头函数(=>),因为该方法需要一个名称。如果直接命名每个方法,则可以使用箭头函数(=>)。例如:
const lib = {
sum : (a, b) => a + b,
mult : (a, b)=> a * b
};
console.log( lib.sum(100,200));// 300
console.log( lib.mult(100, 200)); //20000
#### 动态属性键
在 **ES 5** 中,虽然可以在创建对象之后添加变量,但是不能使用变量作为键名称。例如
var
key1 = ‘one’,
obj = {
two : 200,
three : 300
};
obj[key1] = 100;
//表示obj.one = 100,obj.two = 200, obj.three = 300
通过在方括号(Ⅱ)内放置表达式,可以在ES6中动态分配对象键。例如:
const
key1 = ‘one’,
obj = {
[key1]: 100,
two : 200,
three : 300
}
//表示obj.one = 100, obj.two = 200, obj.three = 300
#### 解构对象属性中的变量
在 **ES 5** 中,可以将对象的属性值提取到另一个变量中。例如:
var myobject = {
one : ‘洗衣机’,
two : ‘冰箱’,
three : ‘空调’
);
var
one = myobject.one,//洗衣机
two = myobject.two,//冰箱
three = myobject.three; //空调
在 **ES 6** 中,通过解构可以创建与等效对象属性同名的变量。例如:
var myobject = {
one : ‘洗衣机’,
two : ‘冰箱’,
three : ‘空调’
);
const { one, two, three } = myobject;
//表示one = ‘洗衣机’,two = ‘冰箱’,three = ‘空调’
### 7. 箭头函数
**ES 6** 新增了使用“箭头”声明函数,代码如下:
let f = v => v
//等同于
var f = function (v){
return v
}
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分,当函数的内容只有返回语句时,可以省去大括号和 return 指令,代码如下:
let f = () => 5
//等同于
var f = function () { return 5 }
let sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(numl, num2) {
return numl + num2
}
如果箭头数的内容部分多于一条语句,就要用大括号将它们括起来,并且使用 return 语句返回,代码如下:
let sum = (numl, num2) =>{
let num = 0;
return num1 + num2 + num;
}
箭头函数会默认绑定外层的上下文对象 this 的值,因此在箭头函数中,this 的值和外层的this 是一样的,不需要使用 bind 或者 call 的方法来改变函数中的上下文对象,例如下面的代码:
mounted () {
this.foo =1
setTimeout(function(){ // 打印出1
console.log(this.foo)
}.bind(this),200)
}
//相当于
mounted(){
this.foo = 1
setTimeout(()
console.log(this.foo) // 同样打印出1
),200)
}
上面的代码中,在 Vue.js 的 mounted 方法中,this 指向当前的 Vue 组件的上下文对象,如果想要在 setTimeout 的方法中使用 this 来获取当前 Vue 组件的上下文对象,那么非箭头函数需要使用 bind,箭头函数则不需要。
5. 对象属性和方法的简写
ES 6 允许在大括号中直接写入变量和函数,作为对象的属性和方法,这样的书写更加简洁,代码如下:
const foo = ‘bar’
const baz = {foo}
// 等同于
const baz = {foo: ‘bar’}
console.log(baz) // {foo: “bar”}
对象中如果含有方法,也可以将function关键字省去,代码如下:
{
name: ‘item’
data () {
return {
name: ‘bar’
}
}
mounted () {
},
methods: {
clearSearch () {
}
}
}
//相当于
{
name: ‘item’
data : function(){
return {
name: ‘bar’
}
}
mounted : function() {
},
methods: {
clearSearch : function() {
}
}
}
在上面的代码中,展示了采用 ES 6 语法来创建 Vue 组件所需的方法和属性,包括 name 属性、mounted 方法、data 方法等,是后面实战项目中经常使用的写法。
### 8. Modules (模块)
在 **ES 6** 版本之前,JavaScript 一直没有模块(Module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、 Python 的 import 甚至就连 CSS 都有 import ,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。
好在广大的 JavaScript 程序员自己制定了一些模块加载方案,主要有 CommonJS 和 AMD 两种。前者用于 Node.js 服务器,后者用于浏览器。
#### import 和 export
随着 **ES 6** 的到来,终于原生支持了模块化功能,即 import 和 export ,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范成为浏览器和服务器通用的模块化解决方案。
在 ES 6 的模块化系统中,一个模块就是一个独立的文件,模块中的对外接口采用 export 关键字导出,可以将 export 放在任何变量、函数或类声明的前面,从而将它们暴露给外部代码使用,代码如下:
export var name = “小明”;
export let age = 20;
//上面的写法等价于下面的写法
var name = "小明”;
let age = 20;
export {
name:name,
age:age
}
// export 对象简写的方式
export {name,age}
要导出函数,需要在函数前面加上 export 关键字:
export function sum(numl,num2){
return numl + num2;
}
//等价于
let sum = function (numl,num2){
return numl + num2;
}
export sum
所以,如果没有通过 export 关键字导出,在外部就无法访问该模块的变量或者函数。 有时会在代码中看到使用 export default,它和 export 具有同样的作用,都是用来导出对外提供接口的,但是它们之间还有一些区别:
* export default 用于规定模块的默认对外接口,并且一个文件只能有一个 export default,而 export可以有多个
* 通过 export 方式导出,在导入时要加{},export default 则不需要。
在一个模块中可以采用 import 来导入另一个模块 export 的内容。导入含有多个 export 的内存,可以采用对象简写的方式,也是现在使用比较多的方式,代码
// other.js
var name = “小明”
let age = 20
// export 对象简写的方式
export {name,age}
//import.js
import {name,age} from “other.js”
console.log(name) // 小明
console.log(age) // 20
导入只有一个 export default 的内容,代码如下:
//other.js
export default function sum(numl,num2){
return numl + num2;
}
//import.js
import sum from “other.is”
console.log(sum(1,1)) // 2
有时也会在代码中看到 module.exports 的用法,这种用法是从 Node.js 的 CommonJS 演化而来的
module.exports = xxx
//相当于
export xxx
### 9. Promise 和 async/await
#### Promise
Promise 是一种适用于异步操作的机制,比传统的回调函数解决方案更合理和更强大。从语法上说,Promise 是一个对象,从它可以获取异步操作的结果:成功或失败。在 Promise中,有三种状态:pending (进行中)、resolved (已成功)和 rejected (已失败)。只有异步操作的结果可以决定当前是哪一种状态,无法被 Promise 之外的方式改变。这也是 Promise 这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。创建一个 Promise 对象,代码如下:
var promise = new Promise(function(resolve, reject){
…
if (/*异步操作成功*/){
resolve(value);
}else{
reject(error);
}
});
在上面的代码中,创建了一个 Promise 对象,Promise 构造函数接受一个函数作为参数,该函数的两个参数分别是 resolve 和 reject 。这是两个内置函数,resolve 函数的作用是将 Promise 对象的状态变为“成功”,在异步操作成功时调用,并将异步操作的结果作为参数传递出去:reject 函数的作用是将 Promise 对象的状态变为“失败”,在异步操作失败时调用,并将异步操作报出的错误作为参数传递出去。当代码中出现错误(Error)时,就会调用catch 回调方法,并将错误信息作为参数传递出去。
Promise对象实例生成后,可以用 then 方法分别指定 resolved (成功)状态和 rejected (失败)状态的回调函数以及 catch 方法,比如:
promise.then(function(value){
// success 逻辑
}), function(error){
// failure 逻辑
}).catch(function(){
// error 逻辑
});
then 方法返回的是一个新的 Promise 实例(不是原来那个 Promise 实例)。因此,可以采用链式写法,即then 方法后面再调用另一个then)方法,比如:
getJSON(“/1.json”).then(function(post){
return getJSON(post.nextUrl);
}).then (function (data){
console.log(“resolved:”, data);
}, function (err){
console.log("rejected: ", err);
});
下面是一个用 Promise 对象实现的 Ajax 操作 get 方法的例子。
var getJSON = function(url){
//返回一个Promise对象
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();//创建 XMLHttpRequest 对象
client.open(“GET”,url) ;
client.onreadystatechange = onreadystatechange;
client.responseType = “json”; //设置返回格式为json
client.setRequestHeader(“Accept”,“application/json”);//设置发送格式为json
client.send();//发送
function onreadystatechange(){
if (this.readyState !== 4){
return;
}
if(this.status === 200){
resolve(this.response);
}else{
reject(new Error(this.statusText));
}
};
});
return promise;
);
getJSON(“/data.json”).then(function(data){
console.log(data);
}, function(error) {
console.error(error);
});
了解 Promise 的基本知识可以便于后续学习使用服务端渲染。当然,Promise 的应用场合还是比较多的,如果想要深入了解,可以访问网址:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global\_Objects/Promise,进行系统的学习。
#### async/await
async/await 语法在 2016 年就已经提出来了,属于 ES 7 中的一个测试标准(目前来看是直接跳过 ES 7,列为 ES 8 的标准了),它主要为了解决下面两个问题:
* 过多的嵌套回调问题
* 以Promise为主的链式回调问题
前面讲解过 Promise,虽然 Promise 解决了恐怖的嵌套回调问题,但是解决得并不彻底,过多地使用 Promise 会引发以 then 为主的复杂链式调用问题,同样会让代码阅读起来不那么顺畅,而 async/await 就是它们的救星。
async/await 是两个关键字,主要用于解决异步问题,其中 async 关键字代表后面的函数中有异步操作,await 关键字表示等待一个异步方法执行完成。这两个关键字需要结合使用。当函数中有异步操作时,可以在声明时在其前面加一个关键字async,代码如下:
async function myFunc(){
//异步操作
}
使用 async 声明的函数在被调用时会将返回值转换成一个 Promise 对象,因此 async 函数通过 return 返回的值会进入 Promise 的 resolved 状态,成为 then 方法中回调函数的参数,代码如下:
// myFunc()返回一个promise对象
async function myFunc(){
return ‘hello’;
}
//使用then方法就可以接收到返回值
myFunc().then (value => {
console.log(value);// hello
})
如果不想使用 Promise 的方式接收 myFunc() 的返回值,可以使用 await 关键字更加简洁地获取返回值,代码如下:
async function myFunc() {
return ‘hello’;
}
let foo = await myFunc();// hello
await 表示等待一个 Promise 返回,但是 await 后面的 Promise 对象不会总是返回resolved 状态,如果发生异常,则进入 rejected 状态,那么整个 async 异步函数就会中断执行,为了记录错误的位置和编写异常逻辑的代码,需要使用 try/catch,代码如下:
try{
let foo = await myFunc(); // hello
}catch(e){
//错误逻辑
console.log(e)
}
下面举一个例子,在后面的实战项目开发中,经常会用到数据接口请求数据,接口请求一般是异步操作,例如在 Vue 的 mounted 方法中请求数据,代码如下:
async mounted ()
//代码编写自上而下,一行一行,以便于阅读
let resp = await ajax.get(‘weibo/list’)
let top = resp [0]
console.log(top)
在上面的代码中,ajax.get 方法会返回一个 Promise,采用 await 进行了接收,并且 await 必须包含在一个用 async 声明的函数中。
可以看出,在使用了 async/await 之后,整个代码的逻辑更加清晰,没有了复杂的回调和烦的换行。
### 10. Classes(类)
在之前的 JavaScript 版本中,JavaScript 不支持类和类继承的特性,只能使用其他模拟类的定义和类的继承\*\*。ES 6\*\* 引入了类的概念,通过关键字 class 使类的定义更接近面向对象语言。
在 **ES 5** 中,没有类的概念,可以通过构造函数和原型混合使用的方式来模拟定义类。
function Goods(gName,gPrice) {
this.name = gName;
this.price = gPrice;
}
Goods.prototype.showName = function(){
console.log(this.name);
};
Var sGoods = new Goods("洗衣机”, 6800);
sGoods.showname();
在 **ES 6** 中,使用类可以改写上面的代码:
class Goods{
constructor(gName,gPrice) (
this.name = gName;
this.price = gPrice;
}
showName () {
console.log(this.name);
}
}
let sGoods = new Goods("洗衣机”,6800);
sGoods.showname();
在 **ES 6** 中,可以通过 extends 关键字来继承类:
class Goods{
constructor(gName) (
this.name = gName;
}
showName () {
console.log(this.name);
}
}
//通过extends关键字来继承类Goods
class Goods1 extends Goods{
constructor(gName,gPrice) {
super(gName); //调用父类的 constructor(gName)
this.price = gPrice;
}
}
let gl = new Goods1(“洗衣机”,6800);
gl.showname();
---
1. Angular.js 1 也叫作 AngularJS,是由 Google 公司在 2012 年发布的一个 JavaScript的 MVC框架,目前还有 Angular 2、Angular 4 两个版本。 [↩︎](#fnref1)
2. Hacker News 是一家关于计算机黑客和创业公司的社会化新闻网站,由保罗·格雷厄姆的创业孵化器 Y Combinator 创建,网站内容主要由来自用户提交的外链构成,是国外比较流行的技术信息交流网站之一 [↩︎](#fnref2)
3. Echo JS是一个由国外社区驱动的信息交流网站,网站内容主要由来自用户提交的外链构成,完全专注于JavaScript开发、HTML5和前端信息 [↩︎](#fnref3)
4. Reddit 是一个国外娱乐、社交及新闻网站,包含众多模块,注册用户可以将文字或链接提交到该网站上发布,使它基本上成为了一个电子布告栏系统 [↩︎](#fnref4)
5. Browserify是一个开源的前端模块打包工具,功能上和Webpack类似,但是名气不如Webpack [↩︎](#fnref5)
### 最后
如果你已经下定决心要转行做编程行业,在最开始的时候就要对自己的学习有一个基本的规划,还要对这个行业的技术需求有一个基本的了解。有一个已就业为目的的学习目标,然后为之努力,坚持到底。如果你有幸看到这篇文章,希望对你有所帮助,祝你转行成功。
**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**
![](https://img-blog.csdnimg.cn/img_convert/54a6b04f29167333b139d2753f60db9f.png)