ES6相关知识点

ES6是一个泛指,含义是5.1版本之后的js版本,涵盖了ES2015,ES2016,ES2017等。

0、es7 新增的两个特性

//** 幂指数
console.log(3**4,2**6,Math.pow(3,4));			//81 64 81
var arr = [1,2,3,4,5];
console.log(arr.includes(6));				//false




//.includes()   判断一个数组是否包含一个指定的值,另外弥补indexOf找不到NaN的bug
var arr = ['hello'/2,NaN];
console.log(arr.indexOf('hello'/2),arr.indexOf(NaN));				//-1 -1
console.log(arr.includes('hello'/2),arr.includes(NaN));				//true true

1、定义变量: var、let、 const

变量声明方式作用域重复声明声明变量时必须初始化(赋值)变量提升
var(es5)函数级作用域×
let (es6)块级作用域×××
const (es6)块级作用域××
 var特点:
  1.会变量提升,不存在暂时性死区
  2.可以重复声明变量
  3.不存在块级作用域 if() for()
let特点:
  1.不可以变量提升存在暂时性死区(在声明之前无法访问)
  2.可以在声明变量同时不进行赋值
  3.使用let不可以重复声明变量,但是可以重新赋值
  4.使用let声明变量存在块级作用域

//1.
// console.log(a);      //报错
// let a = 1;

// 2.
// let a;//var a;
// console.log(a);      //undefined

// 3.
// let a = 'hello';
// let a = 10;
// console.log(a)          //报错,重复声明
//
// let b = 'hello';
// b = 10;
// console.log(b)           //10

// 4.
// if (true) {
//     let a = 1;
// }
// console.log(a);                   //报错
// for (let i = 0; i < 5; i++) {
//     console.log(i)               //0 1 2 3 4
// }
// console.log(i, '外部打印')       //报错
const特点:
  1.使用const不可以重复声明变量
  2.不会变量提升存在暂时性死区
  3.必须在声明得时候进行初始化
  4.使用const声明 基本数据类型值 、 引用数据类型值 一旦声明不可以修改, 但声明 引用数据类型属性 是可以修改删除
  5.存在块级作用域
  6.一般用于声明常量

// 1.
// const a = 'hello';
// const a = 'world';          //报错,因为 1

// 2.
// console.log(a);
// const a = 10;               //报错,2

// 3.
// const a;                    //报错 ,3

// 4.
// const a = BigInt(2n);
// a ='world';
// console.log(a);                 //报错, 4的基本数据类型
//
// const obj = {
//     name: 'zhangsan',
//     age: 12
// }
// obj.name = 'lisi';
// delete obj.age;
// // obj = 'hello';               //加上它就报错,因为不能改值,只能改属性
// console.log(obj)                //{ name: 'lisi' } ,4的引用数据类型

//5.
// if(true){
//   const a = '10'
// }
// console.log(a)         //报错

2、包管理机制(npm ,cnpm ,yarn)

  • npm :node软件自带npm包管理工具 ,安装依赖速度慢(服务器部署在国外,受网络波动较大)
  • cnpm:中国版的npm,淘宝团队优化npm速度 旧的仓库源:taobao.org 新的仓库源npmmirror.com 16以上
  • yarn:下载依赖会先从离线缓存中寻找 ,找不到则下载

3、降版本代码 babel********

babel:将高版本代码(es6及以上)转为低版本代码(es5)

  1. 将文件夹初始化为项目:
    • npm init
    • npm init -y (快速初始化(自动一路yes))
  2. 安装转码工具
    • cnpm install -g babel-cli (全局安装转码工具)
    • babel --version (检测Babel版本,及是否安装)
    • cnpm install --save -dev babel-cli babel-preset-latest (安装预设局部安装)
  3. 安装转换规则
    • cnpm install -g babel-preset-latest
  4. 指定转换规则
    • 新建.babelrc文件,输入 { “presets”:[“latest”] }
    • cnpm install --save-dev babel-cli babel-preset-latest
    • babel xxx.js(对文件进行转码)
  5. 文件高转低后输入到另一个文件(文件会自动新建)
    • babel xxx.js --out-file xxx.js
  6. 整个目录高转低后的输入到另一个目录(目录会自动新建)
    • babel xxx --out-dir xxx

node xxx (指运行该文件)

es6:
let a =1;
let foo=()=>{
    console.log('我是箭头函数');
}


转为ES5后:
'use strict';//严格模式 语法进行限制(转es5后自带)
var a = 1;
var foo = function foo() {
  console.log('我是箭头函数');
};
// b=1;//严格模式下,必须var声明变量,否则不符合严格模式,报错
// console.log(b);

4、模块化机制********

package.json 文件中 默认nodejs采用模块化规范为commonjs
可以设置模块化规范为es6模块化规范 “type”:“module/commonjs(默认)” 导入变量的文件后缀名要加上

4.1 ES6模块化

  • 导出
    1.列表导出:export {first,last}
    2.重命名导出:export {first as fi,last as la};
    3.导出单属性:export var a=3; / export function get(){}
    4.默认导出: export default { first, function get() {} }

  • 导入
    1.列表导入 import {first,last} from ‘xx.js’
    2.重命名导入 import {first as f,last as l};
    3.单个属性导入 import {a,get} from ‘xxx.js’
    4.默认导入需要重命名
    import person from ‘xxx.js’ (person ---->默认导出内容)
    5.引入模块中所有内容 import * as all from ‘xxx.js’ (all为随便名字)

导出
let firstName = 'zhao';
let lastName='larry';
//1.列表导出'
// export{firstName,lastName};

//2.重命名导出
// export{firstName as first,lastName as last};

//3.导出单个属性
// export let a=1;
// export  function foo(){
//     console.log('我是foo函数');
// }

//4.默认导出   一个模块只能有一个默认导出,不能使用 var、let 或 const
// export default{
//     obj:{
//         name:"zhangsan",
//         age:12
//     },
//     b:'我是字符串b'
// }



导入
//1'列表导入 es6编译时加载
// import {firstName,lastName } from "./1-ES6模块导出";
// console.log(firstName,lastName);

// 2. 列表导入的时候导入新的变量名
// import {first,last} from"./1-ES6模块化导出";
// console.log(first,last);

//2.重命名导入 first last
// import {first as f,last as l}from "./1-ES6模块导出.js";
// console.log(f,l,'重命名导入');

//3.导入单个属性
// import {a,foo} from './1-ES6模块导出.js'
// console.log(a,foo());            //我是foo函数  1 undefined      函数会提升,所以先输入函数

//4.默认导入
// import person from './1-ES6模块导出.js'
// console.log(person);                //{ obj: { name: 'zhangsan', age: 12 }, b: '我是字符串b' }

//5.引入文件中所有导出的内容
import * as obj from './1-ES6模块导出.js'
console.log(obj);

4.2 commonjs模块化

即es6之前的模块化

  • 导出
    module.exports.first = ‘zhao’;
    module.exports = { first,last,…}

  • 导入
    let xxx = require( ‘xx.js’ );

导出
// console.log(module,'当前模块','node内部提供了Moudle构造函数');
// var module=new Module();//module代表当前模块

let first='ren';
let last='terry';
//向外输出对象
// module.exports.first=first;
// module.exports.last=last;
module.exports={
    first,
    last
}

导入
//commonjs模块化导入
// let{first,last}=require('./3-commonjs模块化导出');
// console.log(first,last);

let _ =require('./3-commonjs模块化导出');
console.log(_);

4.3 ES6与CommonJS模块的差异

  1. ES6在编译时加载模块,Commonjs在运行时加载模块
  2. ES6导出使用export ;导入使用import导入
    Commonjs导出使用当前模块 module.exports ;导入使用require()
  3. ES6模块化输出的是值得引用,Commonjs输出的是值的复制
ES6模块化
//导出
let first='zhao';
let last='larry';
export{first,last};
setTimeout(function(){
    first='ren';
},2000);
//导入
import {first,last} from "./5-ES6模块化导出差异";
console.log(first,last,'导入变量');     //zhao larry 导入变量
setTimeout(function(){
    console.log(first,last);
},4000);                                //ren larry




CommonJS模块化
//导出
let first='ren';
let last='terry';
module.exports={
    first,last
}
setTimeout(function(){
    first='zhao';
},2000)
//导入
let _=require('./7-commonjs模块化导出差异');
console.log(_.first,_.last);        //ren terry
setTimeout(function(){
    console.log(_.first,_.last);
},4000)                             //ren terry

5、解构********

  • 概念:从数组或者对象中提取值,给变量进行赋值操作就是解构 。
  • 本质属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。如果解构不成功,变量的值就等于undefined。

5.1 数组解构

1.完全解构
  // let  [a,b,c,d,e] =  [1,2,3,4,5];
  // console.log(a,b,c,d,e);				//1 2 3 4 5
  //let [a,b,c,d,e] = [1,2,3,[4,5,6],7];
  // console.log(a,b,c,d,e);				//1 2 3 [4,5,6] 7
2.不完全解构
  // let [a,b,c,[d],e] =  [1,2,3,[4,5,6],7];
  // console.log(a,b,c,d,e);				//1 2 3 4 7
3.集合解构  拓展运算符 (将剩余未匹配的集合到一起)
  // let [a,...b] = [1,2,3,4,5];
  // console.log(a,b);						//1 [2,3,4,5]
4.默认值解构  当没有与变量匹配的值默认值就生效
  // let [a=4,b=5,c=6] = [1,2,3];
  // console.log(a,b,c);			//1 2 3
  // let [a=4,b=5,c=6] = [];
  // console.log(a,b,c);			//4 5 6
5.默认值也可以是函数
  // function foo(){ console.log('我是foo函数'); }
  // let [a=foo()] = [1,2,3];
  // console.log(a);				//1
  // let [a=foo()] = [];
  // console.log(a);				//我是foo函数
6.虽然两者内容相同,但引用地址不同
  // let arr = [1,2,3,4,5];
  // let [...a] = arr;
  // console.log(a===arr);			//false

5.1.1 拓展运算符*********

用于解构数组和对象,并返回解构后的新数组或者新对象

 1.用到左侧是聚合
// var arr = [1,2,3,4,5];
// let [...res] = arr;
// console.log(res);		    //[1,2,3,4,5]
// console.log(res===arr);	  	//false(引用地址不同,(深拷贝))

 2.用到右侧是展开
// let obj={name:'zhangsan',age:12};
// let obj1={...obj};
// console.log(obj1);			//{name:'zhangsan',age:12}
// console.log(obj1===obj);	    //false



var params = {page:1 , pageSize:10}
var form = {title:"" , type:"" , status:""}
let temp = {...params , ...form}
for(let key in temp){
  if(!temp[key]){
    delete temp[key]
  }
}
console.log(temp);      //{ page: 1, pageSize: 10 }

5.2 对象解构

左侧变量名必须和右侧属性名同名,右边对象中对应的属性名才会解构出来

 1.
// let {foo:foo,bar:bar} =  {foo:'hello',bar:'world'};
// let {foo,bar} =  {foo:'hello',bar:'world'};
// console.log(foo,bar); 			//hello world
 2.重命名解构   ‘ :’ 对变量名进行重命名
// let {foo:baz} = {foo:'hello',bar:'world'};
// console.log(baz)				//hello
 3.嵌套解构 ----使用ab变量接收hello world
// let obj={p:['hello',{y:"world"}]};
// let {p:[a,{y:b}]} = obj;
// console.log(a,b);			//hello world
 4.默认值  给对象变量设置默认值 
// let {x:y=2} = {x:1};
// console.log(y);			//1
// let {x:y=2}={};
// console.log(y); 			//2


经典面试题:
const [a, b, c, ...d] = [1, 2, 3, 11, 999];
const { e, f, f1, g, ...h } = { f: 4, g: 5, i: 6, j: 7 };
console.log(a, b, c, d, e, f1, g, h);		
//1 2 3 [11,999] undefined  undefined 5 {i:6 j:7}

5.3 字符串、数值、布尔解构

字符串解构
	1.使用数组解构可以获取指定字符;
	//let [a,b,c]='hello';
	//console.log(a,b,c);					//h e l
    2.使用集合解构可以转换为数组
    //let [...arr]='hello';
	//console.log(arr);			//['h','e','l','l','o']
	3.使用对象解构可以获取实例属性方法
    //let {toString,valueOf,length}='hello';			//相当于把‘hello’当成String基本包装器类型
   	//console.log(toString,valueOf,length)			//[Function: toString] [Function: valueOf] 5
   	
   	
数值解构  可以获取到数值包装器构造函数原型中指定的方法。
 	//let {toString,valueOf}=10;
    //console.log(toString,valueOf)				//[Function: toString] [Function: valueOf]
    
    
布尔值解构
	//let {toString,valueOf}=true;
 	//console.log(toString,valueOf);				//[Function: toString] [Function: valueOf]

5.4 函数参数解构

1.1 参数为对象的解构
// function foo({name,age,gender}){
//   console.log(name,age,gender)
// }
// foo({name:'zhangsan',age:12,gender:'male'});			//zhangsan 12 male

1.2 参数为对象默认值的解构
// function foo({name,age=18,...rest}){
//   console.log(name,age,rest);
// }
// foo({name:'lisi',age:12,gender:'male',weight:'40kg'})		//lisi 12 { gender: 'male', weight: '40kg' } 

2.参数为数组的解构
// function foo([a,b,c]){
//   console.log(a,b,c);
// }
// foo(['hello','terry','tom'])			//hello terry tom


3. 尾参数 
es6允许为函数的参数设置默认值 设置了默认值的参数自动成为函数尾参数
length属性将返回不包括 尾参数及其之后 的个数
function foo(a,d,e,f,b=1,c){
}
foo(1,2,3,4,5,6);
console.log(foo.length);//4

6、箭头函数********

6.1 对象简写

  • 属性简写:属性名和变量名(属性值)一致时可简写为属性名
  • 方法简写:省略 :function,即sayName () { }
let name = 'terry';
let age = 12;
let obj = {

//属性简写
   //name:name,
   //age:age,
     name,
     age,

//方法简写     
// es5 
  // sayName:function(){
  //   console.log(this.name);//此时this指向obj
  // }
// es6
   sayName(){
     console.log(this.name);//此时this指向obj
   }
}
obj.sayName()();

6.2 箭头函数

  • 主要目的:
    普通函数得关心this的指向,修改等
    而箭头函数不用担心,因为this仅指向外部作用域的this指向
普通函数箭头函数
var foo =     function () {}var foo =       () => {}
this指向全局对象,对象中方法指向调用者无this属性,this指向声明该箭头函数外部作用域的this
原型对象原型对象
使用arguments保存实参使用rest参数保存实参(本质上就是用拓展运算符来保存剩余参数到数组中)
//普通函数this指向,保存实参
function test(){
  console.log(this,arguments);
}
test(1,2,3);// 全局对象   [Arguments] { '0': 1, '1': 2, '2': 3 }

//箭头函数this指向,保存实参
// 箭头函数内部没有this属性 不再用arguments属性保存实际参数 用rest参数保存实际参数
let foo = (...res)=>{
  // console.log(this,arguments,'arguments')    //argument打印出来是类数组对象 [arguments]{...},指向模块中的一些其他信息
  console.log(res);     //[1,2,3]
}
foo(1,2,3)



// 普通函数有原型对象  
// 箭头函数没有原型对象
function bar(){}
console.log(bar.prototype,foo.prototype);               //{} undefined
console.log(bar.prototype.toString(),foo.prototype);    //[object Object] undefined



箭头函数和普通函数区别?
  1.普通函数内部this指向全局对象,方法指向调用者
  2.箭头函数没有thisthis访问声明箭头函数外部作用域中的this
  3.普通函数使用arguments保存实际参数,箭头函数使用rest参数保存实际参数
  4.普通函数有原型对象,箭头函数没有原型对象
  5.外观上 ()=>{}

箭头函数的this指向:

let name = 'terry';
let age = 12;
//(4)let sayName = () => { console.log(this.name, this);}		//undeifned {}
(5)module.exports.name = 'lisi';
(5)let sayName = () => { console.log(this.name, this);}			//lisi {name:'lisi}
let obj = {
     name,
     age,
     
(1)es6      //sayName(){console.log(this.name)}		//terry  this指向obj
(2)转为箭头 //sayName:()=>{console.log(this)}		//{}     指向声明该箭头函数(此处为obj)外部作用域this
(3)变形	    // sayName(){
  			//   console.log(this)          //obj
  			//   return ()=>{
  			//     console.log(this.name)   //terry
  			//   }}
(4)(5)变形	sayName() { return sayName }

}
obj.sayName()();//调用return用两个()
console.log(this===module.exports)   //true module表示当前模块,exports表示空对象

7、类 class********

ES6的类可以看成是 构造函数的另一种写法
es5—> 使用构造函数 --------------->生产实例对象
es6—> 通过class定义一个类 ----->生产实例对象

  • 类默认会提供一个空的构造器 constructor(){}
  • 写在构造器中属性和方法是实例私有属性和方法
  • 写在类体中得方法是实例公共方法,写在类体中得属性是是实例私有属性
  • 使用static关键字声明类得方法和属性是静态方法和属性 (只能由类本身访问)
class Person {
//类默认会提供一个空的构造器 constructor(){}
//但满足不了开发需求,所以要建一个(用于创建实例的同时,可以设置实例属性和方法)。没有构造器就创不了实例
  constructor(name, age, gender) {
// 写在构造器中属性和方法是实例私有属性和方法
    this.name = name;
    this.age = age;
    this.gender = gender;
     this.text = xxx;  相当于18行代码
     this.friends=xxx;  相当于19行代码
  }

// 写在类体中得方法是实例公共方法 相当于写在原型对象中 Person.prototype
  sayName() {
    console.log(this.name)
  }

// 写在类体中得属性是是实例私有属性
  test = 'hello';
  friends = [];
  
// 使用static关键字声明类得方法和属性  静态方法和静态属性 只能由类本身访问
  static attr = 'Person类静态属性';
  static method = function(){console.log('Person类静态方法');}

}


let p1 = new Person('terry',18,'male');
let p2 = new Person('larry',20,'female');

p1.sayName();                             //terry
p2.sayName();                             //larry
console.log(p1.sayName === p2.sayName);   //true

p1.friends.push('tom');
console.log(p1.friends === p2.friends);   //false
console.log(p1.test === p2.test);         //true 还没被修改,但是hello
p1.test='我被修改了';
console.log(p1.test === p2.test);         //false 修改之后,一个我被修改了,一个hello

8、继承 extends********

class可以通过extends关键字实现继承

/**
 * ES6继承 分两类:
 * 1.子类继承父类 
 * 2.子类原型对象继承父类原型对象
 */

class Animal{
  constructor(type,weight,length){
    this.type = type;
    this.weight = weight;
    this.length = length;
  }
  sayType(){
    console.log(this.type,'这是animal实例公共方法')
  }
  static AnimalAttr = 'Animal静态属性';
  static AnimalMethod = function(){ console.log('这是Animal静态方法') }
}
// 子类使用extends关键字实现对父类得继承
class Dog extends Animal{
  // Dog类得内容可以为空,仅继承父的东西。但想设置子类自己的东西就得提供构造器来设置
  // 如果子类提供了构造器必须显示调用super函数
  constructor(type,weight,length,name,color){
    super(type,weight,length);//类似于Animal.call()
    this.name = name;
    this.color = color;
  };
}

let d1 = new Dog('狗','40kg','20cm','可乐','白色');
console.log(d1);               //Dog { type: '狗', weight: '40kg', length: '20cm', name: '可乐', color: '白色'}
d1.sayType();                                       //狗 这是animal实例公共方法
console.log(Dog.AnimalAttr);                        //Animal静态属性
console.log(Dog.AnimalMethod());                    //这是Animal静态方法

// 子类对父类继承 (子类有一个指针指向父类)
console.log(Dog.__proto__ === Animal);                        //true

// 子类原型对象继承父类得原型对象(子类的原型对象有一个指针指向父类的原型对象)
console.log(Dog.prototype.__proto__ === Animal.prototype);    //true

console.log(d1.constructor);                                  //[class Dog extends Animal]
es5继承方式:
/**
 * 1.借用构造函数继承 / 经典继承
 * 2.原型链继承 
 * 3.组合继承
 */
function Animal(type,weight,length){
  this.type = type;
  this.weight = weight;
  this.length = length;
}

// 1.借用构造函数继承
function Dog(type,weight,length,name,color){
  Animal.call(this,type,weight,length);    //.call修改this指向
  this.name = name;
  this.color = color;
}
let d1 = new Dog('狗','40kg','20cm','可乐','白色');
console.log(d1);

// 2.原型链继承  将子构造函数原型指向父构造函数实例
// Animal.prototype = {
//   constructor:Animal,   // 将animal原型对象构造者改为animal 
//   sayType(){
//     console.log(this.type)
//   }
// }
// Dog.prototype = new Animal();              //Animal {}
// Dog.prototype.constructor = Dog;  
// let d1 = new Dog('狗','40kg','20cm','可乐','白色');
// console.log(d1);
// d1.sayType();

9、模板字符串 ${ }********

从字符串中提取变量

let params = {
  page:1,
  pageSize:10
};
// let url = 'http://121.199.0.35:8888/index/pageQuery?page=1&pageSize=10';

// 模板字符串
let url = `http://121.199.0.35:8888/index/pageQuery?page=${params.page}&pageSize=${params.pageSize}`;
console.log(url)

10、迭代器 for…of 遍历********

迭代器是一种机制 是一种接口 。
只要数据结构实现了迭代器接口 就可以使用for …of遍历

作用:

  1. 为各种数据结构,提供一个统一的、简便的访问接口
  2. 使得数据结构的成员能够按某种次序排列
  3. ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of消费

检验是否为迭代器,用for-of遍历或输出let map=new map()括号里的值看结果:

  • 有结果表示是迭代器
  • 报错:Iterator value h is not an entry object表明是迭代器,但报错是因为其他
  • 报错:xxx is not iterable表明不是迭代器。

遍历字符串:

  • 1.for 循环
  • 2.for in循环
  • 3.split(‘’)
  • 4.Array.from()
  • 5.Array.prototype.slice.call(str,0)
  • 6.[…res] = str;
  • 7.for of循环遍历字符串
let str = 'hello';
for(let i=0;i<str.length;i++){
  console.log(i,str[i]);            //0 h  1 e  2 l  3 l  4 o
}
for(let key in str){
  console.log(key,str[key]);        //0 h  1 e  2 l  3 l  4 o
}
for(let key of str){
    console.log(key);               //h e l l o
}

迭代器本质:就是迭代器对象调用得next方法 迭代器对象创建一个指针 指向数据结构首位成员位置,第一次调用指向第一个成员 依次调用依次指向后面成员

let arr = ['terry','larry','ronda','jacky','briup'];
let keys = arr.keys();//返回值是迭代器对象 实现了迭代器接口 for ...of遍历 
let values = arr.values();
let entries = arr.entries();
console.log(keys,values,entries);   //Object [Array Iterator] {}      Object [Array Iterator] {}      Object [Array Iterator] {}

//迭代器本质就是迭代器对象调用得next方法 迭代器对象创建一个指针 指向数据结构首位成员位置
//第一次调用指向第一个成员 依次调用依次指向后面成员
// console.log(keys.next());      //{ value: 0, done: false } false表示不是最后一个成员
// console.log(keys.next());      //{ value: 1, done: false }
// console.log(keys.next());      //{ value: 2, done: false }
// console.log(keys.next());      //{ value: 3, done: false }
// console.log(keys.next());      //{ value: 4, done: false }
// console.log(keys.next());      //{ value: undefined, done: true }
// console.log(keys.next());      //{ value: undefined, done: true }
// console.log(values.next());    //{ value: 'terry', done: false }
// console.log(entries.next());   //{ value: [ 0, 'terry' ], done: false }
//自动调成员
// let result;
// while(!(result=keys.next()).done){
//   console.log(result)        //{ value: 0, done: false }......{ value: 4, done: false }
// }

for(let key of keys){
  console.log(key);         //0 1 2 3 4
}
for(let value of values){
  console.log(value);       //terry larry ronda jacky briup
}
for(let entry of entries){
  console.log(entry);       //[ 0, 'terry' ]......[ 4, 'briup' ]
}



function foo(){
  for(let key of arguments){
    console.log(key);        //1 2 3 4
  }}
foo(1,2,3,4)

let arr1 = [1,2,3,4];
for(let key of arr1){
  console.log(key);          //1 2 3 4
} 

let obj = {name:'zhangsan', age:12,gender:'male'}
for(let key of obj){
  console.log(key);           //报错 obj is not iterable
}

10.1、forEach、for in、for of三者区别

forEach更多的用来遍历 :数组、map、set

for in 一般常用来遍历:对象或数组、字符串、类数组对象

for of遍历实现了迭代器接口的对象,遍历对象需要通过Object.keys()、values()、entries()

11、 新增方法********

11.1、对象

静态方法(构造函数本身访问):

  • Object.is(a,b)                          判断ab是否相等 (外观上)
  • Object.assign(a,b)                   两个参数实现对象复制、拷贝 。b复制给a,并返回a
  • Object.assign(a,b,c)                 三个参数代表的是合并对象,合并abc到a中,并返回a
  • Object.getPrototypeOf()                     获取原型对象中的方法
  • Object.setPrototypeOf(a,b);               设置原型对象中的方法 (将a原型对象设置为b)
  • Object.keys(a)                          获取a的属性名组成数组
  • Object.values(a)                       获取b属性值组成数组
  • Object.entries(a)                       获取a属性名和属性值组成的二维数组
  • Object.fromEntries( Object.entries(a) )            将对象属性名和属性值组成二维数组转为对象
// 1.is 判断两个值是否相等 (外观上)
console.log(Object.is(1,1));     //true
console.log(Object.is(+0,-0));   //false 符号位也被进行判断
console.log(+0 === -0);          //true
console.log(Object.is(NaN,NaN)); //true
console.log(NaN === NaN);        //false



//2.1 Object.assign(a,b)  将b复制给a
let o = {};
let obj = { name:'zhangsan',age:12,
 		   //对基本数据类型实现深拷贝  (对引用数据类型实现浅拷贝--半深拷贝)
    	   clazz:{ no:'2023'  }};
let res = Object.assign(o,obj);//将obj对象复制给o对象 同时返回o对象
console.log(res,res===o,res===obj); //{ name: 'zhangsan', age: 12, clazz: { no: '2023' } } true false
o.clazz.no = '2024';
console.log(o,obj);         //{ name: 'zhangsan', age: 12, clazz: { no: '2024' } } { name: 'zhangsan', age: 12, clazz: { no: '2024' } }

//2.2 Object.assign(a,b,c)  将abc合并
let o = {name:'zhangsan'};
let obj = {age:12};
let obj1 = {gender:'male'};
let res = Object.assign(o,obj,obj1);//返回第一个参数
console.log(res,res===o);//{ name: 'zhangsan', age: 12, gender: 'male' } true



//3. Object.getPrototypeOf()
let obj = {
  name:"zhangsan",
  age:12
}
// 获取原型对象 getPrototypeOf 
console.log(obj.__proto__);               //[Object: null prototype] {}
console.log(obj.constructor.prototype);   //[Object: null prototype] {}
console.log(Object.getPrototypeOf(obj));  //[Object: null prototype] {}



//4. setPropertypeOf(a,b)
let obj = {};
let obj1 = {name:'zhangsan',age:12};
Object.setPrototypeOf(obj,obj1);//将obj原型对象设置为obj1
console.log(obj.__proto__)//{ name: 'zhangsan', age: 12 }
console.log(obj.constructor.prototype);//[Object: null prototype] {}   (注意 获取不到新原型对象)
console.log(Object.getPrototypeOf(obj));//{ name: 'zhangsan', age: 12 }


/**
 * keys values entries
 * keys 获取对象属性名组成数组
 * values 获取对象属性值组成数组
 * entries 获取对象属性名和属性值组成得数组
 * fromEntries将对象属性名和属性值组成二维数组转为对象
 */
let obj = {
  name:'zhangsan',
  age:12,
  gender:'male'
}
console.log(Object.keys(obj));                          //[ 'name', 'age', 'gender' ]
console.log(Object.values(obj));                        //[ 'zhangsan', 12, 'male' ]
console.log(Object.entries(obj));                       //[ [ 'name', 'zhangsan' ], [ 'age', 12 ], [ 'gender', 'male' ] ]
console.log(Object.fromEntries(Object.entries(obj)));   //{ name: 'zhangsan', age: 12, gender: 'male' }

11.2、数组

静态方法(构造函数本身访问):

  • Array.from()           将类数组转换为数组
  • Array.of()               创建数组实例

实例方法(原型中方法):

  • .find()               返回第一个满足条件的数组元素或者undefined 。参数:回调函数
  • .findIndex()       返回第一个满足条件的数组元素索引或者-1 。参数:回调函数
  • .includes()         检测元素是否存在数组中
  • .fill()                   填充数组 会修改原数组
  • .keys()               返回得是实现了迭代器接口对象 iterator。 加 .next()后获取的是索引
  • .values()             返回得是实现了迭代器接口对象 iterator 。加 .next()后获取的是元素
  • .entries()             返回得是实现了迭代器接口对象 iterator 。加 .next()后获取的是索引和元素
  • .flat()                   扁平化数组 数组层级展开
  • .flatMap()           将数组展开 每个数组元素*2
// 1.将类数组对象转为数组对象 from  
function foo(){
  console.log(arguments,'类数组对象');  //[Arguments] { '0': 1, '1': 2, '2': 3, '3': 4 } 类数组对象
  console.log(Array.from(arguments));                   //[ 1, 2, 3, 4 ]
  console.log([...arguments]);                          //[ 1, 2, 3, 4 ]
  console.log(Array.prototype.slice.call(arguments,0))  //[ 1, 2, 3, 4 ]
}
foo(1,2,3,4)



// 2.of 创建数组实例
let arr1 = new Array(10);                     //[ 10 ] 
let arr = Array.of(10);                       // [ <10 empty items> ]
console.log(arr,arr1,arr instanceof Array);   //true



// 3.find 返回第一个满足条件的数组元素或者undefined  参数:回调函数
let arr = [1,2,3,4,5];
let res = arr.find(function(item,index,arr){
  return item>3
});
console.log(res);     //4



// 4.findIndex 返回第一个满足条件的数组元素索引或者-1  参数:回调函数
let arr = [1,2,3,4,5];
let res = arr.findIndex((item,index,arr)=>{
  console.log(item,index,arr);
  return item>5
});
console.log(res,arr);
// 1 0 [ 1, 2, 3, 4, 5 ]
// 2 1 [ 1, 2, 3, 4, 5 ]
// 3 2 [ 1, 2, 3, 4, 5 ]
// 4 3 [ 1, 2, 3, 4, 5 ]
// 5 4 [ 1, 2, 3, 4, 5 ]
// -1 [ 1, 2, 3, 4, 5 ]



// includes 检测数组元素是否存在数组中 存在返回true 不存在返回false
let arr = [1,2,3,4,('hello'/2)];
console.log(arr.includes('2'));         //false  针对于NaN优化
console.log(arr.includes(('hello'/2))); //true
console.log(arr.indexOf(('hello'/2)));  //-1


// fill 填充数组  修改原数组
let arr = [1,2,3,4];
let res = arr.fill(8);
console.log(arr,res); //[ 8, 8, 8, 8 ] [ 8, 8, 8, 8 ]



// keys values entries  返回得是实现了迭代器接口对象  iterator 
let arr = [1,2,3,4,5];
console.log(arr.keys());	//Object [Array Iterator] {}
console.log(arr.values());  //Object [Array Iterator] {}
console.log(arr.entries()); //Object [Array Iterator] {}
console.log(arr.keys().next());      //{ value: 0, done: false }
console.log(arr.values().next());    //{ value: 1, done: false }
console.log(arr.entries().next());   //{ value: [ 0, 1 ], done: false }



// flat方法 扁平化数组 数组层级展开 
let arr = [1,2,[3,4,5,[6,7,8,[9,10,[11]]]]];
console.log(arr.flat(1));//[ 1, 2, 3, 4, 5, [ 6, 7, 8, [ 9, 10, [Array] ] ] ]
console.log(arr.flat(Infinity));
// [
//   1, 2, 3, 4,  5,
//   6, 7, 8, 9, 10,
//  11
// ]



// flatMap flat和map方法结合 需求 将数组展开 每个数组元素*2
let arr = [1,2,[3,4]];
let res = arr.flatMap((item,index,arr)=>{
  // console.log(item,index,arr)
  if(typeof item=='number'){
    return item * 2
  }else{
    return item.map((it)=>{return it*2})
  }
})
console.log(res);     //[ 2, 4, 6, 8 ]

11.3、数字

  • .isFinite ()                           是否为有效值,会隐式转换
  • Number.isFinite ()              是否为有效值,不会隐式转换
  • .isNaN ()                                数字返回false,其他返回true
  • Number.isNaN()                 非NaN返回false,其他返回true
  • Number.parseInt()              返回整数
  • Number.parseFloat()          返回小数
  • Number.isInteger()             判断是否为整数
// isFinite 检测值是否是有效值 隐式转换 
console.log(isFinite(null));              //true
console.log(isFinite(""));                //true
console.log(isFinite('10'));              //true
console.log(isFinite(true));              //true
console.log(isFinite([]));                //true
console.log(isFinite('hello'/10));        //false
// Number.isFinite  检测有效值 对于有效值返回true 对于无效值返回false 不做隐式转换
console.log(Number.isFinite(null));        //false
console.log(Number.isFinite(''));          //false
console.log(Number.isFinite('10'));        //false
console.log(Number.isFinite(true));        //false
console.log(Number.isFinite(10));          //true




// isNaN 判断是否是一个数字 是数字返回false 其他返回true
console.log(isNaN(10));                   //false
console.log(isNaN('hello'/10));           //true
console.log(isNaN('hello'));              //true
//  Number.isNaN 对于非NaN一律返回false 只有对NaN才返回true
console.log(Number.isNaN('hello'/10));     //true
console.log(Number.isNaN('hello'));        //false           只对NaN返回true 其他都是false
console.log(isNaN('hello'));               //true            只对数字返回false  其他都返回true
console.log(Number.isNaN(10));             //false



// parseInt parseFloat 
console.log(Number.parseInt('10.1'));           //10
console.log(Number.parseInt('10.123'));         //10
console.log(Number.parseFloat('12.123'));       //12.123
console.log(Number.parseFloat('12.123#'));      //12.123



// 检测是否是整数  对于整数返回true  对于非整数返回false
console.log(Number.isInteger('12.1'));          //false
console.log(Number.isInteger(12));              //true
console.log(Number.isInteger(12.1));            //false
console.log(Number.isInteger('12'));            //false

11.4、字符串、函数

字符串:

  • .trimStart(a)                                   去除a前面空格
  • .trimEnd(a)                                     去除a后面空格
  • .padStaart(num,[ ‘字符串’ ] )         从头部添加字符串
  • .padEnd(num,[ ‘字符串’ ] )             从尾部添加字符串

函数:

  • .toString()                 将从头到尾返回源代码中的实际文本片段(包括注释,空格,语法详细信息)
// 单独去除字符串前后空格 trim 
let str = '  hello world  ';
console.log(str);                           //  hello world 
console.log(str.trim());                    //hello world
// //单独去除前面空格 trimStart 别名trimLeft
console.log('2'+str.trimStart()+'2');       //2hello world  2
console.log('2'+str.trimLeft()+'2');        //2hello world  2
// // 单独去除后面空格 trimEnd 别名trimRight
console.log('2'+str.trimEnd()+'2')          //2  hello world2
console.log('2'+str.trimRight()+'2')        //2  hello world2


//pad..(填充后长度,填充字符(默认空格))
// padStart 从头部添加字符串 
let str = 'es8';
console.log(str.padStart(4),'2'+str);   // es8 2es8
console.log(str.padStart(4,'h'));       //hes8
console.log(str.padStart(2));           //es8      填充长度小于原长度 ,返回源字符串
console.log(str.padStart(6,'ab'));      //abaes8   填充长度大,就重复添加字符串
// padEnd 从尾部添加字符串 
console.log(str.padEnd(4)+'2');         //es8 2
console.log(str.padEnd(4,'h'));         //es8h
console.log(str.padEnd(2));             //es8
console.log(str.padEnd(6,'45'));        //es8454




function foo(){
  console.log('我是函数');
  // 我是函数内的注释
    return ;
}
console.log(foo.toString());// function foo(){
							//     console.log('我是函数');
							//     // 我是函数内的注释
							//       return ;
							//   }
let str = 'hello';
let reg = /l/g;//正则表达式/ /,g表示全部global
console.log(str.replace(reg,'L'));      //heLLo
console.log(str.replaceAll('l','L'));   //heLLo

12、新增数据类型********

基本数据类型

12.1、Symbol

var sy1 = Symbol();
表示独一无二的值,Symbol函数创建独一无二得值。
无论参数是什么数据类型,最终都会转为字符串
一般属性可以 obj.属性 来访问;symbol属性用 obj [ 属性 ] 来访问
symbol值创建的属性无法遍历

let sy1 = Symbol();//创建好一个独一无二得值
let sy2 = Symbol();
console.log(sy1,sy2)                              //Symbol() Symbol()
console.log(sy1 === sy2);                         //false
console.log(typeof sy1,sy1 instanceof Object);    //symbol false

//symbol()中放参数表示:对独一无二值的描述
let sy1 = Symbol('symbol数据类型');      //Symbol("symbol数据类型")
let sy2 = Symbol({name:'zhangsan'})     //Symbol("[object Object]")
let sy3 = Symbol([1,2,3]);              //Symbol("1,2,3")
let sy4 = Symbol(null);                 //Symbol("null")
console.log(sy1,sy2,sy3,sy4);
  • Object.getOwnPropertySymbols(obj)         访问所有symbol创建的属性
  • Symbol.for                    创建一个symbol值的时候进行全局注册
  • Symbol.keyFor        检测symbol值有没有在全局注册过 注册过返回symbol值得描述 没有返回undefined

Symbol的应用:

  1. 解决命名冲突
let sy1 = Symbol('name');
let sy2 = Symbol('age');
let obj = {
  name:'zhangsan',
  age:12,
  [sy1]:'terry',         //对象中的[]可以解析变量
  [sy2]:18,
  [Symbol('email')]:'xxx@briup.com'
};
console.log(obj[sy1]);                //可以访问属性  terry
console.log(obj[sy2]);                //18
console.log(obj[Symbol('email')]);    //无效  undefined

//如何访问Symbol创建的属性? 
console.log(Object.getOwnPropertySymbols(obj));//获取对象中所有symbol属性,访问symbol创建的所有属性
var ss = Object.getOwnPropertySymbols(obj);//[ Symbol(name), Symbol(age), Symbol(email) ]
console.log(obj[ss[0]],obj[ss[1]],obj[ss[2]]);      //terry 18  xxx@briup.com

for(let key in obj){
  console.log(key)      // 遍历对象 使用symbol值创建属性无法遍历 
}



  1. 消除 魔术字符串(非常依赖对字符串的命名,名字一错,代码就没效果)(与代码形成强耦合的某一个具体的字符串或者数值)
//魔术字符串:在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。代码对字符串依赖性非常强 ,形成强耦合关系 形成了魔术字符串
function Area(shape,options){
  let area = 0;
  switch(shape){
    case 'triangle':
      area = options.width * options.height * 0.5;
      break;
    case 'square':
      area = options*width * options.height;
      break;
    case 'circle':
      area = Math.PI * options.r * options.r;
      break;
    default:
      area = -1;
  }
  return area;
}
let res = Area('triangle',{width:100,height:100,r:50});
console.log(res);
//这个函数对字符串的依赖很大,若triangle打错,则出不来结果




//优化后:通过再封装一个对象,包含要求的那些
function Area(shape,options){
  let area = 0;
  switch(shape){
    case Shape.SJX:
      area = options.width * options.height * 0.5;
      break;
    case Shape.ZFX:
      area = options.width * options.height;
      break;
    case Shape.CIRCLE:
      area = Math.PI * options.r * options.r;
      break;
    default:
      area = -1;
  }
  return area;
};

// 枚举:类型可以罗列出来     性别:男 女 
let Shape = {
  SJX:Symbol('三角形'),
  ZFX:Symbol('正方形'),
  CIRCLE:Symbol('圆')
}

let res = Area(Shape.ZFX,{width:100,height:100,r:50});
console.log(res);

3.全局注册表    symbol.for()

  • 与Symbol() 不同的是,用 Symbol.for() 方法创建的的 symbol 会被放入一个全局 symbol 注册表中。
  • Symbol.for() 并不是每次都会创建一个新的 symbol,它会首先检查给定的 key 是否已经在注册表中了。假如是,则会直接返回上次存储的那个。否则,它会再新建一个。
// 可以创建一个symbol值的时候进行全局注册 
let sy1 = Symbol.for('name');
let sy2 = Symbol.for('name');
console.log(sy1 === sy2);          //true

let sy3 = Symbol('age');
let sy4 = Symbol('age');
console.log(sy3 === sy4);           //false

// Symbol.keyFor 检测symbol值有没有在全局注册过 注册过返回symbol值得描述 没有返回undefined
console.log(Symbol.keyFor(sy1));    //name
console.log(Symbol.keyFor(sy2));    //name
console.log(Symbol.keyFor(sy3));    //undefined
console.log(Symbol.keyFor(sy4));    //undefined

12.2、BigInt

引用数据类型

12.2、Set

var set=new Set();
类似数组,但成员值是唯一的,set会去重,没有重复的值(例:参数为hello,输出只有一个l)。
参数为:数组具有迭代器接口的其他数据结构

set中对于引用数据类型,因其每个引用地址不同,所以即使外观相同,但也不会去重;若要删除,应为其赋值变量,从而通过删除变量来删除对应数组

  • set.add(参)                  添加成员
  • set.delete(参)              删除成员
  • set.keys()                        遍历
  • set.values()                     遍历
  • set.entries()                     遍历
  • set.forEach(函数)            遍历
  • set.size                        返回set成员个数
  • set.has(参)                  判断set集合中有没有这个成员
  • set.clear()                    清空set成员
  • set方法可以用于数组去重
// let set = new Set([1,2,3,4,3,2,1]);       //Set(4) { 1, 2, 3, 4 }
// let set1 = new Set('hello');              //Set(4) { 'h', 'e', 'l', 'o' }因为成员只有1个,所以只有一个l
// let set2 = new Set({name:'zhangsan'});    //报错 

let set = new Set();
// 添加成员 add
set.add('hello');
set.add(10);    		num类型的10可以添加,但不能作为Set()的参数
set.add('hello');
set.add([]);    		引用数据类型在堆区中有自己的引用地址
set.add([]);    		所以这两个[]不相同,因为引用地址不同
// console.log(set);                  //Set(4) { 'hello', 10, [], [] }
let arr = [];   		删除之前的数组,要给他赋值一个变量
set.add(arr);
// console.log(set);                  //Set(5) { 'hello', 10, [], [], [] }
// 删除成员 delete 
console.log(set.delete('hello'));     //true
console.log(set.delete(arr));         //true
console.log(set);                     //Set(3) { 10, [], [] }




// keys values entries 
console.log(set.keys());              //[Set Iterator] { 10, [], [] }
console.log(set.values());            //[Set Iterator] { 10, [], [] }
console.log(set.entries());           //[Set Entries] { [ 10, 10 ], [ [], [] ], [ [], [] ] }
for(let key of set.keys()){
    console.log(key);                 //10 [] []
}

// forEach 遍历set集合
set.forEach((key,value)=>{
    console.log(key,value)             //10 10      [] []      [] []
})

// 返回set成员个数
console.log(set.size,'返回成员个数');   //3 返回成员个数
// 判断set集合中有没有这个成员
console.log(set.has(null))             //false
// 清空set成员
set.clear();
console.log(set)                       //Set(0) {}



// set应用 数组去重 
let set1 = new Set([1,2,3,4,5,4,3,2,1]);
console.log(Array.from(set1));         // [ 1, 2, 3, 4, 5 ]
console.log([...set1])                 // [ 1, 2, 3, 4, 5 ]

12.3、Map

let map=new Map();
类似于对象,也是键值对形式的数据结构,键可以是时任意数据类型,实现了迭代器接口

/MapObject
键类型任意数据类型只能是string / symbol类型
键顺序有序的,按照插入键得顺序依次返回无序的,但是也保留字符串或者symbol值得插入顺序
键值对个数通过size获取手动计算
迭代实现了迭代器接口,可以直接使用for…of遍历没有实现迭代器接口,无法直接for…of遍历
性能频繁增删键值对用map更好频繁增删键值对在object中未作出优化
  • map.set(参)                     添加成员
  • map.delete(参)                删除成员
  • map.get(参)                    获取成员键所对应的值
  • map.size()
  • map.keys()                     获取键组成迭代器对象
  • map.values()                  获取值组成迭代器对象
  • map.entries()                  获取键和值组成迭代器对象
  • map.forEach(函数)         遍历
  • 应用:写购物车
// let obj = {
//   name:'zhangsan',
//   null:'hello',
//   [Symbol('email')]:'xxxx.com'
// }
let obj = {
  name:'zhangsan',
  age:12
}
// console.log(Object.entries(obj));    //[ [ 'name','zhangsan' ],[ 'age', 12 ] ]将对象转成键值对
let map = new Map(Object.entries(obj));
// 添加成员 set 
//map.set(1,1)
map.set({name:'map'},'hello');
let foo = function(){}
map.set(foo,null);
console.log(map);               //Map(4) { 'name' => 'zhangsan',  'age' => 12,  { name: 'map' } => 'hello',  [Function: foo] => null}

// 删除成员 
map.delete('name');
// map.delete(function(){});//这里也删不掉,同set原理一样,引用地址不同
map.delete(foo);
console.log(map);                 //Map(2) { 'age' => 12, { name: 'map' } => 'hello' }

// 获取成员键所对应的值
console.log(map.get('age'));     //12
console.log(map.get(foo));       //undefined
console.log(map.size);           //2

console.log(map.keys());//获取键组成迭代器对象        [Map Iterator] { 'age', { name: 'map' } }
console.log(map.values());//获取值组成迭代器对象      [Map Iterator] { 12, 'hello' }
console.log(map.entries());//获取键和值组成迭代器对象 [Map Entries] { [ 'age', 12 ], [ { name: 'map' }, 'hello' ] }

// // 遍历map
map.forEach((value,key)=>{
  console.log(value,key)            //12 age     hello { name: 'map' }
})



//原型对象
console.log(Map.prototype,Set.prototype);      //Object [Map] {}      Object [Set] {}

12.4、promise(详情看13.3)

13、三个异步编程解决方案********

13.1、Promise

  • 作用:封装ajax与axios
  • 是一个承诺对象,存放着将来才会执行的代码(当给出它是成功还是失败后才会执行,所以不给它结果它就不会执行,从而达到控制代码执行时间的效果),
  • 从语法的角度来说是一个对象,主要获取异步操作的消息
  • (异步编程 同步解决)避免了层层嵌套的回调函数,可以链式调用降低操作难度。
  • 成功执行then方法,失败执行catch方法

var xxx= new Promise( 回调函数(resolve,reject)

  • resolve----表示请求成功执行的回调函数–由then方法提供
  • reject —表示请求失败执行的回调函数 —由catch方法提供

promise实例对象的三种状态:

  • pending ---- 未操作/进行中
  • fullfilled ---- 已成功
  • rejected ---- 已失败

promise实例的两种方法:

  • promise.then():       当实例状态为fullfilled时候执行回调函数 resolve()
  • promise.catch():      当实例状态为rejected时候执行回调函数 reject()
<script>
    console.log(Promise,'Promise构造函数');             //function Promise()     Promise构造函数
    let promise = new Promise((resolve, reject) => {
      // 发起异步请求  if(res.status===200){   }else{  }   
      // 模拟异步请求
      if (3 < 2) {
      //   // 异步请求成功 resolve 由then方法回调函数提供
        resolve('请求成功')
      } else {
      //   // 异步请求失败 reject 由catch方法回调函数提供
        reject('请求失败')
      }
    });
// 顺序:这里调用reject,promise的实例就变成rejected失败,然后下面就会执行catch方法的这个回调函数


    console.log(Promise, promise instanceof Object);    //function Promise()    true
    // resolve函数是由then方法提供得回调函数----处理promise实例状态为fullfilled得回调函数
    // reject函数 是由catch方法提供得回调函数
    promise.then((res)=>{
      console.log(res,'成功得回调')      //请求成功,成功得回调
    }).catch((error)=>{
      console.log(error,'失败得回调')
    }).finally(()=>{
      console.log('finally最终执行')     //finally最终执行(无论成功与否都会执行)
    });
    
    // // 也可以:then可以接收两个回调函数 
    // promise.then((res)=>{
    //   // 第一个回调函数表示promise实例状态为fullfilled执行回调函数
    //   console.log(res,'1111')
    // },(error)=>{
    //   // 第二个回调函数表示promise实例状态为rejected执行回调函数----reject
    //   console.log(error,'2222')
    // })
    // console.log(Promise,'33333')



	//调用之后还能继续调用(链式调用)的原因:因为调完一个方法之后输出的还是promise实例对象,还可以调用原型对象中的方法
    // let result = promise.then(()=>{}).catch(()=>{}).finally(()=>{});
    // console.log(result);             //Promise { <state>:"pending" }
  </script>
  • 调用之后还能继续调用 (链式调用)的原因 :因为调完一个方法之后输出的还是promise实例对象,还可以调用原型对象中的方法

promise静态方法:
前4个参数为:[ 多个promise实例 ]或一些实现了迭代器接口的数据结构

  • Promise.all()           得到一个promise实例对象,所有实例请求成功或者所有实例都为fullfilled 实例才是fullfilled
  • Promise.any()         得到一个promise实例对象,任意一个实例请求成功或者实例变为fullfilled 实例就是fullfilled
  • Promise.race()                    哪个实例状态先变为fullfilled 就返回哪一个实例
  • Promise.allSettled()            对每一个promise实例都进行处理
  • Promise.resolve()       得到状态发生改变(fullfilled)promise实例
  • Promise.reject()          得到状态发生改变(rejected)promise实例
  • promise的应用
    • 封装ajax(如下代码) 或 axios(axios一般不用,因为可以使用async和awite处理 / 已经基于promise做过封装,不需要咱们做封装,直接调用axios.get/post,就能得到基于promise得axios请求)
通过封装工厂函数 得到一个基于promise得ajax请求
// 原生:一种方法得封装一个函数
// function getSwipe(){var xhr=new XMLHttpRequest();}
// function getSwipe(){var xhr=new XMLHttpRequest();}

    function getPromise(method,url,data,params){
      // data---post携带参数    params---get请求携带参数
      return new Promise((resolve,reject)=>{
        var xhr = new XMLHttpRequest();
        xhr.open(method,url);
        xhr.send();
        xhr.onreadystatechange = function(){
          if(xhr.readyState===4){
            if(xhr.status===200){
              resolve(xhr.response)
            }else{
              reject(xhr.responseText)
            }
          }
        }
      })
    }
    
    let p1 = getPromise('get','http://121.199.0.35:8888/index/carousel/findAll');
    let p2 = getPromise('get','http://121.199.0.35:8888/index/category/findAll');
    //promise静态方法:
  //  let res =  Promise.all([p1,p2]);
  //  let res =  Promise.any([p1,p2]);
  //  let res =  Promise.race([p1,p2]);
  //  let res =  Promise.allSettled([p1,p2]);
  //  console.log(res);
  // res.then(res=>{
  //   console.log(res)
  // })
  // console.log(Promise.resolve(),'111');
  // console.log(Promise.reject(),'222');
    console.log(p1,p2);
    
    p1.then(res=>{
      console.log(JSON.parse(res),'111')
    })
    p2.then(res=>{
      console.log(JSON.parse(res),'222')
    });

13.2、async异步函数和awite

  • 作用:1、异步编程同步处理;2、简化promise API的一种解决方案;

  • async函数是使用async关键字声明的函数,与await一起连用让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用promise。

  • await关键字只在async函数内有效

  • 该异步函数内部封装了generator函数,输出的是promise对象(也是经过promise封装后才会输出promise对象)
    详细介绍

1. async 是异步的意思,await则可以理解为 async wait。所以可以理解async就是用来声明一个异步方法,而 await是用来等待异步方法执行
2. async作为一个关键字放在函数前面,表示该函数是一个异步函数(异步函数意味着该函数的执行不会阻塞后面代码的执行);
而 await 用于等待一个异步方法执行完成;
3. 当函数内部执行到一个 await 语句的时候,如果语句返回一个 promise 对象,那么函数将会等待 promise 对象的状态变为 resolve 后再继续往下执行。并会阻塞该函数内后面的代码。
4. 因此async/await的作用就是将异步逻辑,转化为同步的顺序来书写,并且这个函数可以自动执行。
5. 为了优化 .then 链而开发出来的。

 /**
     * 异步编程解决方案 : 1.异步编程 同步解决 2.简化promise API一种解决方案 
     * 内部封装了generator函数 与await配合使用 
     * 返回的是一个Promise{}
    */
<script>
    async function findAll() {
      //同步写法
      let res = await axios.get('http://121.199.0.39:8888/index/carousel/findAll');//这个请求很长,如果用同步打印则可能输出不完整,但若是用异步等他请求完再输出则是完整的
        console.log(res, '获取响应111111111');

      //异步写法    axios.get().then().catch()//链式调用promise   then处理请求成功情况,catch处理请求失败的情况
      // axios.get('http://121.199.0.35:8878/index/carousel/findAll').then(res=>{        基于axios请求发回来的都是promise的实例对象,就可以调用promise的实例方法,而then也是再原型对象上
      //   console.log(res.data,'获取响应')
      // }).catch(error=>{
      //   console.log(error,'444');
      // })
    }
    findAll();
  </script>

13.3、Generator函数

  • 语法不同于普通函数,内部有多个使用yiled表示的状态,每个状态都是独立的(1中定义,2中并不能输出1的定义,除非传参)。
  • 范围:上一个yield语句冒号结束~~~下一个yield语句冒号结束
  • 调用Generator 函数会返回一个迭代器对象,可以通过调用迭代器 .next() 依次遍历Generator函数内部的每一个状态。(调用一次,执行一个状态)
  • function关键字与函数名之间有个星号
<script>
    function * generator(){
      // generator函数内部使用yield表示一个状态 一个yield就是一个状态 一个yield就是一个代码运行节点
      yield '1';
      yield '2';
      yield '3';
      return '4'
      // generator函数最后一个状态可以使用return返回
    }
    let res = generator();//调用generator函数得到一个迭代器对象  输出res为:  Generator {  }
    console.log(res.next());//Object { value: "1", done: false } 调用一次next方法执行一个状态
    console.log(res.next());//Object { value: "2", done: false }
    console.log(res.next());//Object { value: "3", done: false }
    console.log(res.next());//Object { value: "4", done: true }
    
  //普通函数无法实现依次返回
  //  function foo(){
  //     // 执行代码 返回
  //     return 1
  //     // 执行代码 返回
  //     return 2 
  //     // 执行代码 返回
  //     return 3
  //  }
  //  console.log(foo());    只会return 1 
  </script>

想要在第二个状态中使用第一个状态的返回值:

  • 直接发起状态执行不能获取第一状态的返回值
  • 给第二个.next()传固定参数,可以获取固定参数却不能获取第一状态的返回值
  • 所以:给第二个.next()传的参数应为第一个状态的返回值就可以
//正确写法:
<script>
    function * generator(){
      let result = yield findAll();
      console.log(result,'result为获取的第一个状态返回值');
      yield '2';
    }
    let res = generator();//调用generator函数得到迭代器对象
    res.next();//发起第一个状态执行

    // 封装异步请求
    async function findAll(){
      let response = await axios.get('http://121.199.0.35:8888/index/carousel/findAll');
      console.log(response,'获取响应');
      res.next(response.data); //response.data为第一个状态的返回值
    }
  </script>





//错误写法:
<script>
    function *generator(){
      // 模拟异步请求  第一个状态
      log();
      let res = yield 'hello';

      // 第二个状态
      console.log(res,'res为获取的第一个状态返回值');
      log();
      yield '2';

      log();
      yield '3';
    }
    let result = generator();
    result.next();//执行第一个状态   123456789
    // result.next();//执行第二个状态   undefined 获取第一个状态返回值  123456789
    result.next(100);//执行第二个状态      100    获取第一个状态返回值  123456789

    // 模拟异步函数
    function log(){
      for(let i=1;i<10;i++){
        console.log(i)
      }
    }
  </script>

14、事件循环********

JS事件循环机制详情

首先了解:
js是单线程语言:同一时间只能做一件事情,异步代码会被放在任务队列中等待执行,先执行同步任务,再执行异步任务。
js任务分为同步任务和异步任务

  • 同步任务:,不耗时,立即执行的任务;在主线程上排队执行,形成一个执行栈;只有前一个任务执行完毕,才能继续执行下一个任务。
  • 异步任务:耗时,不进入主线程,而进入“任务队列”的任务;只有等主线程任务全部执行完毕。“任务队列”的任务才会进入主线程执行。分为微任务、宏任务
    • 微任务:较短时间内可以完成的任务(promise.then 、catch、 finally 、 async、 await之后的代码语句相当于创建微任务)
    • 宏任务:需要相对较长时间才能完成的任务(定时器setTimeout、 间歇调用、 I/O操作 、文件读取(fs.readFile()) 、网络请求)

执行顺序:同步任务 > 微任务 > 宏任务
面试的例题:求输出

//setTimeout第二个参数可以省略,默认为0     //2 4 5 7 10   3 8 6   1 9 
setTimeout(function () {
  console.log('1');
});              

// new Promise((resolve,reject)=>{})
new Promise(function (resolve){      //这里new promise()表示声明的同时也调用
  console.log('2');//调用构造函数
  resolve();
}).then(function () {
  console.log('3');//then方法是耗时任务
});

console.log('4');

async function async1() {
  console.log(5);
  const result = await async2();      
  //await之后的语句都会变成微任务
  console.log(6);
}

async function async2() {
  console.log(7);
}

Promise.resolve().then(() => {
  console.log(8);
});

setTimeout(() => {
  console.log(9);
});

async1();

console.log(10); 

// 主线程:      异步队列:读取文件 fs.readFile() 网络请求

//       打印2          微任务:打印3             宏任务:定时器打印1 
//       打印4                 打印8                    定时打印9
//       打印5                 打印6
//       打印7  
//       打印10               3 8 6               1 9

15、防抖和节流********

可在lodash官网/bootcdn官网中直接调用,不用自己封装

函数目的:为了优化高频率js事件得手段

  • 防抖:在一定时间内,事件一直频繁触发,会重新计算时间,直到超过设定时间,函数才会执行最后一次。一般针对输入框的事件防抖
  • 节流:在一定时间内,事件一直频繁触发,会每隔设定时间函数才会执行一次。一般针对浏览器的窗口事件节流

防抖:

  <script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
</head>

<body>
  <input type="text">
  <script>
    console.log(_);
    var input = document.querySelector('input');
    // 监听输入框事件,会一直触发
    // input.oninput =function(){
    //   console.log(this.value)
    // }

    //防抖(采用lodash库里的.debounce方法)
    // input.oninput = _.debounce(function(){
    //   console.log(this.value)
    // },1000)


    //自己写防抖函数
    let timer;
    input.oninput = function(){
      if(timer){
        clearTimeout(timer)
      }
      var that = this;
      timer = setTimeout(function(){
        console.log(that.value)
      },1000)
    }


    //完整自写防抖(将上述防抖函数封装)
    input.oninput = debounce(function () {
      console.log(this.value)
    }, 1000)
    function debounce(callback, wait) {
      let timer;
      return function () {
        if (timer) {
          clearTimeout(timer)
        }
        var that = this;
        timer = setTimeout(function () {
          console.log(this)
          callback.call(that);
        }, wait)
      }
    }
  </script>
</body>

节流:

<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
  <style>
    body {
      height: 3000px;
    }
  </style>
</head>

<body>
  <script>
    //节流正确写法
    // window.onscroll = _.throttle(function () {
    //   console.log('我正在滚动')
    // }, 1000);
    
    
    //自己封装节流函数
    window.onscroll = throttle(function () {
      console.log('我正在滚动')
    }, 1000);
    function throttle(callback, wait) {
      let id;
      return function () {
        if (!id) {
          id = setTimeout(function () {
            callback();
            id = null;
          }, wait)
        }
      }
    }
  </script>
</body>
  • 33
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
webpack的重要知识点包括以下几个方面: 1. 模块化打包:webpack将前端的所有资源文件都视为模块,并根据模块的依赖关系进行静态分析,最终打包生成对应的静态资源。 2. 配置文件:webpack使用webpack.config.js文件来配置打包过程。在配置文件中可以设置入口文件、输出路径、加载器、插件等各种参数,以满足项目的需求。 3. 加载器:webpack通过加载器来处理各种类型的文件。常用的加载器有babel-loader用于处理ES6及以上的JavaScript代码,css-loader用于处理CSS文件,file-loader用于处理图片和字体文件等。 4. 插件:webpack的插件用于扩展其功能。常用的插件有HtmlWebpackPlugin用于生成HTML文件,CleanWebpackPlugin用于清理输出目录,MiniCssExtractPlugin用于提取CSS文件等。 5. 开发服务器:webpack-dev-server是一个开发服务器,它可以在内存中编译代码并提供资源,实现快速的开发和调试。 以上是webpack的一些重要知识点,它们可以帮助你更好地理解和使用webpack进行前端资源的构建和打包。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [webpack打包基础知识点es6知识点.xmind](https://download.csdn.net/download/qq_43291759/13106867)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Webpack重要知识点](https://blog.csdn.net/sinat_17775997/article/details/95167425)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [webpack知识点总结](https://blog.csdn.net/baidu_39067385/article/details/119428908)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值