# ECMA script 6


其实是 ES6➕之后的版本统称 ES6


# 1.var , let 和 const

var 声明变量会在全局 window 下,let ,const 只能在块级作用域有效(if,for,while)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// var可以重复声明,let ,const 不行

// var存在变量提升
console.log(name); //undefined 不会报错
var name = 'xs'

// let 不影响作用域链的值查找
{
let name = 'xs';
f=()=>{
console.log(name); //xs 在f函数块级没找到,于是往上一级找到name
}
fn();
}

//注意! for循环内如果是 let 声明的循环变量,则会生成n个块级作用域
for(let i = 0, i < 5,i ++) //0,1,2,3,4
//如果是 var 声明的循环变量 ,则会在最后一次循环后覆盖前面值
for(var i = 0, i < 5,i ++) //5,5,5,5,5

const 声明变量不能修改,必须赋初始值

# 2. 解构赋值

​ 1. 数组解构

1
2
3
const F4 = ['one','two','three','four'];
let [a,b,c,d] = F4;
console.log(b); // two
  1. ​ 对象解构

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    const person = {
    name: 'xs',
    age: 18,
    run: function(){
    console.log("running..");
    }
    }
    //解构
    const {name,age,run} = person;
    run();

# 3. 模板字符串

使用 `` 反引号

1
2
3
4
5
6
//1. 直接可以使用换行符
let str = `第一行
第二行`
//2. 使用 ${} 字符串内使用变量
const name = 'lhp'
let str = `${name}是我的名字`

# 4. 箭头函数

关于箭头函数的 this 箭头函数的 this 无法改变(call,apply…),始终指向函数声明是的作用域下的 this

constructor 箭头函数 不能作为构造函数去创建实例化对象!

arguments 箭头函数不能用 arguments 获取参数

1
2
3
4
5
6
//声明普通函数
let sum=(a,b)=>{
return a+b;
}
//关于箭头函数的this 箭头函数的this无法改变(call,apply...),始终指向函数声明是的作用域下的this ****
//补充: 定时器函数内的this指向winodw 可以在定时器前使用 const _this = this 来保存this并使用

# 原型和原型链

Object; Function; Array; Map; Set;JS 中顶级对象是 Object,Object.prototype: 最顶层的原型对象

image-20221112175839161
# 1. 构造函数:

1. 构造函数首字母必须大写。
2. 内部使用 this 对象,来指向要生成的对象实例。
3. 使用 new 来调用构造函数,返回对象实例。

1
2
3
4
5
function Person(){    //构造函数
this.name = 'keith';
}
var boy = new Person();
console.log(boy.name); //'keith'
# 2. 构造函数的缺点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person(name,height){
this.name=name;
this.height=height;
this.hobby=function(){
return 'watching movies';
}
}
// 这里的boy 和 girl 出自同一个构造函数Person 但是hobby却不全等
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //false

//**每当使用new来调用构造函数放回一个对象实例的时候,都会创建一个hobby方法。这既没有必要,又浪费资源**
# 3.prototype 属性

js 中每个数据类型都是对象(除了 null 和 undefined),而每个对象都继承自另外一个对象,后者称为 “原型”(prototype)对象,只有 null 除外,它没有自己的原型对象。

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name,height){
this.name=name;
this.height=height;
}
Person.prototype.hobby=function(){ //把hobby方法放在原型对象上,对象实例可以继承
return 'watching movies';
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //true

也就是说,当某个对象实例没有该属性和方法时,就会到原型对象上去查找。如果实例对象自身有某个属性或方法,就不会去原型对象上查找。

重点:

  1. 原型对象的作用,就是定义所有对象实例所共享的属性和方法。

  2. prototype,对于构造函数来说,它是一个属性;对于对象实例来说,它是一个 (proto) 原型对象。

# 4. 原型链(prototype chains)

由于原型对象本身对于对象实例来说也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)。
比如,a对象是b对象的原型,b对象是c对象的原型,以此类推_proto_。

​ 定义一个数组 arr,数组里面有三个元素。我们并没有给数组添加任何属性和方法,可是却在调用 **length,join (),valueOf ()** 时,却不会报错。

length 属性是继承自 Array.prototype 的,属于原型对象上的一个属性。join 方法也是继承自 Array.prototype 的,属于原型对象上的一个方法。这两个方法是所有数组所共享的。当实例对象上没有这个 length 属性时,就会去原型对象查找。

valueOf 方法是继承自 Object.prototype 的。首先,arr 数组是没有 valueOf 方法的,所以就到原型对象 Array.prototype 查找。然后,发现 Array.prototype 对象上没有 valueOf 方法。最后,再到它的原型对象 Object.prototype 查找。

# 5.constructor

原型 (prototype) 对象有一个 constructor 属性,默认指向该对象所在的构造函数。

1
2
3
4
5
function A(){};
var a=new A();
console.log(a.constructor); //A()
console.log(a.constructor===A.prototype.constructor);//true
//a是构造函数A的实例对象,但是a自身没有contructor属性,该属性其实是读取原型链上面的
1
2
3
4
5
function A(){};
var a=new A();
console.log(a.constructor===A) //true
console.log(a.constructor===Array) //false
//判断实例对象a的构造函数是A而不是Array
# 6.instanceof
  1. instanceof 运算符返回一个布尔值,表示指定对象是否为某个构造函数的实例。
  2. 因为 instanceof 对整个原型链上的对象都有效,所以同一个实例对象,可能会对多个构造函数都返回 true。
  3. instanceof 对象只能用于复杂数据类型(数组,对象等),不能用于简单数据类型(布尔值,数字,字符串等)。
# 7.typeof

​ 判断类型方法,当碰到 ArrayFunction 等类型时均返回一个 Object
所以可以用 Object.prototype.toString.call(obj) 方法来识别对象类型。
返回一个 "[object Type]"

# 5.rest 参数 ——…

1
2
3
4
5
6
const fn = (...args) => {
console.log(args) // ['one','two','three'] 输出一个数组
}
fn('one','two','three');
//-----------------
fn(...arr) //表示把arr数组中的每一项作为参数传入fn

** 注意:利用 …arr 来复制数组是浅拷贝,无法复制原数组内的方法… **

# 6.Symbol

​ symbol 是唯一的标识,可是使属性唯一

1
2
3
4
5
6
7
8
9
10
11
let s =Symbol();
let s2 = Symbol.for('xxx')
//-----
let a1 = Symbol.for('a');
let a2 = Symbol.for('a');
a1 === a2 // true
typeof a1 // "symbol"
typeof a2 // "symbol"

let a3= Symbol("a");
a1 === a3 // false

USONB undefined String Object Number Null Boolean

# 7. 迭代器

​ Symbol.iterator 有属性 next ()

next () 方法返回的迭代器对象 IteratorResult 包含两个属性:done 和 value。done 是一个布 尔值,表示是否还可以再次调用 next () 取得下一个值;value 包含可迭代对象的下一个值(done 为 false),或者 undefined(done 为 true)。done: true 状态称为 “耗尽”

​ for…in… 取下标

​ for…of… 取 值

# 手写迭代器遍历一个对象:

需求遍历对象 pencilCase 中的所有 pens

1
2
3
4
5
6
7
8
9
const pencilCase={
name: "小天才",
pens: ['钢笔','圆珠笔','铅笔','橡皮擦']
}

for(let i of pencilCase){
console.log(i)
}
// "Uncaught TypeError: pencilCase is not iterable"
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
//正确做法,利用迭代器的next()机制
const pencilCase={
name: "小天才",
pens: ['钢笔','圆珠笔','铅笔','橡皮擦'],

//注意迭代器写法
[Symbol.iterator](){ //中括号等于重写了这个属性
let index = 0;
return {
next: ()=>{
//注意 由于是箭头函数 这里的this指向pencilCase
if(index<this.pens.length){
const result={value: this.pens[index],done: false};
index++;
return result
}else{
return {value: undefined,done: true}
}
}
}
}
}

for(let i of pencilCase){
console.log(i)
}

# 8. 生成器 *

​ 生成器不能用箭头函数创建

生成异步函数队列,每一次调用 next () 执行一个代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function *gen(){
console.log('参数')
console.log('111')
yield '这是第一个断点'
console.log('222')
yield '这是第二个断点'
console.log('333')
yield '这是第三个断点'
console.log('444')
}

const iterator = gen('参数') //可以传参
console.log(iterator.next()) //参数 111 {value:'这是第一个断点',done: false}
console.log(iterator.next()) // 222 {value:'这是第二个断点',done: false}
console.log(iterator.next()) // 333 {value:'这是第三个断点',done: false}
console.log(iterator.next()) // 444 {value:undefined, done: true}
console.log(iterator.next()) // value:undefined, done: true}

每次 iterator.next (‘参数’) 传入的参数

将作为上一次断点的返回结果

1
2
3
4
5
6
7
8
9
function *gen(){
let one = yield 'point1';
console.log(one);
yield 'point2';
yield 'point3';
}
const iterator = gen();
iterator.next() //第一个next用于启动生成器
console.log(iterator.next('将作为第一个断点返回值的参数')) //将作为第一个断点返回值的参数 {value: 'point2', done: false}

生成器可以解决 回调地狱 问题

回调: 1s 后输出 111, 1.5s 后输出 222, 2s 后输出 333

1
2
3
4
5
6
7
8
9
setTimeout(()=>{
console.log(111)
setTimeout(()=>{
console.log(222)
setTimeout(()=>{
console.log(333)
},2000)
},1500)
},1000)

使用生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const fn1 =()=> setTimeout(()=>{
console.log('111');
iterator.next()
},1000)
const fn2 =()=> setTimeout(()=>{
console.log('222');
iterator.next()
},1500)
const fn3 =()=> setTimeout(()=>{
console.log('333');
iterator.next()
},2000)

function *FnList(){
yield fn1()
yield fn2()
yield fn3()
}

const iterator = FnList()
iterator.next() // 111 222 333

# 9.Promise

异步编程的一种方案,解决了回调地狱的问题,是一种链式调动的方式

原生 promise, 状态的改变是通过 resolve () 和 reject () 函数来实现的,它的原型上定义了一个 then 方法,使用这个 then 方法可以为两个状态的改变注册回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const myPromise = new Promise((resolve,reject)=>{
console.log('promise本身直接运行')
//模拟一个异步
setTimeout(()=>{
let data = '用户数据'
resolve(data)
},1000)

})

myPromise.then(()=>{
console.log('成功')
},()=>{
console.log('获取数据失败')
})

catch 方法,实际上是 then 方法的语法糖,catch 会停止之后的所有 then。

# 10.Set&Map

# 1.Set

set 集合内的值是不重复

add (value) 添加; delete (value) 删除; has (value) 查看集合内有无该值,返回一个布尔值 clear (); 清除集合

注意配合 扩展运算符 (…)使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
let arr = Array.from(mySet)  //把集合转为数组 
//可以用 for ... of 遍历Set
let set = new Set(['red', 'green', 'blue']);

for (let item of set.keys()) { //遍历键
console.log(item);
}
// red
// green
// blue

for (let item of set.values()) { //遍历值
console.log(item);
}
// red
// green
// blue

for (let item of set.entries()) { //遍历键值对
console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

利用 filter 实现各种过滤

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}

// 差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}

# 2.Map

​ Map 和 Object 区别 : Map 的键值对中,任何值都可以作为键

同 Set ,Map 也能用 **for…of ** 遍历,并且也可以 Map.keys () 遍历键 Map.values () 遍历值…

# 11.Clas 类

# 1. 静态成员 (原生函数对象内无法加静态方法)

1
2
3
4
5
6
7
8
9
10
11
12
class Person{
constructor(name,age){
this.name = name;
this.age= age;
}
static say(name){
console.log(`我叫${name}`);
}
}
let ming = new Person('ming',20);
console.log(ming) //Person { name: 'ming', age: 20 }
Person.say('ming'); //静态方法 只能类自身用

# 2. 继承(原生继承是给 fn.prototype 加属性或方法 )

为什么构造函数的方法不直接写进构造函数,而是写入其原型对象?

​ 因为写进构造函数,每次创建一个实例对象都会创建那个方法,白白占用内存,写入其原型对象中,实例对象就可以直接调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
walk() {
console.log("I am walking");
}
}

class Stu extends Person { // extends继承
constructor(name, age, grade, major) {
super(name, age); // super...哈
this.grade = grade;
this.major = major;
}
}

const xiaoming = new Stu("小明", 20, 3, "软件工程");
console.log(xiaoming); //Stu { name: '小明', age: 20, grade: 3, major: '软件工程' }
xiaoming.walk(); // I am walking

# 3. 多态,子类对父类方法重写

# 4.set 和 get(类似 java)

# 12. 类型转换

convert-table

# 1. 减、乘、除

我们在对各种非 Number 类型运用数学运算符 ( - * / ) 时,会先将非 Number 类型转换为 Number 类型。

1
2
3
1 == true
0 == null
1 * undefined == NaN

# 2 加法

  • 当一侧为 String 类型,被识别为字符串拼接,并会优先将另一侧转换为字符串类型。
  • 当一侧为 Number 类型,另一侧为原始类型,则将原始类型转换为 Number 类型。
  • 当一侧为 Number 类型,另一侧为引用类型,将引用类型和 Number 类型转换成字符串后拼接。

# 3. 逻辑运算

当我们使用 if while for 语句时,我们期望表达式是一个 Boolean ,所以一定伴随着隐式类型转换。而这里面又分为两种情况:

# 1. 单个变量(if (num)、while ( index )…)

# 2. 使用 == 比较

  • 规则 1: NaN 和其他任何类型比较永远返回 false (包括和他自己)。

  • 规则 2:Boolean 和其他任何类型比较,Boolean 首先被转换为 Number 类型(0 / 1)。

  • 规则 3: StringNumber 比较,先将 String 转换为 Number 类型。

  • 规则 4: null == undefined 比较结果是 true ,除此之外, nullundefined 和其他任何结果的比较值都为 false

  • null == undefined // true
    null == '' // false
    null == 0 // false
    null == false // false
    undefined == '' // false
    undefined == 0 // false
    undefined == false // false
    <!--code24-->

# 14.asycn 、 await

ES8 新特性

asycn 函数,返回一个 Promise 类型的对象

1
2
3
4
5
6
7
8
9
10
11
12
async function fn(){
return new Promise((resolve, reject) =>{
//resolve('数据成功')
reject('出错了')
})
}
const f = fn()
f.then(value =>{
console.log(value);
},reason =>{
console.warn(reason);
}) //状态:失败 , 内容:出错了

await 必须写在 async 函数中

1
let result = await $.send('xxx')

await 获取 async 异步的结果