es6阮一峰
基本数据类型
- 数字、字符串、布尔、symbol、bigInt、undefined、null
- object
Set用法
类似于数组,但是成员的值都是唯一的,没有重复的值。
只有NaN和 === 不一样 其他都是一样做比较的
var set = new Set(NaN)
set.add(NaN);
set
set.size
set.delete()
set.has()
set.clear()
[...new Set('ababbc')]
也可以使用Array.from解开Set实例
let set = new Set(['red', 'green', 'blue']);
for (let item of set.keys()) { console.log(item);}
for (let item of set.values()) { console.log(item);}
for (let item of set.entries()) { console.log(item);}
Set.prototype[Symbol.iterator] === Set.prototype.values
for (let i of set) {
console.log(i);
}
set.forEach((value, key) => console.log(key + ' : ' + value))
可以把Set实例看做数组 进行map和filter操作 和数组用法类似
const p = [item,item,...]
const set = new WeakSet(b);
set.add(value)
set.delete(value)
set.has(value)
set.size
set.forEach
Map用法
DOM 节点作为对象data的键,但是由于对象只接受字符串作为键名,所以element被自动转为字符串[object HTMLDivElement]。
const data = {};
const element = document.getElementById('myDiv');
data[element] = 'metadata';
data['[object HTMLDivElement]']
为了解决这个问题,ES6 提供了 Map 数据结构。它类似于对象
var obj = {}
var map = new Map([
[obj, '111'],
['key2', '222']
]);
map.get(obj)
for...map.keys() => 第一项是obj 也可以使用 [...map.keys()]
for...map.values() => 第一项是"111" 也可以使用 [...map.values()]
for...map.entries() => 第一项是[obj,'111'] 也可以使用 [...map.entries()]
for...map.forEach(value, key) => 第一项 value为'111' key为obj
WeakMap只接受对象作为键名 WeakMap 里面对element的引用就是弱引用,不会被计入垃圾回收机制。
只有这些方法 has get set delete
const wm1 = new WeakMap();
Promise
function requestTableList(){
var p = new Promise((resolve, reject) => {
resolve(res);
});
return p;
}
function timeout(){
var p = new Promise((resolve, reject) => {
setTimeout(() => {
reject('请求超时');
}, 10000);
});
return p;
}
Promise.race([requestTableList(), timeout()]).then((data) =>{
console.log(data);
}).catch((err) => {
console.log(err);
});
function promiseClick1(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promiseClick2(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
function promiseClick3(){
let p = new Promise(function(resolve, reject){
setTimeout(function(){
var num = Math.ceil(Math.random()*20);
console.log('随机数生成的值:',num)
if(num<=10){
resolve(num);
}
else{
reject('数字太于10了即将执行失败回调');
}
}, 2000);
})
return p
}
Promise.all([promiseClick3(), promiseClick2(), promiseClick1()]).then(function(results){
console.log(results);
})
class继承
父辈为超类 子辈为子类 子类继承超类 调用super其实是调用超类的构造函数方法
class A {
constructor(a) {
this.a = a;
}
}
class B extends A {
constructor(a, b) {
super(a);
this.b = b;
}
}
class C extends B {
constructor(a, b, c) {
super(a, b);
this.c = c;
}
}
console.log(new C(1, 2, 3))
Promise并行和串行,以及await底层实现
前提代码
var query = function (value) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
resolve(value)
}, value)
})
}
并行 方式一 1秒后输出1000,再过1秒输出2000,再过1秒输出3000
query(1000).then(v => {
console.log(v)
})
query(2000).then(v => {
console.log(v)
})
query(3000).then(v => {
console.log(v)
})
并行 方式二 三秒后输出 [1000, 2000, 3000]
Promise.all([query(1000),query(2000),query(3000)]).then(v=>{
console.log(v)
})
串行 方式一 输出为 1秒后输出1000,再过2秒输出2000,再过3秒输出3000
query(1000).then(v => {
console.log(v)
return query(2000)
}).then(v => {
console.log(v)
return query(3000)
}).then(v => {
console.log(v)
})
串行 方式二 输出为 1秒后输出1000,再过2秒输出2000,再过3秒输出3000
let itor = generator()
itor.next().value.then(value => {
itor.next(value).value.then(value => {
itor.next(value).value.then(value => {
itor.next(value)
})
})
})
await底层实现
const isPromise = function (v) {
if (v !== null && /^(object|function)$/i.test(typeof v)) {
let then;
try {
then = x.then
} catch (err) {
return false
}
if (typeof then === 'function') return true
}
return false
}
function AsyncFunction(generator, ...params) {
return new Promise((resolve, reject) => {
let itor = generator(...params);
const next = v => {
let {
value,
done
} = itor.next(v)
if (done) {
resolve(value)
return
}
if (!isPromise(value)) value = Promise.resolve(value)
value.then(v => {
next(v)
}).catch(reason => {
reject(reason)
itor.throw(reason)
})
}
next()
})
}
AsyncFunction(function* generator() {
let value;
y1 = yield query(1000)
console.log(y1)
y2 = yield query(2000)
console.log(y2)
y3 = yield query(3000)
console.log(y3)
return 'zanlan'
}).then(v => {
console.log('所有请求都成功', v)
}).catch(reason => {
console.log('某个请求失败', reason)
})
一般函数实现
(async function () {
let value;
try {
value = await Promise.reject('xxx')
console.log('第一个请求成功', value)
} catch (err) {
console.log(err)
}
value = await query(2000)
console.log('第二个请求成功', value)
value = await query(3000)
console.log('第三个请求成功', value)
})()
generator原理
把一个函数当做普通函数执行,是否可以创造它这个类的一个实例?
jquery.fn()
function* fn() {
console.log(this)
return 10
}
let itor = fn()
console.log(itor)
输出 window,在输出 { value:10 , done:true }
function* fn() {
console.log(this)
return 10
}
let itor = fn()
console.log(itor.next())
输出 如下
function* generator() {
console.log(1)
yield 2
console.log(3)
yield 4
console.log(5)
yield 6
console.log(7)
return 8
}
let itor = generator()
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
输出 如下
function* generator() {
console.log(1)
let y2 = yield 2
console.log(y2)
console.log(3)
let y4 = yield 4
console.log(y4)
console.log(5)
let y6 = yield 6
console.log(y6)
console.log(7)
return 8
}
let itor = generator()
console.log(itor.next('aa'))
console.log(itor.next('bb'))
console.log(itor.next('cc'))
console.log(itor.next('dd'))
输出如下
function* generator1() {
yield 2;
yield 3;
return 4
}
function* generator2() {
yield 1;
yield* generator1();
yield 5;
return 6;
}
let itor = generator2();
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
Iterator 源码
class Iterator {
constructor(assemble) {
let self = this;
self.assemble = assemble;
self.index = 0;
}
next() {
let self = this;
let assemble = self.assemble;
if (self.index > assemble.length - 1) {
return {
done: true,
value: undefined
}
}
return {
done: false,
value: assemble[self.index++]
}
}
}
一般应用
let itor = new Iterator([10, 20, 30, 40])
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
console.log(itor.next())
下面代码可以使得一般对象使用for of 循环
Object.prototype[Symbol.iterator] = function () {
let self = this
let keys = Object.keys(self).concat(Object.getOwnPropertySymbols(self))
let index = 0
return {
next() {
if (keys.length - 1 < index) {
return {
done: true,
value: undefined
}
}
return {
value: self[keys[index++]],
done: false
}
}
}
}
针对类数组,则直接借用真数组自带的Symbol.iterator函数
var obj = {
0: 'a',
1: 'b',
length: 2
}
obj[Symbol.iterator] = Array.prototype[Symbol.iterator]
for (var value of obj) {
console.log(value)
}
jquery是类数组,下面是jquery源码实现
jQuery.fn[Symbol.iterator] = [][Symbol.iterator];
async && await 面试题
已知两个函数,分别提问,得出结果
var f1 = function f1() {
console.log(1)
return new Promise(resolve => {
setTimeout(() => {
resolve(6)
console.log(5)
}, 2000);
})
}
var f2 = function f2() {
console.log(2)
return new Promise(resolve => {
setTimeout(() => {
resolve(4)
console.log(3)
}, 1000);
})
}
问题1 输出结果为 :1 5 6 2 3 4
var f = async function () {
console.log(await f1())
console.log(await f2())
}
f()
问题2 输出结果为 :1 2 3 5
Promise.all([
f1(),
f2(),
])
问题3 输出结果为 :1 2 3 4 5 6
Promise.all([
(async () => { console.log(await f1()) })(),
(async () => { console.log(await f2()) })(),
])
class继承
父辈为超类 子辈为子类 子类继承超类 调用super其实是调用超类的构造函数方法
class A {
constructor(a) {
this.a = a;
}
}
class B extends A {
constructor(a, b) {
super(a);
this.b = b;
}
}
class C extends B {
constructor(a, b, c) {
super(a, b);
this.c = c;
}
}
console.log(new C(1, 2, 3))
ES5和ES6的模块化导入导出
require:require('s.css');
improt 's.css'
var o = require('s.js');
import o form s.js
导出一个模块对象(es5):
module.exports={
add:add,
sub:sub
}
导出一个模块对象(es6):
module.exports={
add,
sub
}
注意:这种写法属性名和属性值变量是同一个,否则要分开写
module.exprots={
addFn:add,
sub
}
module.exports={
addFun:function(x,y){
return x+y;
}
}
module.exports={
addFun(x,y){
return x+y;
}
}
calc.js中有两个函数:
function add(){}
function sub(){}
es5写法:
module.exports.add = add;
module.exports.sub = sub;
使用:
var calc = require('./calc.js');
es6写法:
exprot function add(){}
exprot function sub(){}
es5:
module.exports = {add:add,sub:sub};
es6:
exprot default{
add,sub
}
import calc from './calc.js'
import {add} from './calc.js'
1、如果模块中是使用 export default {} 方式导出的对象
只能通过 import 对象名称 from '模块路径'
不能通过 import {对象名称} from '模块路径'
2、如果就想要import {对象名称} from '模块路径'通过这种方式来按需导入对象中的某个属性
那么应该使用 export 跟着要导出的对象或者方法名称
export function add(){}
export function substrct(){}
那么就可以使用:
import {add,substrct} from '模块路径'
只需要直接使用 add()方法即可
注意这里不能直接使用: import cacl from '模块路径' 这种方式导入,会报错
class继承
父辈为超类 子辈为子类 子类继承超类 调用super其实是调用超类的构造函数方法
class A {
constructor(a) {
this.a = a;
}
}
class B extends A {
constructor(a, b) {
super(a);
this.b = b;
}
}
class C extends B {
constructor(a, b, c) {
super(a, b);
this.c = c;
}
}
console.log(new C(1, 2, 3))
ES5 和 ES6 及Object用到过的方法
es6的prototype不可以枚举
class Person {
constructor(x, y) {}
toString() {}
}
console.log(Object.keys(Person.prototype));
console.log(Object.getOwnPropertyNames(Person.prototype));
function Person1() {}
Person1.prototype.toString = function () {};
console.log(Object.keys(Person1.prototype));
console.log(Object.getOwnPropertyNames(Person1.prototype));
自动添加constructor函数
class Person {
}
等 价
class Person {
constructor(x, y) {}
}
constructor默认return 实例化对象this,但可以自定义 class函数必须要new才能调用,es5不需要new也可以调用
class Foo{
constructor(){
return Object.create(null);
}
}
new Foo() instanceof Foo
修改一个实例__proto__的方法,其他的实例也会牵连
class Person {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return this.x + '--' + this.y;
}
}
let p = new Person(1, 2);
console.log(p.hasOwnProperty('x'));
console.log(p.hasOwnProperty('y'));
console.log(p.hasOwnProperty('constructor'));
console.log(p.hasOwnProperty('toString'));
console.log(p.__proto__.hasOwnProperty('constructor'));
console.log(p.__proto__.hasOwnProperty('toString'));
let p1 = new Person(2, 3);
p1.__proto__.toString = function () {
return 'what fuck?';
};
let p2 = new Person(3, 4);
console.log(p1.toString());
console.log(p2.toString());
class可以自定义变量,Person只对构造函数内部有效,而clafun则用于外部调用
let clafun = class Person {
constructor(x, y) {
this.x = x;
}
toString() {
return this.x + '--' + Person.name;
}
};
let p = new clafun(1);
console.log(p.toString());
let p = new class Person {
constructor(x, y) {
this.x = x;
}
toString() {
return this.x + '--' + Person.name;
}
}(1);
console.log(p.toString());
class不存在变量提升,let不会变量提升,假设class存在变量提升,则为报错Foo 是undefined ,而实际上没有报错,说明class不会变量提升
{
let Foo=class {};
class Bar extends Foo{
}
}
this的指向问题,默认指向实例化对象,但是通过解构出来的方法,则函数内部的this是指向环境的因为es6默认是用严格模式的,所以是指向undefined,解决方法有三种
- bind改变this的指向
- 箭头函数
- proxy
console.log(this);
class Person {
constructor() {
}
fun1() {
console.log(this);
return this.fun2() + '--------';
}
fun2() {
return 'what';
}
}
let p = new Person();
console.log(p.fun1());
const { fun1 } = p;
console.log(fun1());
proxy添加this
function selfish(target) {
const cache = new WeakMap();
const handler = {
get(target, key) {
const value = Reflect.get(target, key);
if (typeof value !== 'function') {
return value;
}
if (!cache.has(value)) {
cache.set(value, value.bind(target));
}
return cache.get(value);
},
};
const proxy = new Proxy(target, handler);
return proxy;
}
const p = selfish(new Person());
class继承static方法 es6只有静态方法没有静态属性
class Foo {
static fun1() {
return '111';
}
}
class Bar extends Foo {
static fun2() {
return super.fun1() + '222';
}
}
console.log(Bar.fun1());
console.log(Bar.fun2());
class声明实例化属性和方法
class Foo {
constructor() {
this.state1 = {};
}
state = { name: 1 };
fun1() {
return 11111;
}
}
console.log(new Foo().hasOwnProperty('state1'));
console.log(new Foo().hasOwnProperty('state'));
console.log(new Foo().__proto__.hasOwnProperty('fun1'));
ES5和ES6的get和set方法的比较
ES5
var obj = {};
Object.defineProperty(obj, 'name', {
get: function () {
console.log('正在访问name');
return this._name;
},
set: function (val) {
console.log('正在修改name');
this._name = val;
},
});
obj.name = 10;
console.log(obj);
console.log(obj.name);
ES6
class Person{
constructor(){
this._name = '';
}
get name(){
console.log("正在访问name属性");
return `我的名字是${this._name}`;
}
set name(val){
console.log("正在修改name属性");
this._name = val;
}
}
const person = new Person();
person.name = "德玛-压缩";
console.log(person.name);
es7
let a = 7 ** 12
let b = 2 ** 7
console.log(a === Math.pow(7,12))
console.log(b === Math.pow(2,7))
|