这里写目录标题
- *01.let与const
- *02.类class
- * 03.模板字符串
- *04.箭头函数
- *05.对象字面量
- *06.解构赋值
- *07.Promise函数
- 09.模块概念
- 10.Symbol类型
- 11.proxy
- *12.set与map的区别
- *13.函数默认参数
- *14 拓展运算符
- 15.数组的拓展方法
- *16.for---of
- *17.Async +Await
- *18.Decorator装饰器
- 总结:
- reduce可以操作字符串,数组,第二个参数可以是数字0就是从0开始加法运算,第二个参数是[],就是数组的去重之类的操作,是对象{}就是对象的合并等方法
- map,filter,some 操作数组
- map对象可以替代switch case
- 数组去重可以用reduce,set
- 1.ECMAScript 6 / ECMAScript 2015 新增了哪些新特性?
- 2.箭头函数注意什么东西
- 3.set与map的区别
- 4.Promise有几种状态
- 5.这几种状态的关系
- 6.catch与reject的区别
- 7.for-each for-in for-of
- 8.Async +Await
- 9.怎么把异步执行操作变成同步执行
- 19.es6里面操作数组API 类似map和set map是干嘛用的 es6的对象结合,数组结合 ,找到序号是5的对象 Map.prototype.keys(5) - 返回键名的遍历器
ECMAScript 6 / ECMAScript 2015 新增了哪些新特性?
- 01.块级作用域let与const
- 02.类Class
- 03.模板字符串
- 04.箭头函数
- 05.字面量
- 06.解构赋值-解构赋值,函数.数组.对象扩展
- 07.Promise
- 08.Generator生成器
- 09.模块概念
- 10.Symbol类型
- 11.Proxy代理
- 12.Set & Map
- 13.函数默认参数
- 14.rest与展开运算符…
- 15…数组扩展-解构赋值,函数.数组.对象扩展
- 16.for of
- 17.Async
- 18.Decorator装饰器
*01.let与const
默认使用 const,只有当确实需要改变变量的值的时候才使用 let。这是因为大部分的变量的值在初始化后不应再改变,而预料之外的变量的修改是很多 bug 的源头;let在一个模块不能重复声明;
1.let不存在变量提升
var a=[];
for(var i=0;i<10;i++){
let c=i;//变成var的话 就是9
a[i]=function(){
console.log(c)
};
}
a[5]();//5
*02.类class
// 例子 1
//构造函数尽可能使用 Class 的形式
class Foo {
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
Foo.bar(); // hello
//例2
class person{
constructor(name='alex',age=18){
this.name=name;
this.age=age;
}
showname(){
console.log(this.name)
}
showage(){
console.log(this.age)
}
}
let v=new person();
v.showname()
v.showage()
import:es6的导入=== 属于加载前置的机制,因此将其全放在代码顶部,代码解析逐个import获取一个引入的列表,先引入依赖,再向下执行代码,加载前置
require :commonJs的导入===加载滞后,代码执行到哪一行才进行加载;if(true){letquerystring=require(‘querystring’) }
2.1.静态函数
function obj(){}
obj.prototype.age=1;//实例属性
obj.staticTest="abc"
let o=new obj();
这个用类class来表示
class obj{
myAge=123;
//静态属性
static staticAge=999;
static staticFn=function(){
console.log("静态函数")
}
//箭头函数才向上用的别人的this
myFn(){//上下文this与function是一致的,用的就是自己的
console.log("实例的函数",this.myAge)
}
}
let o1=new obj();
o1.myFn()
2.2继承
function P1(XXX){
this.xxx=xxx;
类似继承 this.prototype=p2.prototype
继承玩的就是原型链
}
//例1
实例继承
class Person{
age=100;
}
class Boy extends Person{
name="jack";
}
const p=new Boy();
console.log(p)
例2
class Person{
constructor(props){//这就是构造函数
this.age=props.age
console.log('触发了person')
}
}
class Boy extends Person{
constructor(props){
super(props)//初始化父类构造器class person
//先person 后Boy
this.name=props.name;
console.log('触发了Boy')
}
}
const p=new Boy({name:"apple",age:18});
console.log(p)
例3
class Shape {
constructor(width, height) {
this._width = width;
this._height = height;
}
get area() {
return this._width * this._height;
}
}
const square = new Shape(10, 10);
console.log(square.area); // 100
console.log(square._width); // 10
* 03.模板字符串
需要拼接字符串的时候尽量改成使用模板字符串
标签模板:
let x = 'Hi', y = 'jack';
var res = message`${x}, I am ${y}`;
function message(content, value1, value2) {
console.log(content); // [ "", ", I am ", "" ]
console.log(value1); // Hi
console.log(value2); // jack
}
这些参数将其拼合回去
function message(content, ...values) {
let result = '';
for (let i = 0; i < values.length; i++) {
result += literals[i];
result += values[i];
}
result += literals[literals.length - 1];
return result;
}
function message(content, ...values) {
let result = content.reduce((prev, next, i) => {
let value = values[i - 1];
return prev + value + next;
});
return result;
}
*04.箭头函数
注意什么东西
- 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
- 不可以当作构造函数,也就是说,不可以使用new关键字,否则抛出错误
- 不可以使用arguments对象,该对象在函数体内不存在(可用rest参数代替)
- 不可以使用yield命令,因此箭头函数不能用作Generator函数
====不能使用箭头函数的情况:
//例1
—使用箭头函数定义对象的方法
let foo = {
value: 1,
getValue: () => console.log(this.value)
}
foo.getValue(); // undefined
例2
var person = {
name:'alex',
fav:()=>{
console.log(this);//window
},
showName(){
console.log(this);//person
}
}
//例3
----定义原型方法
function Foo() {
this.value = 1
}
Foo.prototype.getValue = () => console.log(this.value)
let foo = new Foo()
foo.getValue(); // undefined
//例4
-----作为事件的回调函数
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
箭头函数的this指向
this指向问题;
ES5中 this永远指向最后调用它的那个对象;
var name = "window";
var a = {
name : null,
fn : function () {
console.log(this.name);
}
}
var f = a.fn;
f(); // console.log(window);
ES6中 箭头函数的指向;
- 箭头函数本身没有this对象,会引用外层函数或者对象的作用域。
- 箭头函数本身没有this对象,会沿着作用域链去查找this绑定的对象;是基于作用域链去找this对象;
- 箭头函数本身没有this对象,所以谈不上用call,apply,bind来改变this指向;
const name = 'window';
function out() {
setTimeout(()=> {console.log(this.name)});
}
const obj = {
name: 'hhhh'
};
out.apply(obj)
*05.对象字面量
05.1.增强的对象字面量
// 例子1
// bad
const something = 'y'
const x = {
something: something
}
// good
const something = 'y'
const x = {
something
};
05.2动态属性
// 例子2
const x = {
['a' + '_' + 'b']: 'z'
}
console.log(x.a_b); // z
*06.解构赋值
06.1.对象的基本解构
// 例子1
componentWillReceiveProps(newProps) {
this.setState({
active: newProps.active
})
}
componentWillReceiveProps({active}) {
this.setState({active})
}
// 例子 2
// bad
handleEvent = () => {
this.setState({
data: this.state.data.set("key", "value")
})
};
// good
handleEvent = () => {
this.setState(({data}) => ({
data: data.set("key", "value")
}))
};
06.2.对象深度解构
// 例子4
// bad
function test(fruit) {
if (fruit && fruit.name) {
console.log (fruit.name);
} else {
console.log('unknown');
}
}
// good
function test({name} = {}) {
console.log (name || 'unknown');
}
// 例子 5
let obj = {
a: {
b: {
c: 1
}
}
};
const {a: {b: {c = ''} = ''} = ''} = obj;
06.3.数组解构
// 例子6
// bad
const spliteLocale = locale.splite("-");
const language = spliteLocale[0];
const country = spliteLocale[1];
// good
const [language, country] = locale.splite('-');
06.4变量重命名
// 例子8
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
console.log(baz); // "aaa"
06.5仅获取部分属性
// 例子 9
function test(input) {
return [left, right, top, bottom];
}
const [left, __, top] = test(input);
function test(input) {
return { left, right, top, bottom };
}
const { left, right } = test(input);
*07.Promise函数
07.1 Promise有几种状态
Promise对象有以下特点
* 对象的状态不受外界影响,Promise对象代表一个异步操作,具有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
* 一旦状态改变,就不会再次改变
* 任何时候都可以得到结果
(Promise对象的状态改变,只有两种可能 1.从pending变为fulfilled 2.从pending变为rejected
只要这两种情况发生,状态就凝固了(不会再变化),会一直保持这个结果,这时就称为resolved(已定型),如果改变已经发生,再对Promise对象添加回调函数,也会立即得到这个结果
07.2. catch与reject的区别
reject - 返回一个新的 Promise 实例,该实例的状态为rejected
catch - 用于指定发生错误时的回调函数
07.2.1基本示例
// bad
request(url, function(err, res, body) {
if (err) handleError(err);
fs.writeFile('1.txt', body, function(err) {
request(url2, function(err, res, body) {
if (err) handleError(err)
})
})
});
// good
request(url)
.then(function(result) {
return writeFileAsynv('1.txt', result)
})
.then(function(result) {
return request(url2)
})
.catch(function(e){
handleError(e)
});
07.2.2.finally
fetch('file.json')
.then(data => data.json())
.catch(error => console.error(error))
.finally(() => console.log('finished'));
07.3手写promise
基础版
const p1 = new Promise((resolve, reject) => {
console.log('create a promise');
resolve('成功了');
})
console.log("after new promise");
const p2 = p1.then(data => {
console.log(data)
throw new Error('失败了')
})
const p3 = p2.then(data => {
console.log('success', data)
}, err => {
console.log('faild', err)
})
A+规范
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks= [];
let resolve = (value) => {
if(this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 依次将对应的函数执行
this.onResolvedCallbacks.forEach(fn=>fn());
}
}
let reject = (reason) => {
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 依次将对应的函数执行
this.onRejectedCallbacks.forEach(fn=>fn());
}
}
try {
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected) {
if (this.status === FULFILLED) {
onFulfilled(this.value)
}
if (this.status === REJECTED) {
onRejected(this.reason)
}
if (this.status === PENDING) {
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
});
// 如果promise的状态是 pending,需要将 onFulfilled 和 onRejected 函数存放起来,等待状态确定后,再依次将对应的函数执行
this.onRejectedCallbacks.push(()=> {
onRejected(this.reason);
})
}
}
}
总结:
promise 有三个状态:pending,fulfilled,or rejected;「规范 Promise/A+ 2.1」
new promise时, 需要传递一个executor()执行器,执行器立即执行;
executor接受两个参数,分别是resolve和reject;
promise 的默认状态是 pending;
promise 有一个value保存成功状态的值,可以是undefined/thenable/promise;「规范 Promise/A+ 1.3」
promise 有一个reason保存失败状态的值;「规范 Promise/A+ 1.5」
promise 只能从pending到rejected, 或者从pending到fulfilled,状态一旦确认,就不会再改变;
promise 必须有一个then方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected;「规范 Promise/A+ 2.2」
如果调用 then 时,promise 已经成功,则执行onFulfilled,参数是promise的value;
如果调用 then 时,promise 已经失败,那么执行onRejected, 参数是promise的reason;
如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 then 的失败的回调onRejected;
Promise.all([GetPlayList(data), GetPayTips(data)]).then((res) => {
this.performList = (res[0] && res[0].body && res[0].body.performList) || [];
var SESSION_BOOLEAN = res[0].body && res[0].body.clearSession;
var payCode = res[1].body && res[1].body.payTypes && res[1].body.payTypes[0] && res[1].body.payTypes[0].payCode;
// console.log(SESSION_BOOLEAN, '5555', res[1].body.payTypes[0], payCode);
localStorage.setItem('payCode', JSON.stringify(payCode));
this.payTypeTip = res[1].body.payTypes[0];
if (SESSION_BOOLEAN) {
this.dbclickHandle();
return;
}
});
7.4Promise 的链式调用,和axios处理高并发?
应用场景:下一个操作依赖于上一个操作的结果或状态;
前提条件:.then方法中必须返回一个promise对象
运行过程:
1…then在链式调用时,
会等其前一个then 中的回调函数执行完毕;
2.并且返回成功状态的promise,才会执行下一个then的回调函数
//链式调用,回调地域
axios.get(_api_1)
.then(_d1=>{
console.log(_d1.data)
axios.get(_api_2).then(_d2=>{
console.log(_d2.data)
axios.get(_api_3).then(_d3=>{
console.log(_d3.data)
})
})
})
//axios.get() 这就是个promise对象
//链式调用,ok的方法
axios.get(_api_1)
.then(_d1=>{
console.log(_d1.data)
return axios.get(_api_2)
})
.then(_d2=>{
console.log(_d2.data)
return axios.get(_api_3)
}).then(_d3=>{
console.log(_d3.data)
})
08.Generator生成器
Generator生成器与普通函数相比具有2个特征:
08.1.function与函数名之间有一个*。
当在调用生成器时,它不允许使用new关键字,也不会立即执行,而是返回一个Iterator对象,允许通过遍历器、for…of、解构语法等表达式执行。
每一个 yield 表达式,会使 Generator 生成一种新的状态,并转交控制权给外部函数,此时我们需要调用遍历器对象的next方法,才能使 Generator 继续执行。需要注意的是,Generator函数内部如果不存在yield表达式,它也不会立即执行,而是需要手动使用next方法触发:
function* test() { console.log(‘hello’) }
const fn = test(); // 没有任何输出
fn.next(); // hello
复制代码Generator函数结束的标志为 return,return 返回的值也会作为next方法返回对象的value,而此时 done 属性为:true(如果函数体内无 return 关键字,则会执行到函数结束,默认返回值为undefined)。
08.2.函数内部使用yield表达式。
yield表达式
yield表达式用于定义Generator不同的内部状态,它同时作为函数暂停的标志,将执行权交给外部的其他函数,并将 yield 关键字紧邻的表达式作为接下来遍历器的next()方法返回的对象的value键值。外部函数在调用了next()方法以后,Generator才得以恢复执行:
function* test() {
yield ‘hello’
yield ‘world’
return ‘!’
}
const executer = test();
executer.next(); // {value: “hello”, done: false}
executer.next(); // {value: “world”, done: false}
executer.next(); // {value: “!”, done: true}
for (item of test()) { console.log(item) } // hello world
09.模块概念
09.1.导出模块
// export1.js
// 导出变量
export let name = 'jack';
// 导出函数
export function print() {
console.log("function");
}
// 导出类
export class Person {
constructor(name) {
this.name = name;
}
}
// 私有函数
function privateFunction () {
console.log('我是私有函数,外部访问不了我');
}
// export2.js
// 导出变量
let name = 'jack';
// 导出函数
function print() {
return 'function';
}
// 导出类
class Person {
constructor(name) {
this.name = name;
}
}
// 私有函数
function privateFunction () {
return '我是私有函数,外部访问不了我';
}
export { name, print, Person }
09.2.导入模块
// import1.js
import { name, print, Person } from './export1.js';
console.log(name); //jack
console.log(print()); // function
// 报错, 不能定义相同名字变量
let name = 2333;
// 报错,不能重新赋值
name = "小猪";
10.Symbol类型
ES6引入了Symbol数据类型很好的解决了对象属性名冲突的问题。
唯一性
例1
// bad
// 1. 创建的属性会被 for-in 或 Object.keys() 枚举出来
// 2. 一些库可能在将来会使用同样的方式,这会与你的代码发生冲突
if (element.isMoving) {
smoothAnimations(element);
}
element.isMoving = true;
// good
if (element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__) {
smoothAnimations(element);
}
element.__$jorendorff_animation_library$PLEASE_DO_NOT_USE_THIS_PROPERTY$isMoving__ = true;
// better
var isMoving = Symbol("isMoving");
...
if (element[isMoving]) {
smoothAnimations(element);
}
element[isMoving] = true;
11.proxy
11.1Proxy 构造函数
在Es6 中 提供了原生的 Proxy 构造函数,可以用来生成 Proxy实例。
let p = {
name: ‘李四’
}
let proxy = new Proxy(p, {
get: function(target, property) {
if (property in target) {
retrun target[property]
} else {
console.log(‘报错’)
}
}
})
proxy.name // ‘李四’
proxy.age // ‘报错’
get方法可以继承
get方法可以进行链式操作
11.3. 使用 JavaScript Proxy 实现简单的数据绑定?
<body>
hello,world
<input type="text" id="model">
<p id="word"></p>
</body>
<script>
const model = document.getElementById("model")
const word = document.getElementById("word")
var obj= {};
const newObj = new Proxy(obj, {
get: function(target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function(target, key, value, receiver) {
console.log('setting',target, key, value, receiver);
if (key === "text") {
model.value = value;
word.innerHTML = value;
}
return Reflect.set(target, key, value, receiver);
}
});
model.addEventListener("keyup",function(e){
newObj.text = e.target.value
})
</script>
11.2.this指向
虽然 Proxy 可以代理针对目标对象的访问,但它不是目标对象的透明代理,即不做任何拦截的情况下,也无法保证目标对象的行为一致。主要原因就是在Proxy代理的情况下,目标对象内部的this关键字会指向Proxy代理
*12.set与map的区别
12.1.数组去重:
[…new Set(array)]
12.2.条件语句的优化 (Map)
原来:
// 根据颜色找出对应的水果
// bad
function test(color) {
switch (color) {
case 'red':
return ['apple', 'strawberry'];
case 'yellow':
return ['banana', 'pineapple'];
case 'purple':
return ['grape', 'plum'];
default:
return [];
}
}
test('yellow'); // ['banana', 'pineapple']
现在
// good
const fruitColor = {
red: ['apple', 'strawberry'],
yellow: ['banana', 'pineapple'],
purple: ['grape', 'plum']
};
function test(color) {
return fruitColor[color] || [];
}
// better
const fruitColor = new Map()
.set('red', ['apple', 'strawberry'])
.set('yellow', ['banana', 'pineapple'])
.set('purple', ['grape', 'plum']);
function test(color) {
return fruitColor.get(color) || [];
}
或者
function tests(color){
const myMap = new Map([
['red',['apple', 'strawberry']],
['yellow',['banana', 'pineapple']],
['purple',['grape', 'plum']],
])
return myMap.get(color) ? myMap.get(color) : [] ;
}
12.3.新的数据结构 Map
是 Es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是’键’的范围不限于字符串,各种类型的值(包括对象)都可以当作键,即 Map 提供了一种值 - 值的对应,是一种更完善的Hash结构实现
作为构造函数,Map 可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组
const map = new Map([[‘name’,‘张三’],[‘title’,‘Author’] ])
map.size // 2
map.has(‘name’) // true
map.get(‘name’) // ‘张三’
map.has(‘title’) // true
map.get(‘title’) // ‘Author’
总结Map实例的属性和方法 属性 Map.prototype.size - 返回Map实例的成员总数
12.4. 方法(操作方法 & 遍历方法)
* 操作方法
* Map.prototype.set(key,value) - 设置键名Key对应的键值Value,然后返回整个Map结构,如果Key已经存在,则键值更新
* Map.prototype.get(key) - 读取Key对应的键值,如果找不到则返回undefined
* Map.prototype.has(key) - 返回一个布尔值,表示某个键是否在当前Map对象中存在
* Map.prototype.delete(key) - 删除某个键,返回true,如果删除失败,则返回false
* Map.prototype.clear() - 清除所有成员,没有返回值
* 遍历方法
* Map.prototype.keys() - 返回键名的遍历器
* Map.prototype.values() - 返回键值的遍历器
* Map.prototype.entries() - 返回键值对的遍历器
* Map.prototype.forEach() - 使用回调函数遍历每个成员
12.5…es6里面操作数组API 类似map和set map是干嘛用的 **
es6的对象结合,数组结合 ,找到序号是5的对象 Map.prototype.keys(5) - 返回键名的遍历器
map基本用法跟forEach方法类似
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map()返回的是新数组,map() 不会改变原始数组。
语法:
array.map(function(currentValue,index,arr), thisValue)
参数说明:
function(currentValue, index,arr):
必须。函数,数组中的每个元素都会执行这个函数
函数参数:
currentValue 必须。当前元素的值
index 可选。当前元素的索引值
arr 可选。当前元素属于的数组对象
thisValue:
可选。对象作为该执行回调时使用,传递给函数,用作 "this" 的值。
如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
注意:
function(currentValue, index,arr)回调函数必须要return返回值,不然会返回一个undefind的数组
实际使用的时候,可以利用map方法方便获得对象数组中的特定属性值们。
实例:
var users = [
{name: "熊大", "email": "zhang@email.com"},
{name: "熊二", "email": "jiang@email.com"},
{name: "光头强", "email": "li@email.com"}
];
// emails => email的数组
var emails = users.map(function (user) { return user.email; });
12.6.新的数据解构 Set
Es 6 提供了新的数据结构Set,它类似于数组,但是成员的值是唯一的,没有重复的值
Set()接受一个数组(或者具有iterable接口的其他数据结构)作为参数,用来初始化
const arr = new Set([1,2,3,4,4])
console.log([…set]) // Array(4) [1, 2, 3, 4] […xxx]转化为Array
const items = new Set([1,2,3,4,5,5,5,5])
console.log(items) // Set(5) {1, 2, 3, 4, 5}
总结Set实例的属性和方法
- Set.prototype.constructor - 构造函数,默认就是Set函数 Set.prototype.size - 返回Set实例的成员总数
12.7.set 方法(操作方法 & 遍历方法)
* 操作方法
* Set.prototype.add(value) - 添加某个值,返回Set结构本身
* Set.prototype.delete(value) - 删除某个值,返回一个布尔值
* Set.prototype.has(value) - 返回一个布尔值,表示该值是否为Set成员
* Set.prototype.clear() - 清除所有成员,没有返回值
* 遍历方法
* Set.prototype.keys() - 返回键名的遍历器
* Set.prototype.values() - 返回键值的遍历器
* Set.prototype.entries() - 返回键值对的遍历器
* Set.prototype.forEach() - 使用回调函数遍历每个成员
*13.函数默认参数
13.1. 默认值
// 例子1
// bad
function test(quantity) {
const q = quantity || 1;
}
// good
function test(quantity = 1) {
...
}
// 例子2
doSomething({ foo: 'Hello', bar: 'Hey!', baz: 42 });
// bad
function doSomething(config) {
const foo = config.foo !== undefined ? config.foo : 'Hi';
const bar = config.bar !== undefined ? config.bar : 'Yo!';
const baz = config.baz !== undefined ? config.baz : 13;
}
// good
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 }) {
...
}
// better
function doSomething({ foo = 'Hi', bar = 'Yo!', baz = 13 } = {}) {
...
}
//例子3
// bad
const Button = ({className}) => {
const classname = className || 'default-size';
return <span className={classname}></span>
};
// good
const Button = ({className = 'default-size'}) => (
<span className={classname}></span>
);
// better
const Button = ({className}) =>
<span className={className}></span>
}
Button.defaultProps = {
className: 'default-size'
}
// 例子4
const required = () => {throw new Error('Missing parameter')};
const add = (a = required(), b = required()) => a + b;
add(1, 2) // 3
add(1); // Error: Missing parameter.
*14 拓展运算符
14.1 . arguments 转数组
// 例1
// bad
function sortNumbers() {
return Array.prototype.slice.call(arguments).sort();
}
// good
const sortNumbers = (...numbers) => numbers.sort();
14.2. 调用参数
// 例2
// bad
Math.max.apply(null, [14, 3, 77])
// good
Math.max(...[14, 3, 77])
// 等同于
Math.max(14, 3, 77);
14.3.构建对象
14.3.1.剔除部分属性,将剩下的属性构建一个新的对象
// 例子 3
let [a, b, ...arr] = [1, 2, 3, 4, 5];
const { a, b, ...others } = { a: 1, b: 2, c: 3, d: 4, e: 5 };
14.3.2.有条件的构建对象
// 例子 4
// bad
function pick(data) {
const { id, name, age} = data
const res = { guid: id }
if (name) {
res.name = name
}
else if (age) {
res.age = age
}
return res
}
// good
function pick({id, name, age}) {
return {
guid: id,
...(name && {name}),
...(age && {age})
}
}
14.3.3.合并对象
let obj1 = { a: 1, b: 2,c: 3 }
let obj2 = { b: 4, c: 5, d: 6}
let merged = {...obj1, ...obj2};
14.4.将对象全部传入组件(jsx)
````c
const parmas = {value1: 1, value2: 2, value3: 3}
<Test {...parmas} />
```
14.5.双冒号运算符
// 例子 1
foo::bar;
// 等同于
bar.bind(foo);
foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
15.数组的拓展方法
15.1. keys
//例 1
var arr = ["a", , "c"];
var sparseKeys = Object.keys(arr);
console.log(sparseKeys); // ['0', '2']
var denseKeys = [...arr.keys()];
console.log(denseKeys); // [0, 1, 2]
15.2.entries
// 例子 2
var arr = ["a", "b", "c"];
var iterator = arr.entries();
for (let e of iterator) {
console.log(e);
}
15.3. values
// 例子 16-3
let arr = ['w', 'y', 'k', 'o', 'p'];
let eArr = arr.values();
for (let letter of eArr) {
console.log(letter);
}
15.4. includes
// 例子 16-4
// bad
function test(fruit) {
if (fruit == 'apple' || fruit == 'strawberry') {
console.log('red');
}
}
// good
function test(fruit) {
const redFruits = ['apple', 'strawberry', 'cherry', 'cranberries'];
if (redFruits.includes(fruit)) {
console.log('red');
}
}
15.5 find
// 例子 16-5
var inventory = [
{name: 'apples', quantity: 2},
{name: 'bananas', quantity: 0},
{name: 'cherries', quantity: 5}
];
function findCherries(fruit) {
return fruit.name === 'cherries';
}
console.log(inventory.find(findCherries)); // { name: 'cherries', quantity: 5 }
15.6 findIndex
// 例子 16-6
function isPrime(element, index, array) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false;
}
}
return element > 1;
}
console.log([4, 6, 8, 12].findIndex(isPrime)); // -1, not found
console.log([4, 6, 7, 12].findIndex(isPrime)); // 2
*16.for—of
16.1. 遍历范围
for…of 循环可以使用的范围包括:
数组
Set
Map
类数组对象,如 arguments 对象、DOM NodeList 对象
Generator 对象
字符串
16.2. 优势
ES2015 引入了 for…of 循环,它结合了 forEach 的简洁性和中断循环的能力:
// 例子 6-1
for (const v of ['a', 'b', 'c']) {
console.log(v);
}
// a b c
for (const [i, v] of ['a', 'b', 'c'].entries()) {
console.log(i, v);
}
// 0 "a"
// 1 "b"
// 2 "c"
```
### 16.3. 遍历 Map
// 例子 6-2
```c
let map = new Map(arr);
// 遍历 key 值
for (let key of map.keys()) {
console.log(key);
}
// 遍历 value 值
for (let value of map.values()) {
console.log(value);
}
// 遍历 key 和 value 值(一)
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
// 遍历 key 和 value 值(二)
for (let [key, value] of data) {
console.log(key)
}
### 16.4遍历 flatMap 二维数组转一维数组
[1,[2],3].flatMap(v=>v)
16.4 for-each for-in for-of
for in 与 for of 的区别
- for in
- 遍历对象及其原型链上可枚举的属性
- 如果用于遍历数组,除了遍历其元素外,还会遍历数组对象自定义的可枚举属性及其原型链上的可枚举属性
- 遍历对象返回的属性名和遍历数组返回的索引都是字符串索引
- 某些情况下,可能按随机顺序遍历数组元素
- for of
- es6 中添加的循环遍历语法
- 支持遍历数组,类数组对象(DOM NodeList),字符串,Map 对象,Set 对象
- 不支持遍历普通对象
- 遍历后输出的结果为数组元素的值
- 可搭配实例方法 entries(),同时输出数组的内容和索引
forEach()
对数组每一项运行函数,没有返回值 (forEach无法中途跳出forEach循环,break、continue和return都不奏效。)
*17.Async +Await
async 是“异步”的简写,async 用于申明一个 function 是异步的,
async 是“异步”的简写,async 用于申明一个 function 是异步的, 而 await 用于等待一个异步方法执行完成,await 只能出现在 async 函数中
async await和generator的写法很像,就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成await
但async 函数对 Generator 函数做了改进:
17.1、内置执行器:Generator函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器.也就是说,async 函数的执行,与普通函数一模一样。
17.2、更好的语义:async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
17.3、更广的适用性: co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
async 函数是非常新的语法功能,新到都不属于 ES6,而是属于 ES7。目前,它仍处于提案阶段,但是转码器 Babel 和 regenerator 都已经支持,转码后就能使用。
async 的作用
17.4. async 函数负责返回一个 Promise 对象
如果在async函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve() 封装成 Promise 对象;
如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)
await 在等待什么
一般我们都用await去等带一个async函数完成,不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值,所以,await后面实际可以接收普通函数调用或者直接量
如果await等到的不是一个promise对象,那跟着的表达式的运算结果就是它等到的东西;
如果是一个promise对象,await会阻塞后面的代码,等promise对象resolve,得到resolve的值作为await表达式的运算结果
虽然await阻塞了,但await在async中,async不会阻塞,它内部所有的阻塞都被封装在一个promise对象中异步执行
Async Await使用场景
如上面的例子,当需要用到promise链式调用的时候,就体现出Async Await的优势;
假设一个业务需要分步完成,每个步骤都是异步的,而且依赖上一步的执行结果,甚至依赖之前每一步的结果,就可以使用Async Await来完成
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(`step1 with ${n}`);
return takeLongTime(n);
}
function step2(m, n) {
console.log(`step2 with ${m} and ${n}`);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(`step3 with ${k}, ${m} and ${n}`);
return takeLongTime(k + m + n);
}
async function doIt() {
console.time("doIt");
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(`result is ${result}`);
console.timeEnd("doIt");
}
doIt();
```c
17.5.代码更简洁
//例1
```c
// good
function fetch() {
return (
fetchData()
.then(() => {
return "done"
});
)
}
// better
async function fetch() {
await fetchData()
return "done"
};
//例2
// good
function fetch() {
return fetchData()
.then(data => {
if (data.moreData) {
return fetchAnotherData(data)
.then(moreData => {
return moreData
})
} else {
return data
}
});
}
// better
async function fetch() {
const data = await fetchData()
if (data.moreData) {
const moreData = await fetchAnotherData(data);
return moreData
} else {
return data
}
};
// 例3
// good
function fetch() {
return (
fetchData()
.then(value1 => {
return fetchMoreData(value1)
})
.then(value2 => {
return fetchMoreData2(value2)
})
)
}
// better
async function fetch() {
const value1 = await fetchData()
const value2 = await fetchMoreData(value1)
return fetchMoreData2(value2)
};
17.6.async 地狱
// 例子
// bad
(async () => {
const getList = await getList();
const getAnotherList = await getAnotherList();
})();
// good
(async () => {
const listPromise = getList();
const anotherListPromise = getAnotherList();
await listPromise;
await anotherListPromise;
})();
// good
(async () => {
Promise.all([getList(), getAnotherList()]).then(...);
})();
17.7.错误处理
// 例子
// good
function fetch() {
try {
fetchData()
.then(result => {
const data = JSON.parse(result)
})
.catch((err) => {
console.log(err)
})
} catch (err) {
console.log(err)
}
}
// better
async function fetch() {
try {
const data = JSON.parse(await fetchData())
} catch (err) {
console.log(err)
}
};
17.8.1.async函数返回的是一个Promise对象
function fn1(){ return new Promise(resolve=>{
setTimeout(function(){
msg='wait me 3000';
resolve(msg) },3000); }); }
async function asyncCall(){ var result=await fn1(); console.log(result); }
asyncCall();
17.9怎么把异步执行操作变成同步执行**
async/await的作用就是使异步操作以同步的方式去执行
*18.Decorator装饰器
// 例子1
class Math {
@log
add(a, b) {
return a + b;
}
}
// 例子 2
class Toggle extends React.Component {
@autobind
handleClick() {
console.log(this)
}
render() {
return (
<button onClick={this.handleClick}>
button
</button>
);
}
}
总结:
reduce可以操作字符串,数组,第二个参数可以是数字0就是从0开始加法运算,第二个参数是[],就是数组的去重之类的操作,是对象{}就是对象的合并等方法
map,filter,some 操作数组
map对象可以替代switch case
数组去重可以用reduce,set
1.ECMAScript 6 / ECMAScript 2015 新增了哪些新特性?
类Class
模板字符串
箭头函数
字面量
对象解构赋值
Promise
Generator生成器
模块概念
Symbol类型
Proxy代理
Set & Map
函数默认参数
rest与展开运算符…
块级作用域
2.箭头函数注意什么东西
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象
不可以当作构造函数,也就是说,不可以使用new关键字,否则抛出错误
不可以使用arguments对象,该对象在函数体内不存在(可用rest参数代替)
不可以使用yield命令,因此箭头函数不能用作Generator函数
3.set与map的区别
新的数据结构 Map
是 Es6 提供的一种新的数据结构,它类似于对象,也是键值对的集合,但是’键’的范围不限于字符串,各种类型的值(包括对象)都可以当作键,即 Map 提供了一种值 - 值的对应,是一种更完善的Hash结构实现
作为构造函数,Map 可以接受一个数组作为参数,该数组的成员是一个个表示键值对的数组
const map = new Map([[‘name’,‘张三’],[‘title’,‘Author’] ])
map.size // 2
map.has(‘name’) // true
map.get(‘name’) // ‘张三’
map.has(‘title’) // true
map.get(‘title’) // ‘Author’
总结Map实例的属性和方法 属性 Map.prototype.size - 返回Map实例的成员总数
方法(操作方法 & 遍历方法)
操作方法
Map.prototype.set(key,value) - 设置键名Key对应的键值Value,然后返回整个Map结构,如果Key已经存在,则键值更新
Map.prototype.get(key) - 读取Key对应的键值,如果找不到则返回undefined
Map.prototype.has(key) - 返回一个布尔值,表示某个键是否在当前Map对象中存在
Map.prototype.delete(key) - 删除某个键,返回true,如果删除失败,则返回false
Map.prototype.clear() - 清除所有成员,没有返回值
遍历方法
Map.prototype.keys() - 返回键名的遍历器
Map.prototype.values() - 返回键值的遍历器
Map.prototype.entries() - 返回键值对的遍历器
Map.prototype.forEach() - 使用回调函数遍历每个成员
新的数据解构 Set Es 6 提供了新的数据结构Set,它类似于数组,但是成员的值是唯一的,没有重复的值
Set()接受一个数组(或者具有iterable接口的其他数据结构)作为参数,用来初始化
const arr = new Set([1,2,3,4,4])
console.log([…set]) // Array(4) [1, 2, 3, 4] […xxx]转化为Array
const items = new Set([1,2,3,4,5,5,5,5])
console.log(items) // Set(5) {1, 2, 3, 4, 5}
总结Set实例的属性和方法
Set.prototype.constructor - 构造函数,默认就是Set函数 Set.prototype.size - 返回Set实例的成员总数
方法(操作方法 & 遍历方法)
操作方法
Set.prototype.add(value) - 添加某个值,返回Set结构本身
Set.prototype.delete(value) - 删除某个值,返回一个布尔值
Set.prototype.has(value) - 返回一个布尔值,表示该值是否为Set成员
Set.prototype.clear() - 清除所有成员,没有返回值
遍历方法
Set.prototype.keys() - 返回键名的遍历器
Set.prototype.values() - 返回键值的遍历器
Set.prototype.entries() - 返回键值对的遍历器
Set.prototype.forEach() - 使用回调函数遍历每个成员
4.Promise有几种状态
5.这几种状态的关系
Promise对象有以下特点
对象的状态不受外界影响,Promise对象代表一个异步操作,具有三种状态:pending(进行中)、fulfilled(已成功)、rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
一旦状态改变,就不会再次改变
任何时候都可以得到结果
(Promise对象的状态改变,只有两种可能 1.从pending变为fulfilled 2.从pending变为rejected
只要这两种情况发生,状态就凝固了(不会再变化),会一直保持这个结果,这时就称为resolved(已定型),如果改变已经发生,再对Promise对象添加回调函数,也会立即得到这个结果
6.catch与reject的区别
reject - 返回一个新的 Promise 实例,该实例的状态为rejected
catch - 用于指定发生错误时的回调函数
7.for-each for-in for-of
for in 与 for of 的区别
for in
-
遍历对象及其原型链上可枚举的属性
-
如果用于遍历数组,除了遍历其元素外,还会遍历数组对象自定义的可枚举属性及其原型链上的可枚举属性
-
遍历对象返回的属性名和遍历数组返回的索引都是字符串索引
-
某些情况下,可能按随机顺序遍历数组元素
for of
-
es6 中添加的循环遍历语法
-
支持遍历数组,类数组对象(DOM NodeList),字符串,Map 对象,Set 对象
-
不支持遍历普通对象
-
遍历后输出的结果为数组元素的值
-
可搭配实例方法 entries(),同时输出数组的内容和索引
forEach()
对数组每一项运行函数,没有返回值 (forEach无法中途跳出forEach循环,break、continue和return都不奏效。)
8.Async +Await
async 是“异步”的简写,async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成,await 只能出现在 async 函数中
async的内部阻塞 都在Promise对象中异步执行了,直接返回的就是promise对象 await会等promise对象resolve
.then已经被添加到链式回调
async await和generator的写法很像,就是将 Generator 函数的星号(*)替换成 async,将 yield 替换成await
但async 函数对 Generator 函数做了改进:
1、内置执行器:Generator函数的执行必须靠执行器,所以才有了 co 函数库,而 async 函数自带执行器.也就是说,async 函数的执行,与普通函数一模一样。
2、更好的语义:async 和 await,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。
3、更广的适用性: co 函数库约定,yield 命令后面只能是 Thunk 函数或 Promise 对象,而 async 函数的 await 命令后面,可以跟 Promise 对象和原始类型的值(数值、字符串和布尔值,但这时等同于同步操作)
async 函数是非常新的语法功能,新到都不属于 ES6,而是属于 ES7。目前,它仍处于提案阶段,但是转码器 Babel 和 regenerator 都已经支持,转码后就能使用。
async 的作用
async 函数负责返回一个 Promise 对象
如果在async函数中 return 一个直接量,async 会把这个直接量通过Promise.resolve() 封装成 Promise 对象;
如果 async 函数没有返回值,它会返回 Promise.resolve(undefined)
await 在等待什么
一般我们都用await去等带一个async函数完成,不过按语法说明,await 等待的是一个表达式,这个表达式的计算结果是 Promise 对象或者其它值,所以,await后面实际可以接收普通函数调用或者直接量
如果await等到的不是一个promise对象,那跟着的表达式的运算结果就是它等到的东西;
如果是一个promise对象,await会阻塞后面的代码,等promise对象resolve,得到resolve的值作为await表达式的运算结果
虽然await阻塞了,但await在async中,async不会阻塞,它内部所有的阻塞都被封装在一个promise对象中异步执行
Async Await使用场景
如上面的例子,当需要用到promise链式调用的时候,就体现出Async Await的优势;
假设一个业务需要分步完成,每个步骤都是异步的,而且依赖上一步的执行结果,甚至依赖之前每一步的结果,就可以使用Async Await来完成
function takeLongTime(n) {
return new Promise(resolve => {
setTimeout(() => resolve(n + 200), n);
});
}
function step1(n) {
console.log(step1 with ${n}
);
return takeLongTime(n);
}
function step2(m, n) {
console.log(step2 with ${m} and ${n}
);
return takeLongTime(m + n);
}
function step3(k, m, n) {
console.log(step3 with ${k}, ${m} and ${n}
);
return takeLongTime(k + m + n);
}
async function doIt() {
console.time(“doIt”);
const time1 = 300;
const time2 = await step1(time1);
const time3 = await step2(time1, time2);
const result = await step3(time1, time2, time3);
console.log(result is ${result}
);
console.timeEnd(“doIt”);
}
doIt();
9.怎么把异步执行操作变成同步执行
https://juejin.im/post/6844903984889593863
async/await的作用就是使异步操作以同步的方式去执行
1.async函数返回的是一个Promise对象
function fn1(){ return new Promise(resolve=>{ setTimeout(function(){ msg=‘wait me 3000’; resolve(msg) },3000); }); } async function asyncCall(){ var result=await fn1(); console.log(result); } asyncCall();
10.rem计算单位的原理
rem是相对于根元素html的font-size进行计算的
浏览器给的字体大小是16px,按照转化关系16px = 1rem
使用rem布局的时候,为了兼容不同的分辨率,我们应该要动态的修正根字体的大小,让所有的用rem单位的子元素跟着一起缩放,从而达到自适应的效果。
19.es6里面操作数组API 类似map和set map是干嘛用的 es6的对象结合,数组结合 ,找到序号是5的对象 Map.prototype.keys(5) - 返回键名的遍历器
map基本用法跟forEach方法类似
map() 方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
map() 方法按照原始数组元素顺序依次处理元素。
注意: map() 不会对空数组进行检测。
注意: map()返回的是新数组,map() 不会改变原始数组。
语法:
array.map(function(currentValue,index,arr), thisValue)
参数说明:
function(currentValue, index,arr):
必须。函数,数组中的每个元素都会执行这个函数
函数参数:
currentValue 必须。当前元素的值
index 可选。当前元素的索引值
arr 可选。当前元素属于的数组对象
thisValue:
可选。对象作为该执行回调时使用,传递给函数,用作 “this” 的值。
如果省略了 thisValue,或者传入 null、undefined,那么回调函数的 this 为全局对象。
注意:
function(currentValue, index,arr)回调函数必须要return返回值,不然会返回一个undefind的数组
实际使用的时候,可以利用map方法方便获得对象数组中的特定属性值们。
实例:
var users = [
{name: “熊大”, “email”: “zhang@email.com”},
{name: “熊二”, “email”: “jiang@email.com”},
{name: “光头强”, “email”: “li@email.com”}
];
// emails => email的数组
var emails = users.map(function (user) { return user.email; });