es6学习笔记

let/const/var

varconst/let
变量提升不存在变量提升
变量覆盖同一作用域 { } 下不可以重复声明
没有块级作用域有块级作用域 { }
全局声明变量会变成window下的不会
生命周期不受代码块影响受影响

const

声明一个只读变量,一般用于全局变量,只能被赋值一次
const一旦声明变量,就必须立即初始化,不能留到以后赋值

const PI=3.14159

const obj={ a:1 } obj.b=2; console.log(obj);//{a:1 ,b:2}
注:
const实质,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。
对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。

const num=Object.freeze({a:1,b:2})//冷冻对象,之后就改不了了
num.c=3
console.log(num)//{a:1,b:2}

作用域

作用域
ES5:全局作用域、局部(函数)作用域
ES6:全局作用域、局部(函数)作用域、块级作用域

块级作用域

块级作用域:简单的理解如果一段代码是由一个大括号包裹起来的,那么这个大括号里面就是一个块级作用域,if和for语句里面的{ }也属于块作用域。
ES6 的块级作用域必须有大括号,如果没有大括号就认为不存在块级作用域

变量提升

js运行之前先把var 和 function事先声明提到当前作用域的最顶层,并在内存中存储

console.log(a)//undefined
var a=100
//因为 相当于在console前面声明var a并且给a设置undefined
//所以不会报错会显示undefined

console.log(a)//Cannot access 'a' before initialization...
let a=100
//会报错,因为let没有变量提升

暂时性死区(TDZ)

ES6 规定,如果区块中存在 let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。总之,在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”,也就是说使用let声明的变量都是先声明再使用 ,不存在变量提升问题。

let myname= 'sxx'{

    console.log(myname)let myname= 'sdx '}//报错

报错原因:在块作用域内,let声明的变量被提升,但变量只是创建被提升,初始化并没有被提升(初始化就是给变量先赋值成undefined),在初始化之前使用变量,就会形成一个暂时性死区。

【注】

·var的创建和初始化被提升,赋值不会被提升。

·let的创建被提升,初始化和赋值不会被提升。let 和 const 作用基本一致,但是const 声明的变量不能再次赋值

·function的创建、初始化和赋值均会被提升。

2.为什么let,const有暂时性死区,而var没有?

因为var有预处理机制,也就是变量提升; 声明提前指的是,不管变量被声明在函数什么位置,这些声名都会被提升至函数顶部。 比如 var a = 1; 会把var a; 提升到函数顶部。 赋值在原位置不动。

解构赋值

ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构赋值
项目中 的对象的解构赋值,接口返回数据

//数组的
			let [a,b,c]=[1,2,3]
			console.log(a,b,c) //1,2,3

	(占位)let [a,,c]=[1,2,3]
			console.log(a,c)//1,3
		
(解构整体)let arr=[1,2,3]
			let a=[...arr]
			console.log(a)//[1,2,3]
			//用于数组合并,克隆,伪数组转为真数组
//对象的
		let obj={
			a:1,
			b:2,
		}
		let {a,b}=obj
		console.log(a,b)//1,2
		
(解构整体)let c={...obj}
			console.log(c)//{a: 1, b: 2}
		
(赋值另外变量存储)let {a:d}=obj
					console.log(d)//1
		
(剩余运算)let {a,...demo}=obj
			console.log(demo)//{b:2}
			
(函数可以正常调用)let obj={
			c:function(){
				console.log(11111111)
			}
		}
		let {c}=obj
		c()//1111111	

(数据没有数据设置默认值)let obj={ a:1,b:2,c:3 }
					let {a,b,c,d='默认值'}=obj
					console.log(d)//'默认值'

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(` )标识,使用 ${xxx} 形式引用变量;

let out = `${s}是我最大的榜样!`;

箭头函数()=>{}

箭头函数相当于匿名函数,并且简化了函数定义。箭头函数有两种格式,只包含一个表达式,连{ … }和return都省略掉了。还有一种可以包含多条语句,这时候就不能省略{ … }和return:

let my=(a,b)=>{
	return a+b
}
简写 :var addTen = num => num + 10
  • 更加简洁的函数书写方式
  • 本身没有this ,所以call,bind,apply不能改变this指向
  • 上下文决定this指向,外层作用域决定(如果外面有函数this指向外部函数,没有函数指向window)
  • this由声明创造环境决定,而不是使用的时候,在一开始就决定好了,所以用call更改不了
  • 不可以当作构造函数(箭头函数没有自己的this),也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不能使用arguments,可以用rest
  • 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

函数作用域

一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的

var x='text'
function fn(x,y=x){
	console.log(x,y)
}
fn('hello')//hello,hello
fn()//undefined,undefined
var x='text'
function fn(y=x){
	console.log(x,y)
}
fn('hello')//text,hello
fn()//text,text
var x='text'
function fn(x,y=function(){x=2}){
	var x=3
	y()
	console.log(x)//3
}
fn()
console.log(x) //test
//参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错”x 未定义“
var x='text'
function fn(x=x){
	console.log(x)
}
fn()//Cannot access 'x' before initialization
//不能使用arguments,可以用rest
let my=(...values)=>{
	console.log(values)//[1,2,3,4]
}
my(1,2,3,4)
//箭头函数的自执行函数
(() => {
    console.log(1)
})()

this指向

function my(){
	console.log(this)//window
	setTimeout(()=>{
		console.log(this)//window
	},0)
}
my()
var obj={
	b:()=>{
		console.log(this)//window		
	}
}
obj.b()
function A() {
  this.foo = 1
}

A.prototype.bar = () => console.log(this.foo)

let a = new A()
a.bar() // undefined

let res = (function pt() {
  return (() => this.x).bind({ x: 'inner' })();
}).call({ x: 'outer' });

console.log(res)  //outer

this指向四种规则

默认 指向window :函数独立调用 fn()

隐式 :对象调用 obj.fn()

显式: call,bind,apply

new绑定: new Fn()创建出来的对象

对象属性

数据属性/访问器属性

数据属性包含value,writable
访问器属性包含get/set

Object.getOwnPropertyDescriptor(obj, prop) 获取对象属性

  • value: 需要设置属性的值(默认为 undefined)
  • writable: 该属性是否为可修改的(默认为 false)
  • enumerable: 该属性是否可枚举(默认为false)
  • configurable:目标属性是否可以被删除或是否可以再次修改特性
  • set(): 该属性修改时会调用此函数(默认为undefined)
  • get(): 该属性获取时 会调用此函数(默认为undefined)
对于enumerable为true的属性,是可枚举属性
若某个属性的enumerable为false,下面几种操作会忽略该属性
(1for...in循环:只遍历对象自身的和继承的可枚举的属性
(2)Object.keys():返回对象自身的所有可枚举的属性的键名
(3JSON.stringify():只串行化对象自身的可枚举的属性
(4)Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性
说明:对象的toString和数组的length属性的enumerable都是false
当使用了getter或setter方法,不允许使用writable和value这两个属性

在这里插入图片描述

在这里插入图片描述

Object.defineProperty(obj, prop, descriptor)定义对象属性

		obj:被操作的对象
       prop:属性名称, 指定对象要修改或者新增的属性名
       descriptor:对属性的描述(是一个对象)

get/set的使用

get/set的使用

//对象实现
	var obj={
		name:1,
		get _name(){
			return this.name
		},
		set _name(val){
			this.name=val*10
		}
	}
obj._name=2 
console.log(obj)//name:20
//class
class Demo{
    constructor(){
        this._name = '';
    }
    
    get name(){
        return this._name;
    }
    
    set name(val){
        this._name = val;
    }
}

const demo = new Demo();
demo.name = 'yivi';
console.log(demo.name);		// 'yivi'

//基于Object.defineProperty的实现
var obj={a:1}
Object.defineProperty(obj,'b',{
	get(){
		return this.a
	},
	set(val){
		this.a=val
	}
})
obj.b=234
console.log(obj)//234
//proxy
let p = {
  a: 'a'
};

let handler = {
  set(target, key, value, receiver) {
    console.log('set');
    Reflect.set(target, key, value, receiver)
  },
  defineProperty(target, key, attribute) {
    console.log('defineProperty');
    Reflect.defineProperty(target, key, attribute);
  }
};

let obj = new Proxy(p, handler);
obj.a = 'A';
// set
// defineProperty

Promise

我们知道 js 执行的时候,一次只能执行一个任务,它会阻塞其他任务。由于这个缺陷导致 js 的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以使用回调函数执行。
对于 ajax 网络请求就没有这么简单了,可能有多个网络请求是关联的,先执行某个请求返回结果后,第一个返回结果作为第二个请求的参数,调用第二个网络请求。如此,如果业务复杂,网络请求太多时,回调也很多,容易出现回调地狱。所以 Promise 出现了,专门解决异步回调地狱问题。
Promise是JS异步编程中的重要概念,promise是一个构造函数,于是你可以new, 异步抽象处理对象,解决异步回调地狱问题

Promise的三种状态:

pending:对象初始化状态
fulfilled:当调用resolve(成功),会由pending => fulfilled
rejected:当调用reject(失败),会由pending => rejected

创建Promise

const promise = new Promise((resolve, reject) => {
//resolve成功,reject失败
   resolve('fulfilled'); // 状态由 pending => fulfilled
    //reject('rejected'); // 状态由 pending => rejected
});

//then 在Promise 状态发生改变时触发
promise.then(result => { console.log(result); }, // onFulfilled  resolve被调用会进入
    reason => {} // onRejected ,reject被调用会进入
).catch(error=>{
	//抛出错误
})
//then 有两个参数,第一个接收成功的返回数据,第二个接收错误的
//catch(),获取异常信息,具体用法与上面代码中then()方法一致。

Promise 链式调用

//简化1
const ppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
  },1000)
 }).then(res=>{
  console.log('res1',res)
  return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res',res)
 return new Promise(resolve=>resolve(res+'a'))
}).then(res=>{
 console.log('res3',res)
})

//简化2
const pppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  resolve('a')
 },1000)
}).then(res=>{
 return  res+'a'
}).then(res=>{
 return res+'a'
}).then(res=>{
 console.log('res3',res)
})

失败状态catch简写


 
//简写1
const pppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  return new Promise((resolve,reject)=>reject(err+'a'))
 }).catch(err=>{
  console.log('err',err)
 })
 
//简写2
const ppppppp = new Promise((resolve,reject)=>{
 setTimeout(()=>{
  reject('a')
  },1000)
 }).catch(err=>{
  throw err+'a'
 }).catch(err=>{
  console.log('err',err)
})

注意:失败简写省略掉Promise时,使用的 throw 抛出异常。

throw

throw的存在就是为了创建异常,可以看做是一种打断当前代码块执行的操作,一般配合Error使用。

throw '123';
throw new Error('123);

以上两种都会打断当前代码块的执行,都可以作为抛出错误的方式
并且由于js的单线程机制,如果外部没有catch接收错误时,会阻止当前线程导致项目崩溃。所以我们应该慎用throw,或者当我们使用throw时,应该明确的用catch去处理自己的错误。

Promise的方法

Promise.all 方法

将多个promise实例包装成一个新的promise实例,同时多个异步执行,成功时返回一个结束数组,失败返回最先被reject失败状态的值

let p1=new Promise((resolve,reject)=>{
resolve('成功1')
})
let p2=new Promise((resolve,reject)=>{
resolve('成功2')
})
Promise.all([p1,p2]).then(res=>{
	console.log(res)
}).catch(erro=>{
	console.log(error)
})

Promise.race

用法与 all 一样,只是返回结果上不同,它返回的是执行最快的那个 Promise 的结果

Promise.race([
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },100)
  ),
 new Promise(resolve=>
  setTimeout(()=>{
   resolve('a')
   },200)
  ),
 ]).then(res=>{
  console.log('race',res) // 返回 a
})

Promise.finally

在Promise结束时,无论结果是什么都会执行的回调函数,不接受参数

var promise = new Promise(function(resolve, reject) { 
        resolve('huangbiao');
  }).then(function(){
    console.log('success');
  }).catch(function(){
    console.log('catch');
  }).finally(function(){
    console.log('finally');
  });

Promise ajax封装

function sendAjax(url) {
                return new Promise((resolve, reject) => {

                    const xhr = new XMLHttpRequest();
                    xhr.responseType = 'json';
                    xhr.open("GET", "https://api.apiopen.top/getJoke");
                    xhr.send();
                    xhr.onreadystatechange = function() {
                        if (xhr.readyState === 4) {
                            if (xhr.status >= 200 && xhr.status < 300) {
                                resolve(xhr.response);
                            } else {
                                reject(xhr.status);
                            }
                        }
                    }
                })
            }
  sendAjax().then(value => {
                    console.log(value);
               }, reason => {
                    console.warn(reason);
                })

async,await 语法糖支持异步

async注明这个方法是异步方法,方法返回值会被包装成promise对象。

await 只能在async标注的方法里面使用,用于同步等待异步方法返回,如果抛出异常需要用try catch接收

async function a(){
		
	return  new Promise((resolve,reject)=>{
		setTimeout(function(){//3秒之后出现222
			console.log(222)
			resolve('222')
		},3000)
	 	
	 })
	}
	
	async function b(){
		console.log(111)
		var A=await a()
		
		console.log(333)
	}
b()//111,222,333

try catch

Js的异常捕获机制,凡是在try语句块中的代码出错了,都会被catch捕获,只要有一个抛出了异常,就不会继续执行,它只会捕捉代码异常,例如变量不存在,语法错误等。

try {
	throw new Error('1')
} catch(error) {
	console.log(error)
}

因为 js 异常被捕获后,js 是能够正常往下执行的,如果没有被捕获的话,那么 js 将抛出异常,js 执行将会停止!

try-catch----只能处理同步异常【同步和异步不是一个线程,所以同步无法捕捉异步的异常】
Promise-catch----专门为异步提供的异常处理

try{
    //通常来讲,这里的代码会从头到尾而不会产生任何问题
    //但有时会抛出一个异常,要么是由throw语句直接抛出,要么通过调用一个方法间接抛出
}catch(e){
    //当且仅当try语句块抛出了异常,才会执行这里的代码
    //这里可以通过局部变量e来获得对Error对象或者抛出的其他值的引用
    //这里的代码块可以基于某种原因处理这个异常,也可以忽略这个异常,还可以通过throw语句重新抛出异常
}finally{
    //不管try语句是否抛出了异常,finally里的逻辑总是会执行,终止try语句块的方式有:
    //1、正常终止,执行完语句块的最后一条语句
    //2、通过break、continue或return语句终止
    //3、抛出一个异常,异常被catch从句捕获
    //4、抛出一个异常,异常未被捕获,继续向上传播
}

在try中出现异常时会退出try代码块的执行,也就是说出现异常的代码之后的代码不会再执行。(猜测是try出现异常之后调用了throw功能,因为throw是一种阻断线程的机制)当我们try中的异常被catch捕获之后便不会阻塞线程。

finally是不受try与catch影响的存在,不论try中是否有异常,finally总是会执行。即使在try中直接return也会调用finally,

reject,then,catch区别

  • reject用于抛出异常,catch用于处理异常
  • then,catch 是promise实例的方法,reject是promise的方法
  • 网络错误直接catch,不进入then
  • then 的第二个错误依赖于上一个promise抛出的错误
  • reject后的东西一定进入then的第二个参数,如果没有第二个参数,就进入catch
  • 如果then 的第一个参数发生异常,第二个参数捕获不到,catch可以

模块化

模块化,是将大的一个程序文件,拆分成许多小的文件再组合
防止命名冲突,代码复用,高维护性

模块化编程的优点
(1)易设计:较大的复杂问题分解为若干较小的简单问题,使我们可以从抽象的模块功能角度而非具体的实现角度去理解软件系统,从而整个系统的结构非常清晰、容易 理解,设计人员在设计之初可以更加关注系统的顶层逻辑而非底层细节。
(2)易实现:模块化设计适合团队开发,因为每个团队成员不需要了解系统全貌,只需关注所分配的小任务。
(3)易测试:每个模块不但可以独立开发,也可以独立测试,最后组装时再进行联合测试
(4)易维护:如果需要修改系统或者扩展系统功能,只需针对特定模块进行修改或者添加新模块。
(5)可重用:很多模块的代码都可以不加修改地用于其他程序的开发。

CommonJS 和 AMD、CMD

CommonJS(同步加载)

CommonJS用同步的方式加载模块。在服务端,模块文件都存放在本地磁盘,读取非常快,所以这样做不会有问题。但是在浏览器端,限于网络原因,更合理的方案是使用异步加载。
Node.js是commonJS规范的主要实践者
定义模块:module.exports 加载模块:require()

function split(str){
  if(!str){return}
  return str.split('/')
}
  module.exports={split:split}
let strs=require('./module1')

在这里插入图片描述
在这里插入图片描述

AMD/CMD(异步加载)

  • AMD/CMD/CommonJs 是js模块化开发的规范,对应的实现是require.js/sea.js/Node.js
  • CommonJs 主要针对服务端,AMD/CMD/ES Module主要针对浏览器端
  • AMD/CMD区别, AMD是预加载,在并行加载js文件同时,还会解析执行该模块(因为还需要执行,所以在加载某个模块前,这个模块的依赖模块需要先加载完成);而CMD是懒加载,虽然会一开始就并行加载js文件,但是不会执行,而是在需要的时候才执行。
  • AMD优点:加载快速,尤其遇到多个大文件,因为并行解析,所以同一时间可以解析多个文件。
  • CMD优点:因为只有在使用的时候才会解析执行js文件,因此,每个JS文件的执行顺序在代码中是有体现的,是可控的。
  • CommonJS 和 ES Module 区别:CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
  • 如何使用?CommonJs 的话,因为 NodeJS 就是它的实现,所以使用 node 就行,也不用引入其他包。AMD则是通过

es6模块化

(vscode使用live server 打开)
export命令用于规定模块的对外接口
import命令用于加载其他模块

使用< script >标签,但是要加入type="module"属性

<script type="module" src='1.js'>  </script> 

浏览器对于带有type="module"的< script >,都是异步加载,不会造成堵塞浏览器,即等到整个页面渲染完,再执行模块脚本。

分类暴露

//1.js
export let a=10;
export function my(){
    console.log(a)
}

<script type="module">
    import * as m1 from './1.js'
    console.log(m1.my())
</script>

统一暴露

let a=10;
function my(){
    console.log(a)
}
export {a,my}
<script type="module">
    import {a as name,my} from './1.js'//解构赋值,加别名
    console.log(my())
</script>

默认暴露

export default{
    a:10,
    my:function(){
        console.log(a)
    }
}
<script type="module">
    import m1 from './1.js' //简便写法,只针对默认暴露
    console.log(m1)//{a: 10, my: ƒ}
</script>

面向对象class

什么是面向对象(OOP):不需要知道原理就可以使用

三大特点:

  • 继承:代码复用,从父继承方法属性

  • 封装:保护内部代码,使用api调用

  • 多态:不同对象作用同一操作产生不同效果(扫地机器,平常扫地,热了当电风扇)

面向对象思维:抽取对象公共属性,封装成类,对类实例化获取类的对象
编程:面向过程,面向对象

	(打开冰箱)                  (冰箱对象)
          |							  |
	 (放进冰箱)			      (大象对象)
 		  |							  |
	 (关冰箱)                    (结合)

class 类

类 : 抽出对象的公共部分,泛指一大类
对象:特指一个,通过类实例化的具体对象
class类,通过class定义语法糖,让对象原型更清楚

let Demo=class{
	constructor(a){  //constructor里面的this指向实例对象
	this.a=a
	}
	call(){
		console.log('电话:'+this.a)//方法里面的this,谁调用了,就指向谁(onePhone)
	}
}
let onePhone=new Demo('123')
onePhone.call()//电话:123
//严格模式中,this指向undefined
//构造函数
function Phone(name,number){
	this.name=name
	this.number=number
}
Phone.prototype.call=function(){
	console.log('电话:'+this.number)
}
var newPhone=new Phone('张三','123456')
newPhone.call()

class继承

class 继承使用 extends + super

super 可以访问和继承父的函数,子类必须在constructor方法中调用super方法,否则新建实例时会报错并且super()必须放在当前类的构造函数最上面,否则会报错
super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B的实例
super.say()//调用函数
super作为对象时,在静态方法中,指向父类
在这里插入图片描述

//构造函数继承
function Phone(name,number){
	this.name=name
	this.number=number
}
Phone.prototype.call=function(){
	console.log('电话:'+this.number)
}
function SmallPhone(name,number,size,color){
	Phone.call(this,name,number)
	this.color=color
	this.size=size
}

var newPhone=new Phone('张三','123456')
SmallPhone.prototype=newPhone 

var newSmallPhone= new SmallPhone('李四','08765','big','red')

在这里插入图片描述

//es6 class继承
	let Phone=class{
			constructor(name){  
				this.name=name
			}
			call(){
				console.log('电话'+this.name)
			}
		}
	class SmallPhone extends Phone{//继承phone
		constructor(name,number){
			super(name)             //phone 的name属性
			super.call()            //电话小米
			this.number=number
		}
	}
let onePhone=new SmallPhone('小米','123456678')
onePhone.call()
console.log(onePhone)

在这里插入图片描述

class 静态方法

静态属性是类上的不是实例上的,不会被实例继承
如果有this 是类的不是实例的

	class Phone{
			static name='小米'
			static call(){console.log('手机'+this.name)}
		}
	
let newPhone = new Phone()
Phone.call()//手机小米
newPhone.call()//newPhone.call is not a function...

Symbol 数据类型

es6 ,新增的数据类型,用于声明唯一的对象属性名,是原始值,不用new 声明,
不能使用for of 遍历(因为么有Symbol.iterator)
使用Object.getOwnPropertySymbols(obj) 返回对象的所以symbol属性

let lev=Symbol('lev')
let obj={
			name:'Tom',
			age:20,
			[lev]:'优秀',
			[Symbol('lev2')]:'良'
		}

Map,Set 数据结构

Map,Set 数据结构1

Map,Set 数据结构2

在开发过程中涉及到的数据结构,优先考虑Map,如果要求数据的唯一性考虑Set,尽量少使用数组和对象

Map

Map 是以 [key ,value] 的形式存储元素。(键值对)
Map是一组键值对的结构,用于解决以往不能用对象做为键的问题,具有极快的查找速度。
Map 只接收每个成员都是一个双元素的数组,例如:new Map([[‘key1’, value1],[‘key2’, value2]]) 。

const map = new Map([
      ['a', 111],
      ['b', 222]
  ]);

Map属性和方法

  • newMap.size属性返回 Map 结构的成员(一个键值对算一个)总数。
  • newMap.set()方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
  • newMap.get() 方法读取key对应的键值,如果找不到key,返回undefined。
  • newMap.has() 方法返回一个布尔值,表示某个key是否在当前 Map 对象之中。
  • newMap.delete 方法删除某个键,返回true。如果删除失败,返回false。

map转数组

1.扩展运算符(…)

const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

应用

//根据同学的名字查找对应的成绩
const map = new Map([
      ["小明", 98],
      ["小何", 69]
      ["小红", 78]
   ]);
// get是读取属性值
console.log(map.get("小红")); // 78

Set

Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
Set 是以 [value ,value] 的形式存储元素。
Set 接收的参数是一个数组,例如: new Set([value,value]);
set 会自动去掉重复的 3和‘3’是不一样的

let arr = ([1, 3, 4, 3, '4']);
const setObj = new Set(arr);  // set中添加一个数组
console.log(set); // 1,3,4,'4'

set 属性和方法

  • newSet .add(value):添加某个值,返回 Set 结构本身。
  • newSet .delete(value):删除某个值,返回一个布尔值,表示删除是否成功。 setObj
  • newSet . has(value):返回一个布尔值,表示该值是否为Set的成员。
  • newSet .clear():清除所有成员,没有返回值。

set转为数组

1.Array.from方法可以将 Set 结构转为数组。
2.扩展运算符(…)

应用

//搜索框历史,不重复
//去除字符串重复
[...new Set('ababbc')].join('')
// "abc"

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}

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

//处理数据
let set = new Set([1, 2, 3]);
set = new Set([...set].map(x => x * 2));//2,4,6

map和 set 的遍历

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历 Map 的所有成员。
//keys()
for (let key of map.keys()) {
   console.log(key); // name,age  
}
//forEach
// 第一种写法
// map.forEach(function(key, value, map) {
    // console.log(key, value); // 111 "a" 和 222 "b" 
 // })
 
// 第二种写法,对象方式传入
let obj = {
    a: 1
};
map.forEach(function(key, value, map) {
    console.log(key, value, this.a);
}, obj) // 这里的obj就相当于作用域,this的指向

转换数组-map-set

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Proxy 代理

1、Vue3双向数据绑定的原理
2、真正私有变量
3、实现校验器

可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

let proxy = new Proxy(target, handler);
		 target:要拦截的目标对象(要代理的对象)
         handler:是一个对象用来定制拦截的行为(筛选、过滤的规则)

实例的方法

1.get(target,key,receiver)

     作用:拦截某个属性的读取操作
     参数说明:target:目标对象
           	   key:目标对象的属性名
                    receiver:指向原始的读操作所在的那个对象,一般情况下  就是 Proxy 实例
var obj={a:1}
	var objN=new Proxy(obj,{
		get(target,key){			
			        // '获取到'+target[key] //获取到1 		
			return 	 Reflect.get(target,key)
			}	
	})
	console.log(objN.a)

如果一个属性不可配置(configurable)且不可写(writable),则 Proxy 不能修改该属性,否则通过 Proxy 对象访问该属性会报错。
在这里插入图片描述

2.set(target,key,value,receiver)

作用:拦截某个属性的赋值操作
参数说明:依次为目标对象、属性名、属性值和原始的操作行为所在的那个对象,一般情况下是proxy实例本身,其中最后一个参数可选。
例如:要求只能修改对象的name属性,其他属性是不可以进行修改的。 
	var obj={a:1}
	var objN=new Proxy(obj,{
		set(target,key,value){
			console.log('修改值')
			return  Reflect.set(target,key,value)
		}
	})
	objN.a=100
	console.log(objN.a)

如果目标对象自身的某个属性不可写,那么set方法将不起作用

3.has(target,key)

       作用:拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。
       			(典型的就是可以对in运算符遍历的属性做拦截)
       参数介绍:目标对象、需查询的属性名
例如:要求:利用in操作符查找属性的时候只暴露name属性,其他的不暴露出去即找不到

has方法针对in操作符查找属性,如果直接通过点.或者中括号访问属性不可以拦截

		
	var obj={_a:1}
	var objN=new Proxy(obj,{
		has(target,key){		
			if(/^_/.test(key)){
				return console.log(Reflect.has(target,key))//只能获取以下划线开始的 true
			}
		}
	})
	'_a' in objN

4. deleteProperty(target,key)

      作用:用于拦截delete操作,如果这个方法抛出错误或者返回false,当前属性就无法被delete命令删除。
      参数说明:目标对象和属性名
var obj={_a:1}
	var objN=new Proxy(obj,{
		deleteProperty(target,key){console.log(111111)
			return 
		}
	})
	delete obj._a

5.ownKeys(target)

     作用:用来拦截对象自身属性的读取操作(具体来说拦截Object.keys()、for...in循环)
     参数说明:目标对象

在这里插入图片描述

6. apply(target, ctx, args)

       作用:拦截函数的调用、call和apply操作
       参数介绍:目标对象、目标对象的上下文对象(this)和目标对象的参数数组

在这里插入图片描述

7.construct(target, args, newTarget)

      作用:用于拦截new命令。
      参数说明:目标对象、构造函数的参数数组、创造实例对象时new命令作用的构造函数

在这里插入图片描述
construct()方法返回的必须是一个对象,否则会报错
在这里插入图片描述

construct()拦截的是构造函数,所以它的目标对象必须是函数,否则就会报错
在这里插入图片描述
construct()方法中的this指向的是handler,而不是实例对象

	var py2=new Proxy(function(x,y){
		return x+y
	},{
		construct:function(target,args){
			return {value:args}    //{value:[1,2]}
		}
	})
	console.log(new py2(1,2))
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值