ES6经常听到,所以去看了一些视频了解一下,加上参考他人博客,总结出下面一些重要知识点
1.let
- 表示
变量
,相当于之前的 var 注意:
1.没有预编译,不存在变量提升
;- 在代码块内,只要let定义变量,在之前使用,都是报错;
- 先定义完,再使用;
- let 是块级作用域,而 var 是函数作用域。
2.不能重复定义;但能重新赋值;
3.for循环,for循环里面是父级作用域,里面又一个;- 补充一个变量提升知识:
在ES6之前,我们都是用var关键字声明变量。无论声明在何处,都会被视为声明在函数的最顶部(不在函数内即在全局作用域的最顶部)。这就是函数变量提升例如:1
2
3
4
5
6
7function aa() {
if(bool) {
var test = 'hello man'
} else {
console.log(test)
}
}
而上面的代码在执行时会经过预编译环节,如下:1
2
3
4
5
6
7
8
9
10function aa() {
var test // 变量提升
if(bool) {
test = 'hello man'
} else {
//此处访问test 值为undefined
console.log(test)
}
//此处访问test 值为undefined
}
`注意类型的区别:
- 基本类型:直接存储基本类型:字符串、数值、布尔类型、null、undefined
- 复制类型:通过引用的方式存储复杂类型:对象、数组、函数
`2.count
常量声明
,定义完变量必须有值,不能之后赋值,不能修改;声明的变量都会被认为是常量,意思就是它的值被设置完成后就
不能再修改
了。1
2const name = 'lux'
name = 'joe' //再次赋值此时会报错还有,如果const的是一个对象,对象所包含的值是可以被修改的。抽象一点儿说,就是
对象所指向的地址
没有变就行。1
2
3
4
5const student = { name: 'cc' }
// 没毛病
student.name = 'yy'
// 如果这样子就会报错了
student = { name: 'yy' }下面看一道实例面试题
1
2
3
4
5
6
7var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(function() { console.log(i) })
}
funcs.forEach(function(func) {
func()
})
这样的面试题是大家常见,很多同学一看就知道输出 10 十次
但是如果我们想依次输出0到9呢?
有两种解决方法。直接看一下代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// ES5告诉我们可以利用闭包解决这个问题
// 立即执行函数
//(function() {
// return function() {
// }
//})()
var funcs = []
for (var i = 0; i < 10; i++) {
funcs.push(
(function(value) {
return function() {
console.log(value)
}
})(i)
)
}
funcs.forEach(function(func) {
func()
})
1 | // 再来看看es6怎么处理的 |
3.块级作用域
- let和const都是块级作用域
- 在一个函数内部
- 在一个代码块内部
- 说白了
{}大括号内的代码块
即为let 和 const的作用域。 - 如:
let的作用域是在它所在当前代码块,但不会被提升到当前函数的最顶部。1
2
3
4
5
6
7
8function aa() {
if(bool) {
let test = 'hello man'
} else {
//test 在此处访问不到
console.log(test)
}
}
4.结构赋值
因为解构能减少临时引用属性
- 非常有用,特别是在做数据交互 ajax;
(let[a,b,c] = [1,2,3])
注意:左右两边,结构保持一致 - 解构时可以给初始值
let[a,b,c='默认值'] = ['aaa','bbb];
5.字符串模板
1.基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}
来界定引用变量,且可以随意换行。1
2
3
4
5
6//ES5
var name = 'lux'
console.log('hello' + name)
//es6
const name = 'lux'
console.log(`hello ${name}`) //hello lux
2.在ES5时我们通过反斜杠(\)
来做多行字符串或者字符串一行行拼接。ES6反引号(`
)`直接搞定。1
2
3
4
5
6
7
8// ES5
var msg = "Hi \
man!
"
// ES6
const template = `<div>
<span>hello world</span>
</div>
3.字符串ES6当然也提供了很多厉害也很有意思的方法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18// 1.includes:判断是否包含字符串,然后直接返回布尔值
const str = 'hahay'
console.log(str.includes('y')) // true
// str.indexOf(要找的东西) 返回索引(位置),没找到返回-1;
// 2.repeat: 获取字符串重复n次
const str = 'he'
console.log(str.repeat(3)) // 'hehehe'
//如果你带入小数, Math.floor(num) 来处理
// s.repeat(3.1) 或者 s.repeat(3.9) 都当做成 s.repeat(3) 来处理
// 3. startsWith 和 endsWith 判断是否以 给定文本 开始或者结束
const str = 'hello world!'
console.log(str.startsWith('hello')) // true
console.log(str.endsWith('!')) // true
//4.str.padStart(整个字符串长度,填充东西) 玩前填充
str.padStart(整个字符串长度,填充东西) 玩后填充
4.字符串超过 80 个字节应该使用字符串连接号换行;
5.字符串连接例子:1
2
3
4
5
6
7
8
9
10// bad
const errorMessage = 'This is a super long error that was thrown because \
of Batman. When you stop to think about how Batman had anything to do \
with this, you would get nowhere \
fast.';
// good
const errorMessage = 'This is a super long error that was thrown because ' +
'of Batman. When you stop to think about how Batman had anything to do ' +
'with this, you would get nowhere fast.';
6. 函数变化
函数声明代替函数表达式
因为函数声明是可命名的,所以他们在调用栈中更容易被识别。此外,函数声明会把整个函数提升(hoisted),而函数表达式只会把函数的引用变量名提升。这条规则使得箭头函数可以取代函数表达式1
2
3
4
5//bad
const foo = function () {};
//good
function foo() {};函数的默认参数
1
2
3
4function show({x=0,y=0}={}){
console.log(x,y);
}
show();函数参数默认值若已经定义,则不能再使用let、const声明
1
2
3
4
5function show({x=10){
let x = 101; //错误
console.log(x);
}
show();扩展运算符–reset运算符
- 展开数组
- … :[1,2,3] -> …[1,2,3] -> 1,2,3;
- 1,2,3 -> …1,2,3 -> [1,2,3]
- 剩余参数,必须放到最后
- 展开数组
箭头函数
=>
当你必须使用函数表达式(或传递一个匿名函数)时
箭头函数最直观的三个特点:- 不需要 function 关键字来创建函数
- 省略 return 关键字
- 继承当前上下文的 this 关键字
1 | //例如: |
1 | let show() = {} => 1; |
注意:
- this问题,定义所在的对象,不再是运行时所在的对象(即不再是函数谁调用就指向谁)
- 箭头函数里面没有arguments,用
...
;...
能明确你要传入的参数。另外 rest 参数是一个真正的数组,而arguments
是一个类数组。 - 箭头函数不能当构造函数;
- 来道笔试题:
1 | // 请使用ES6重构以下代码 |
1 | const calculate = (x, y, z) => { |
构造函数:总是使用
class
,避免直接操作prototype
为什么? 因为 class 语法更为简洁更易读。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//bad
function Queue(content = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queuep[0];
this._queue.splice(0, 1);
return value;
}
}使用
extends
继承
为什么:因为extends
是一个內建的原型继承方法并且不会破坏instanceof
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53// bad
const inherits = require('inherits');
function PeekableQueue(contents) {
Queue.apply(this, contents);
}
inherits(PeekableQueue, Queue);
PeekableQueue.prototype.peek = function() {
return this._queue[0];
}
//good
class PeekableQueue extends Queue {
peek() {
return this._queue[0];
}
}
### 7. 数组
* 1.ES5里面新增的一些东西
* 循环:
1.for循环:for(let i = 0; i < arr.length; i++){};
2.while循环
* arr.forEach() //代替普通for循环
arr.forEach(function(val,index,arr){
comsole.log(val,index,arr);
})
* arr.map()
// 非常有用,做数据交互 ‘映射’;
//正常情况下,需要配合return,返回一个新数组;
// 若是没有return,相当于forEach;
// 注意:平常用到map,一定要配合return
* arr.filter()
// 过滤,过滤一些不合格的“元素”; 如果函数返回turn,就留下来;
* arr.some()
// 类似查找,数组里面某一个元素符合条件,返回turn;
* arr.every()
// 数组里面所有元素都要符合条件,才返回turn;
**注意: 其实他们都可以接受两个参数;
循环回调函数,this指向谁;**
* arr.reduce()
// 从左往右,求数组的和,阶乘
* arr.reduceRight()
// 从右往左,求数组的和,阶乘
* ES2017新增一个运算符:
* 幂运算符: Math.pow(2,3) 相当于 2 ** 3;
-----------------------------------------------------
* for...of...:
arr.keys() //数组下标;
arr.entries() //数组某一项;
```javascript
for(let val of arr){
console.log(val);
}数组新增
1.使用字面值创建数组:1
2
3
4
5// bad
const items = new Array();
// good
const items = [];
2.向数组添加元素时使用 Arrary#push 替代直接赋值:1
2
3
4
5
6
7const someStack = [];
// bad
someStack[someStack.length] = 'abracadabra';
// good
someStack.push('abracadabra');
3.使用拓展运算符 … 复制数组。1
2
3
4
5
6
7
8
9
10
11// bad
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// good
const itemsCopy = [...items];
- 扩展运算符
- let arr = [1,2,3];
- let arr2 = […arr];
- let arr2 = Array.from(arr);
- Array.from:
- 作用:把类数组(获取一组元素、arguments…)对象转成数组;
- 个人观点:具备length这个东西,就靠谱(json没length,但添加后也可使用);
- Array.of(): 把一组值,转成数组;
- let arr = Array.of(‘a’,’b’,’c’);
- arr.find(): 查找,找出一个符合条件的数组成员,如果没有找到,返回undefined;
- arr.findindex():找到的是位置,没找到返回-1;
- arr.fill(): 填充
- arr.fill(填充的东西,开始位置,结束位置);
- 在ES2016里面新增:
- arr.indexOf();
- arr.includes();
8.对象
使用字面值创建对象。
1
2
3
4
5// bad
const item = new Object();
// good
const item = {};使用对象方法的简写:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
311.
// bad
const atom = {
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
value: 1,
addValue(value) {
return atom.value + value;
},
};
2.
const lukeSkywalker = 'Luke Skywalker';
// bad
const obj = {
lukeSkywalker: lukeSkywalker,
};
// good
const obj = {
lukeSkywalker,
};
9.模块
1.总是使用模组 (import
/export
) 而不是其他非标准模块系统
为什么?模块就是未来,让我们开始迈向未来吧。1
2
3
4
5
6
7
8
9
10
11// bad
const AirbnbStyleGuide = require('./AirbnbStyleGuide');
module.exports = AirbnbStyleGuide.es6;
// ok
import AirbnbStyleGuide from './AirbnbStyleGuide';
export default AirbnbStyleGuide.es6;
// best
import { es6 } from './AirbnbStyleGuide';
export default es6;
2.模块化-export和import1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108//mod.js
// 第一种模块导出的书写方式(一个个的导出)
// 导出普通值
export let a = 12;
export let b = 5;
// 导出json
export let json = {
a,
b
};
// 导出函数
export let show = function(){
return 'welcome';
};
// 导出类
export class Person{
constructor(){
this.name = 'jam';
}
showName(){
return this.name;
}
}
//index.js
//导出模块如果用default了,引入的时候直接用,若没有用default,引入的时候可以用{}的形式
// 导入模块的方式
import {
a,
b,
json,
show,
Person
} from './mod.js';
console.log(a); // 12
console.log(b); // 5
console.log(json.a); // 12
console.log(json.b); // 5
console.log(show()); // welcome
console.log(new Person().showName()); // jam
//mod1.js
// 第二种模块导出的书写方式
let a = 12;
let b = 5;
let c = 10;
export {
a,
b,
c as cc // as是别名,使用的时候只能用别名,特别注意下
};
//index1.js
// 导入模块的方式
import {
a,
b,
cc // cc是导出的,as别名
} from './mod1.js';
console.log(a); // 12
console.log(b); // 5
console.log(cc); // 10
//mod2.js
// 第三种模块导出的书写方式 ---> default
// default方式的优点,import无需知道变量名,就可以直接使用,如下
// 每个模块只允许一个默认出口
var name = 'jam';
var age = '28';
export default {
name,
age,
default(){
console.log('welcome to es6 module of default...');
},
getName(){
return 'bb';
},
getAge(){
return 2;
}
};
//index2.js
// 导入模块的方式
import mainAttr from './mod2.js';
var str = ' ';
// 直接调用
console.log(`我的英文名是:${mainAttr.name}我的年龄是${mainAttr.age}`);
mainAttr.default(); // welcome to es6 module of default...
console.log(mainAttr.getName()); // bb
console.log(mainAttr.getAge()); // 2
//mod3.js
var name = 'jam';
var age = '28';
export function getName(){
return name;
};
export function getAge(){
return age;
};
//index3.js
// 导入模块的方式
import * as fn from './mod3.js';
// 直接调用
console.log(fn.getName()); // jam
10.class和extends
1 | //传统面向对象写法 |
11.promise:承诺,许诺
- 作用:解决异步回调问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91//传统方法:大部分回调函数,事件:
ajsx(url,{ //获取token
ajax(url,0=>{ //获取用户信息
ajax(url,{}=>{
//获取用户相关新闻
})
}
})
//Promise对象 ---> 用来传递异步操作过来的数据的
//Pending(等待、处理中) ---> Resolve(完成,fullFilled) ---> Reject(拒绝,失败)
var p1 = new Promise(function(resolve,reject){
resolve(1); // 成功了
// reject(2); // 失败了
});
// 接收成功和失败的数据,通过then来传递
// then也是返回一个promise对象,会继续往下传递数据,传递给下一个then
p1.then(function(value){
// resolve
console.log(value);
return value + 1; // 1
alert(`成功了:${value}`);
},function(value){
// reject
alert(`失败了:${value}`);
}).then(function(value){
console.log(value); // 2
});
//catch捕获异常错误
var p1 = new Promise(function(resolve,reject){
resolve('成功了');
});
p1.then(function(value){
console.log(value);
// throw是用来抛错误的
throw '发生了点小意外';
}).catch(function(e){
// catch用来捕获这个错误的 ---> 追踪
console.log(e);
});
//all ---> 全部,用于将多个promise对象,组合,包装成
//Promise.all([p1,p2,p3,...]); 所有的promise对象,都正确,才走成功
//否则,只要有一个错误,就走失败
var p1 = Promise.resolve(1);
var p2 = Promise.reject(0);
Promise.all([true,p1,p2]).then(function(obj){
console.log(`成功了:${obj}`);
},function(obj){
console.log(`失败了:${obj}`);
});
// race ---> 返回的也是一个promise对象
//最先执行的的promise结果,哪个最快我用哪个
var p1 = new Promise(function(resolve,reject){
setTimeout(resolve,50,'one');
});
var p2 = new Promise(function(resolve,reject){
setTimeout(resolve,100,'two');
});
Promise.race([p1,p2]).then(function(val){
console.log(val);
});
//resolve ---> 生成一个成功的promise对象
//语法规则:Promise.resolve(val); // 普通值
// Promise.resolve(arr); // 数组之类
//Promise.resolve(promise); // 传递另一个promise对象
//传递普通值
Promise.resolve('success').then(function(val){
// 注意resolve,走得是这里
console.log(val); // success
},function(err){
console.log("err:"+ err);
});
//传递数组
Promise.resolve([1,2,3]).then(function(val){
// 注意resolve,走得是这里
console.log(val); // [1,2,3]
},function(err){
console.log(err);
});
//传递一个promise对象
var p1 = Promise.resolve(520);
var p2 = Promise.resolve(p1);
p2.then(function(val){
//从p1那边传递过来的
console.log(val); // 520
});
11.Generator,yield
1 | //Generator ---> 生成器就是一个函数 |
属性
使用
.
来访问对象的属性1
2
3
4
5
6
7
8
9
10const luke = {
jedi: true,
age: 28,
};
//bad
const isJedi = luke['jedi'];
//good
const isJedi = luke.jedi;当通过变量访问属性时使用中括号
[]
1
2
3
4
5
6
7
8
9
10const luke = {
jedi: true,
age: 28,
};
function getProp(prop) {
return luke[prop];
}
const isJedi = getProp('jedi');
比较运算符 & 等号
- 优先使用
===
和!==
而不是==
和!=
。 - 条件表达式例如
if 语句
通过抽象方法ToBoolean
强制计算它们的表达式并且总是遵循下面 的规则:对象
被计算为true
Undefined
被计算为false
Null
被计算为false
布尔值
被计算为 布尔的值数字
如果是+0、-0、或NaN
被计算为false
,否则为true
字符串
如果是空字符串被计算为 `false`,否则为`true` 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
### 注释
* 使用`/**.....*/`作为多行注释,包括描述、指定所有参数和返回值的类型和值
* 使用 `//` 作为单行注释,在评论对象上面另起一行使用单行注释。在注释前插入空行。
```javascript
// good
/**
* make() returns a new element
* based on the passed in tag name
*
* @param {String} tag
* @return {Element} element
*/
function make(tag) {
// ...stuff...
return element;
}
更多细节
参考:https://www.w3cschool.cn/rtuhtw/
一个不错的ES6教学视频:http://study.163.com/course/courseMain.htm?courseId=1005211046
参考來源:简书;作者:陈嘻嘻啊;链接:https://www.jianshu.com/p/287e0bb867ae
参考來源:简书; 作者:前端工程狮_jam 链接:https://www.jianshu.com/p/384fa7cbaa63