ES6简介
- ECMACScript6.0 ES6 -> ES2015
- es7 -> ES2016
ES6问题
浏览器兼容的问题
- babel 把es6代码转换成es5
- babeljs.io/repl/ 通过babel将高级代码转化成es5
- chrome浏览器 一般采用62以上 import export
特性
let&const
es6 提供了新的声明方式替代了以前的var
var的弊端
- var 不支持封闭作用域,会声明到全局作用域上
(function () {
for (var i = 0; i < 3; i++) {
console.log(i);
}
})();
console.log(i);
console.log(window.i);
let的好处
- let和{}配和可以产生一个作用域
- let支持块级作用域声明的变量只会声明在当前作用域内
- let可以解决 作用域污染问题和局部作用域的问题
for (let i = 0; i < 3; i++) {
setTimeout(function () {
console.log(i);
}, 1000);
}
console.log(i);
- 在同一个作用域下可以多次声明同一个变量(如果用let声明过了 就不要再用var了)
function b(){
let a =1
let b =2
}
b()
- 域解释问题(变量提升问题)用let解决这个问题
- 暂存死区,如果作用域内 有这样一个变量 那么这个作用域内就会绑定这个变量,不会继续向上查找了
let a = 1;
{
console.log(a);
let a = 2;
}
const的好处
- 通过const声明的变量不能被修改,不能被修改引用空间
const a = {name:'zfpx'};
a.age = 9;
console.log(a);
// 不能修改变量的地址
解构赋值
解构赋值是指声明和赋值都放到一起了
- 解构 表示等号左边和右边解构类似
- 数组的必须位置相同
- 采用:的形式进行更改名字,取个别名
- 必须采用=号的方式,设置属性默认值
let [, age] = ['aa', 9];
// 对象解构时名字必须相同
let { length } = ['aa', 9];
console.log(length);
// 如果有关键字可以采用:的形式进行更改名字,取个别名
let { name, age, default: d } = { name: 'aa', age: 9, default: 'xxx' };
console.log(d);
// 如果想设置某个属性的默认值 必须采用=号的方式
let [, { address: [, a] }, hobby = '游泳'] = [
{ name: 'hs' },
{ age: 9, address: [1, 2, 3] },
]
console.log(hobby);
模板字符串
模板字符串取代了原有的字符串拼接功能
- 可以支持换行 可以支持取值
let name = 'hs';
let age = 9;
let ul = `<ul>
<li>${name}</li>
<li>${age}</li>
</ul>`;
console.log(ul);
- 实现一个类模板字符串的功能
let name = 'hs';
let age = 9;
let str = 'hello~${name}今年${age}岁了';
str = str.replace(/\$\{([^}]*)\}/g, function () {
console.log(arguments)
return eval(arguments[1]); // with
});
console.log(str);
- 实现带标签的模板字符,变量前后加字符
let name = 'hs';
let age = 9;
function jw() { // 第一个参数是字符串的数组 第二个参数是第一个变量。。。
let strings = arguments[0];
// Array.prototype.slice.call()
let values = [].slice.call(arguments, 1);
let str = ''
for (let i = 0; i < values.length; i++) {
str += `${strings[i]}*${values[i]}*`;
}
str += strings[strings.length - 1];
return str
}
let str = jw`hello~${name}今年${age}岁了`;
- includes 是否包含
let url = 'http://a.com/logo.png';
console.log(url.includes('a'));
- startsWith 以xxx开头
console.log(url.startsWith('http://'))
- endsWith 以xxx结尾
console.log(url.endsWith('.png'))
-
padStart padEnd 补全
不足多少位,补某个字符
// 进制转化
setInterval(function () {
let date = new Date();
let hour = date.getHours();
let minutes = date.getMinutes();
let seconds = date.getSeconds();
let str = `${hour.toString().padStart(2, 0)}:`;
str += `${minutes.toString().padStart(2, 0)}:`;
str += `${seconds.toString().padStart(2, 0)}`;
console.log(str)
}, 1000)
箭头函数
箭头函数 es6 写起来简单 可以解决this的问题
- 箭头函数没有function的关键字
- 小括号和大括号之间有个箭头
- 如果参数是一个 可以省略小括号
- 如果没有return 可以不写大括号
- 如果直接返回的是对象类型 需要()包裹
- 箭头函数中没有arguments
解决this指向
- 解决this的问题 var that = this;
- 通过bind方式绑定this (call apply)
- 箭头函数 箭头函数中没有this指向
注意:对象不是作用域, let声明的也不会被声明到全局上
let a = 1;
let obj = {
a:2,
b:()=>{
console.log(a);
}
}
obj.b();
// 箭头函数中没有arguments
// ... 叫剩余运算符 就是把多余的都放到数组中(放到最后一个)
let fn = (...arguments) =>{
let args = arguments.slice(1);
console.log(args);
}
fn('x',1,2,3,4,5);
// 函数可以赋予默认参数
let fn = (a=1,b=2)=>{
console.log(a,b)
}
fn();
展开运算符
function spread(x, ...args) {
sum(...args); //展开运算符
}
function sum(a, b, c, d) {
console.log(a, b, c, d)
}
spread('x', 1, 2, 3, 4);
- ...是浅拷贝
let name = { name: 'zfpx' };
let age = { age: 9 };
let school = { ...name, ...age };
console.log(school);
- slice是浅拷贝 如果拷贝一层就是深拷贝
let b = [1, 2, 3]
let a = [b];
let c = a.slice(0); // 是深拷贝 还是浅拷贝
b[0] = 100;
console.log(c);
- 深拷贝的实现
let obj = { a: 1, fn: function (params) { }, t: /a/, d: new Date(), a: null }
console.log(JSON.parse(JSON.stringify(obj)));
// JSON.stringify有缺陷,只能处理JSON,还不支持函数
// 实现深拷贝 保留继承关系 可以实现各种类型的拷贝 实现递归拷贝
function deepClone(obj) {
if (typeof obj !== 'object') return obj;
if (obj == null) return null;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
let o = new obj.constructor(); // 保留类的继承关系
for (let key in obj) {
o[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key]
}
return o;
}
let o = { a: { a: 1 } }
let newObj = deepClone(o);
o.a.a = 2;
console.log(newObj);
数组的方法
- reduce 返回的结果是叠加后的结果
// 函数的返回结果会作为下一次循环的prev
let result = [1, 2, 3, 4, 5].reduce((prev, next, currIndex, ary) => {
console.log(prev, next, currIndex, ary)
if (currIndex === ary.length - 1) {
return (prev + next) / ary.length
}
return prev + next;
});
console.log(result);
Array.prototype.myReduce = function (fn, prev) {
for (let i = 0; i < this.length; i++) {
if (typeof prev === 'undefined') {
prev = fn(this[i], this[i + 1], i + 1, this);
++i; // 保证下次取值时是正确的结果
} else {
prev = fn(prev, this[i], i, this);
}
}
return prev;
}
let total = [1, 2, 3].myReduce((prev, next, currIndex, ary) => {
return prev + next
}, 0);
console.log(total);
- 展开
let flat = [[1, 2, 3], [4, 5, 6]].reduce((prev, next, index, ary) => {
return [...prev, ...next];
});
console.log(flat);
- 手写forRach
Array.prototype.forEach = function (fn) {
for (let i = 0; i < this.length; i++) {
fn(this[i], i);
}
}
;[1, 2, 3].forEach((item, index) => {
console.log(item, index);
})
- 手写 map返回值 返回值是一个新数组
Array.prototype.map = function (fn) {
let arr = [];
for (let i = 0; i < this.length; i++) {
arr.push(fn(this[i], i));
}
return arr;
};
let arr = [1, 2, 3].map(item => {
return item * 2;
});
console.log(arr);
- filter 过滤 如果返回true表示留下 返回false表示删除
let arr = [1, 2, 3];
let filterArr = arr.filter(item => {
return item > 2;
});
console.log(filterArr);
- find 查找 他会返回查找的那一项,没有返回undefined 找到后就不会继续查找了
let f = [1, 2, 3].find(item => {
return item === 5;
});
console.log(f);
- some找到后返回true,找false可以用every
let r = [2, 1, 3].every(item => {
console.log(item);
return item === 1;
});
console.log(r);
- includes
[1, 2, 3].includes(3)
- 将类数组转化成数组
- 常见的类数组有 htmlCollection arguments {0:1,1:2,2:3,length:3}
function a(){
console.log(eval(Array.from(arguments).join('+')))
}
a(1,2,3);
// of()
let ary = Array.of(3);
console.log(ary)// [3];
对象
- Object.assign浅拷贝
let name = {name:"hs"};
let age = {age:9};
let obj = Object.assign(name,age);// 浅拷贝
console.log({...name,...age});
- 再es6中可以再对象内 直接操作__proto __ Object.setPrototypeOf
// __proto__ 链
// 再es6中可以再对象内 直接操作__proto__
let obj1 = { name: "zfpx" };
let obj2 = { age: 9 };
// obj1.__proto__ = obj2;
Object.setPrototypeOf(obj1,obj2);
console.log(Object.getPrototypeOf(obj1));
let obj2 = {
age: 9,
name:'jw'
};
let obj = {
name:'hs',
getPName(){ // 可以通过super关键字获取到父属性
return super.name
},
__proto__:obj2
}
console.log(obj.getPName());
类的继承
类的继承 三种属性 公有属性(proto) 私有属性 静态方法(静态属性)
- 继承私有属性
function Parent(){
// 构造函数中的this 通过new调用的那么this指代的是实例
this.name = 'parent';
}
Parent.prototype.eat = function () {
console.log('eat');
}
function Child() {
this.age = 9;
// 重点 Parent.call(this)
Parent.call(this);
}
- 继承公有属性 Object.create
// X:Child.prototype = Parent.prototype; 这个是兄弟关系 不是父子关系
// 第一种方式).Child.prototype.__proto__ = Parent.prototype;
// Object.setPrototypeOf(Child.prototype,Parent.prototype);
// 第二种方式).Child.prototype = Object.create(Parent.prototype); 只继承公有
function create(parentPrototype,props){
function Fn() {}
Fn.prototype = parentPrototype;
let fn = new Fn();
for(let key in props){
Object.defineProperty(fn, key, {
...props[key],
enumerable:true
});
}
return fn;
}
Child.prototype = create(Parent.prototype,{constructor:{value:Child}});
let child = new Child();
console.log(child.constructor);
// let a = {}
// // a.name = 1;
// // ES5
// Object.defineProperty(a, 'name', {
// enumerable: true, // 表示这个属性是否可以被枚举出来
// configurable: true, // 表示这个属性是否可被删除
// //writable:true,
// get() { // value可以替换成set和get
// console.log('get');
// return 1;
// },
// set(val) {
// console.log('设置值')
// }
// });
// console.log(a.name);
// a.name = 200;
类的编译
class Parent{
constructor(){
this.name = 'parent';
return {a:1};
}
static b(){
return 2;
}
eat(){
console.log('eat');
}
}
class Child extends Parent{ // 要求继承父亲的私有和有公有
constructor(){
super(); // Parent.call(this);
this.age = 9; // 私有属性
}
static a(){ // 属于类上的方法
return 1;
}
smoking(){ // 原型上的方法
console.log('smoking')
}
}
let child = new Child();
console.log(child);
//1.类只能new
// Class constructor Child cannot be invoked without 'new'
//2.类可以继承公有私有和静态方法
//3.父类的构造函数中返回了一个引用类型会把这个引用类型作为子类的this
Promise
Promise是一种异步流程的控制手段
- 回调地狱,代码难以维护 第一个的输出是第二个的输入
- promise链式调用
- promise可以支持多个并发的请求,获取并发请求中的数据
- promise可以解决异步的问题,本身不能说promise是异步的
// promise(承诺)关键字 resolve 成功 reject 失败 pending 等待态
// 如果一旦promise成功了就不能失败,相反也是一样的
// 只有状态是等待的状态pending时 才可以转化状态
// 每一个promise的实例上都有一个then方法,then方法中有两个参数,一个参数叫成功的函数 ,一个是失败的函数
// promise中发生错误 就会执行失败态
// promise可以实现不在传递回调函数了
// 事件环
// Promise只有一个参数 叫excutor执行器,默认new时就会调用
// promise 实现链式调用返回的并不是this而是一个新的promise
let p = new Promise((resolve,reject)=>{
// 默认promise中的executor是同步执行的
resolve('买');
});
// then方法是异步调用的,事件环
p.then((value)=>{ // value成功的原因
console.log(1);
},(err)=>{ // err失败的原因
});
console.log(2);
let fs = require('fs'); // fileSystem
function read(url) {
return new Promise((resolve,reject)=>{
fs.readFile(url, 'utf8', function (err, data) {
if(err) reject(err);
resolve(data);
})
})
}
// 如果返回的是promise 那么会取这个promise的结果,如过成功会走外层的promise的下一个then的成功,将数据传递到成功里
// promise 实现链式调用返回的并不是this而是一个新的promise
// 链式调用
// read('1.txt').then((data)=>{
// return read(data);
// }).then(data=>{
// console.log(data);
// },err=>{
// console.log(err);
// });
// read('1.txt').then(data=>{
// return 100;
// }).then(data=>{
// throw new Error();
// }).then(data=>{
// console.log(data);
// },(err)=>{
// console.log(err);
// }).then(data=>{
// console.log(data,'123123');
// });
// 如果返回的是一个普通值就会走到写一个then中的成功回调
// 如果有错误产生会走失败的回调
read('1.txt').then(data=>{
}).then(data=>{
throw new Error();
}).catch(err=>{
console.log(err);
}).then(data=>{
throw new Error()
}).then(data=>{
},err=>{
console.log(err);
});
// fs.readFile('1.txt','utf8',function (err,data) {
// if(err)return console.log(err);
// fs.readFile(data, 'utf8', function (err, data) {
// if (err) return console.log(err);
// console.log(data);
// })
// })
- 处理并发请求
let p = new Promise((resolve,reject)=>{
resolve('成功');
});
//一个promise可以then多次
p.then(data=>{
console.log(data);
});
p.then(data=>{
console.log(data);
})
p.then(data => {
console.log(data);
});
let fs = require('fs'); // fileSystem
function read(url) {
return new Promise((resolve, reject) => {
fs.readFile(url, 'utf8', function (err, data) {
if (err) reject(err);
resolve(data);
})
})
}
// Promise.all方法调用后会返回一个新的promise
// 并发的
// race赛跑,处理多请求只取最快的
// Promise.race([read('1.txt'),read('2.txt')]).then((data)=>{
// console.log(data);
// },err=>{
// console.log(err);
// });
// Promise.resolve() 返回一个成功的promise
// Promise.reject() 返回一个失败的promise
Promise.reject('123').then(null,data=>{
console.log(data);
});
解决异步的方案
-
高阶函数 函数是一等公民,函数可以当作参数,函数可以返回函数 (偏函数,函数柯里化)callback
-
Promise
-
generator + co
-
async + await
-
高阶函数
// 1).函数可以返回函数 // 类型判断 function isType(type, content) { // [object String] let t = Object.prototype.toString.call(content).replace(/\[object\s|\]/g, ''); return t === type; } console.log(isType('String', 'abc')); console.log(isType('String', 'abc')); // 需要批量的产生一些方法 isString('abc') isNumber(123); function isType(type) { return function (content) { let t = Object.prototype.toString.call(content).replace(/\[object\s|\]/g, ''); return t === type; } } let arr = ['String', 'Number', 'Array', 'Object', 'Null']; let util = {} arr.forEach(item => { util['is' + item] = isType(item) }); console.log(util.isString('123')); // 2) 函数可以当作参数传递 典型的callback // loadash after // 吃饭一个函数 调用3次后 在执行另一个函数 function after(times, callback) { return function () { if (--times === 0) { callback(); } } } let eat = after(3, function () { console.log('吃完了'); }); eat(); eat(); // 作业:Promise 异步发展流程 // 当达到某个条件时 执行callback let fs = require('fs'); // let arr = []; // 相当于在外部声明了一个变量 // function out(d) { // arr.push(d); // if(arr.length == 2) console.log(arr); // } function after(times,callback) { let arr = []; return function (d) { arr.push(d); if(arr.length === times) callback(arr); } } let out = after(2, function (data) { console.log(data); }); fs.readFile('./2.promise.js/a.txt', 'utf8', function (err, data) { out(data); }) fs.readFile('./2.promise.js/b.txt', 'utf8', function (err, data) { out(data); }); // 希望当这个文件都被读取完后 拿到结果
实现promise
function resolvePromise(promise2, x, resolve, reject) {
// 判断x是不是promise
// 规范里规定了一段代码,这个代码可以实现我们的promise和别人的promise可以进行交互
if (promise2 === x) { // 不能自己等待自己完成
return reject(new TypeError('循环引用'));
}
// x不是null或者是对象或者函数
if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
let called; // 防止成功后调用失败
try { // 防止取then是出现异常 Object.defineProperty
let then = x.then; // 取x的then方法 {then:{}}
if (typeof then === 'function') { // 如果then是函数我就认为它是promise
// call 第一个参数是this ,后面的是成功的回调和失败的回调
then.call(x, y => { // 如果y是promise就继续递归解析promise
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, r => { // 只要失败了就失败了
if (called) return;
called = true;
reject(r);
});
} else { // then是一个普通对象,就直接成功即可1
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else { // x = 123
resolve(x); // x就是一个普通值
}
}
class Promise {
constructor(executor) {
// 默认状态是等待态
this.status = 'pending';
this.value = undefined;
this.reason = undefined;
// 存放成功的回调
this.onResolvedCallbacks = [];
// 存放失败的回调
this.onRejectedCallbacks = [];
let resolve = (data) => {
if (this.status === 'pending') {
this.value = data;
this.status = 'resolved';
this.onResolvedCallbacks.forEach(fn => fn());
}
}
let reject = (reason) => {
if (this.status === 'pending') {
this.reason = reason;
this.status = 'rejected';
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try { // 执行时可能会发生异常
executor(resolve, reject);
} catch (e) {
reject(e); // promise失败了
}
}
then(onFulFilled, onRejected) {
// 解决onFulFilled,onRejected没有传的问题
onFulFilled = typeof onFulFilled === 'function' ? onFulFilled : y => y;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err; };
let promise2;
if (this.status === 'resolved') {
promise2 = new Promise((resolve, reject) => {
// 成功的逻辑 失败的逻辑
setTimeout(() => {
try {
let x = onFulFilled(this.value);
// 看x是不是promise 如果是promise 取他的结果 作为promise2,成功的结果
// 如果要是返回一个普通值 作为promise2,成功的结果
// resolvePromise可以解析x和promise2之间的关系
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
if (this.status === 'rejected') {
promise2 = new Promise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0);
});
}
// 当前既没有完成 也没有失败
if (this.status === 'pending') {
// 存放成功的回调
promise2 = new Promise((resolve, reject) => {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulFilled(this.value);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e);
}
}, 0)
});
// 存放失败的回调
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
})
}
return promise2; // 调用then后返回一个新的promise
}
}
// promise的语法糖,测试
Promise.deferred = Promise.defer = function () {
let dfd = {};
dfd.promise = new Promise((resolve,reject)=>{
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// npm install promises-aplus-tests -g
// promises-aplus-test 文件名
module.exports = Promise;
// 写完promise会测试一下