ES5和ES6笔记
JS对象
JSON.stringify(obj/arr) //js对象或数组转换为json对象或数组 JSON.parse(json) //json对象或数组转换为js对象或数组 var obj = {name: 'Tom'} obj = JSON.stringify(obj) console.log(obj); //{"name":"Tom"} String obj = JSON.parse(obj) console.log(obj); //{ name: 'Tom' } Object
JS数组
Array.prototype.indexOf(value) //得到值在数组中的第一个索引 Array.prototype.LastIndexOf(value) //得到值在数组中的最后一个索引 Array.prototype.forEach(function(item,index){}) //遍历数组 Array.prototype.map(function(item,index){ return item+1 }) //遍历数组返回一个新的数组,返回加工之后的值 //item每个+1 Array.prototype.filter(function(item,index){}) //遍历过滤出一个新的子数组,返回条件为true的值
JS函数
区别bind()与call()和aplly()?
- 都能指定函数中的this
- call和apply是立即调用函数
- bind是将函数返回
- 传入参数的形式
Function.prototype.bind(obj) //将函数内的this绑定为obj,并将函数返回 foo.call(obj,33,44) foo.apply(obj,[33,44]) foo.bind(obj,33,44)() //得到返回的函数,需要再后面加括号才能立即调用 //bind传参方式和call一样 setTimeout(function(){ console.log(this) }.bind(obj),1000) //这里的this指向obj
let关键字
特点: 在块级作用域内有效 不能重复声明 不会预处理,不存在提升
应用: 循环遍历加监听
console.log(i) //报错 let i = 1 let i = 1 //报错
const关键字
作用:定义一个常量
特点: 不能修改 其他特点同let
应用: 保存不用改变的数据
变量的解构 赋值
从对象或数组中提取数据,并赋值给变量(多个)
let obj = {name:'Tom' , age:12} let {name , age} = obj //等于赋obj.name和obj.age中的值 let arr = [1,3,5,'abc',true] let [a,b,c,d,e] = arr //根据下标来给值 let[,,a,b] = arr //a==5,b=='abc function foo({name,age}){ // let {name,age} = obj console,log(name , age) } foo(obj)
模板字符串
简化字符串的拼接 模板字符串必须用到``包含 变化的部分用${xxx}定义
let obj ={name:'Tom' ,age:12} let str = `我的名字叫:${obj.name},我的年龄是:${obj.age}`
简化的对象写法
省略同名的属性值 省略同名的function
let name = 'Tom' let age =39 let obj = { name:name, age:age, getName: function(){ return this.name } } //在es6中 let obj = { //同名的属性可以省略不写 name, age, getName(){ //可以省略函数的:function return this.name } }
箭头函数详解
作用:定义匿名函数
基本语法: 没有参数:()=> console.log('xxxx) 一个参数:i=>i+2 大于一个参数:(i,j)=> i+j 函数体不用大括号:默认返回结果 函数体如果有多个语句,需要用{}包围,若有需要返回的值,需要手动返回
使用场景:多用于定义回调函数
箭头函数的特点:
1.简洁
2.箭头函数没有自己的this,箭头函数的this不是调用时候决定的,而是在定义的时候处在的对象就是他的this
3.扩展理解:箭头函数的this看外层是否有函数,如果有,外层函数的this就是内部箭头函数的this,如果没有则this是window
let fun = ()=> console.log('xxx') fun() //xxx let fun = (i,j)=> console.log(i+j) fun(1,2) //3 let fun = (x,y) => { x+y //undefined return x+y //3 //只有一条语句时通常把{}省略,会自动返回执行结果 } fun(1,2) btn1.onclick = () =>{ alert(this) //点击btn1之后发现this指向window } let obh = { name:'Tom' getName(){ btn1.onclick = () =>{ alert(this) } } } obj.getName() //点击btn1之后发现this指向obj
点点点运算符
用途:
1.rest(可变)参数,用来取代arguments,但比arguments灵活,只能是最后部分形参参数,后面不能跟其他形参
2.扩展运算符
何为arguments
funciton foo(a,b){ console.log(arguments) arguments.callee() //指向函数本身 arguments.forEach(function(item,index){ console.log(item,index) //报错 }) } foo(1,2) //arguments是个伪数组 funciton foo(...value){ //通过三点运算符收集的实参形成数组赋给value console.log(arguments) console.log(value) //真数组,取代了arguments value.forEach(function(item,index){ console.log(item,index) // 1,0 }) } foo(1) funciton foo(a,...value){ //通过三点运算符收集的实参形成数组赋给value console.log(arguments) console.log(value) //真数组,取代了arguments,[2] value.forEach(function(item,index){ console.log(item,index) // 2,0 }) } foo(1,2) //第一个1给了形参a let arr = [1,6] let arr1 = [2,3,4,5] //console.log(...arr1) 相当于把arr1数组遍历把每个值拿出来变成2,3,4,5 arr = [1, ...arr1,6] //[1,2,3,4,5,6]
形参默认值
function Fun(x=0,y=0){ this.x=x this.y=y } let fun = new Fun(1,2) fun.x //1 fun.y //2 let fun1 = new Fun() fun.x //0 fun.y //0
Promise对象
理解:
1.Promise对象:代表了未来某个将要发生的事件(通常是一个异步操作)
2.有了Promise对象,可以将异步操作以同步的流程表达出来,避免了层层嵌套的回调函数(回调地狱:回调函数多的时候有很多嵌套,中间某个环节出了问题,不好解决,因为回调函数无法控制。还有一种回调函数之间的耦合度比较高,互相有依赖关系,导致不可预期的错误发生)
3.ES6的Promise是一个构造函数,用来生成promise实例
使用promise的基本步骤(2步)
//创建promise对象 let promise = new Promise((resolve,reject)=>{ //初始化promise状态为pending //执行异步操作,通常是发送ajax请求,开启定时器 console.log(111) setTimeout(()=>{ console.log(333) //根据异步任务的返回结果来去修改promise状态 //异步任务执行成功 resolve('hh成功了') //自动修改promise的状态为fullfilled 成功状态 //异步任务执行失败 reject('失败了~') //修改promise的状态为rejected 失败状态 },2000) }) console(222) // 111 222 333 //调用promise的then() promise.then((data)=>{ //成功的回调,当状态还为初始化时,不会调用,状态变为成功时调用 console.log(data) //hh成功了 } , (error)=>{ //失败的回调,状态变为失败时调用 console.log(error) //失败了~ })
promise对象的3个状态 1.pending:初始化状态 2.fullfilled:成功状态 3.rejected:失败状态
应用: 使用promise实现超时处理
使用promise封装处理ajax请求
symbol
概念:ES6中添加了一种原始数据类型symbol
特点:
1.symbol属性对应的值是唯一的,解决命名冲突问题
2.symbol值不能与其他数据进行计算,包括同字符串拼串
3.for in,for of遍历时不会遍历symbol属性
使用:
//调用symbol函数得到symbol值 let symbol = Symbol() //不像构造函数要去new console.log(symbol) //Symbol() let obj ={name:'Tom',age:12} //obj.sex = '男' //obj.symbol = 'hello' 只是给obj添加了一个叫symbol的属性 obj[symbol] = 'hello' //obj多了symbol():'hello' //for in , for of不能遍历symbol属性 for(let i in obj){ console.log(i) //没有symbol } //可以去定义常量 const Person_key = Symbol('person_key') console.log(Person_key) //Symbol(person_key) //传参标识 let symbol2 = Symbol('one') let symbol3 = Symbol('two') console.log(symbol2 == symbol3) //false console.log(symbol2,symbol3) //Symbol(one) Symbol(two)
内置symbol值 ES6提供了11个内置的Symbol值,指向语言内部的使用方法 Symbol.iterator属性指向该对象的默认遍历器方法
iterator遍历器
概念:iterator是一种借口机制,为各种不同的数据结构提供统一的访问机制
作用
1.为各种数据结构提供一个统一的,简便的访问接口
2.使得数据结构的成员能够按某种次序排列
3.ES6创造了一种新的遍历命令for of循环,iterator接口主要供for of消费
工作原理:
1.创建一个指针对象(遍历器对象),指向数据结构的起始位置
2.第一次调用next方法,指针自动指向数据结构的第一个成员
3.接下来不断调用next方法,指针会一直往后移动,直到指向最后一个成员
4.每调用next方法返回的是一个包含value和done的对象,{value:当前成员的值 , done:布尔值} *value表示当前成员的值,done对应的布尔值表示当前的数据结构是否遍历结束 *当遍历结束的时候value返回undefined,done返回true
原生具备iterator接口的数据(可用for of遍历)
扩展理解: 1.当数据结构上部署了Symbol.iterator接口,该数据就是可以用for of遍历 2.当使用for of去遍历目标数据时,该数据会自动寻找Symbol.iterator属性
//模拟指针对象(遍历器对象) function myIterator(arr){ //iterator接口 let nextIndex = 0 //记录指针位置 return { //遍历器对象 next: function(){ return nextIndex < arr.length?{value:arr[nextIndex++],done:false}:{value:undefined,done:true} } } } let arr = [4,1,65,'abc'] let iteratorObj = myIterator(arr) console.log(iteratorObj.next()) //4 console.log(iteratorObj.next()) //1 console.log(iteratorObj.next()) //65 console.log(iteratorObj.next()) //'abc' console.log(iteratorObj.next()) //undefined true //将iterator接口部署到指定的数据类型上,可以使用for of去循环遍历 //数组,字符串,arguments,set容器,map容器 //对象没有iterator接口 for(let i of arr){ console.log(i) //4,1,65,'abc' } let str = 'abcdefg' for(let i of str){ console.log(i) //a,b,c,d,e,g } function fun(){ for(let i of arguments){ console.iog(i) } } fun(1,4,5,'abc') //1,4,5,'abc' let targetData = { //等同于在指定的数据内结构上部署了iterator接口 //当使用for of去遍历某一个数据结构时,首先去找Symbol.iterator,找到了就去遍历,没有就报错 [Symbol.iterator]:function(){ let nextIndex = 0 //记录指针位置 return { //遍历器对象 next: function(){ return nextIndex < this.length?{value:this[nextIndex++],done:false}:{value:undefined,done:true} } } } } //使用三点运算符,解构赋值,默认调用iterator接口 let arr2 = [1,6] let arr3 = [2,3,4,5] arr2 = [1,...arr3,6] let [a,b] = arr2 console.log(a,b) //1,2
Genrator函数
概念:
1.ES6提供的解决异步编程方案之一
2.Genrator函数是一个状态机,内部封装了不同状态的数据
3.用来生成遍历器对象 4.可暂停函数(惰性求值),yield可暂停,next方法可启动。每次返回的是yield后的表达式结果
特点: 1.function与函数名之间有个*号
2.内部用yield表达式来定义不同的状态
3.generator函数返回的是指针对象,而不会执行函数的内部逻辑
4.调用next方法函数内部逻辑开始执行,遇到yield表达式停止,返回{value: field后的表达式结果,done:布尔值}
5.再次调用next方法会从上一次停止时的yield处开始,直到最后 6.yield语句返回结果通常为undefined,当调用next方法时,传参内容会作为启动时yield语句的返回值
function* generatorExample(){ console.log(1) let result = yield 'hello' //状态值为hello console.log(result) //aaaaaaa 不传的话为undefined console.log(2) yield 'generator' //状态值为generator return '3' } let MG = generatorExample() //MG.next() //1 没有2第一次在'hello'暂停了 console.log(MG.next()) //{value: 'hello',done:false} console.log(MG.next('aaaaaaa')) //2 {value:'generator',done:false} console.log(MG.next()) //{value:3,done:true} //对象的symbol.iterator属性 指向遍历器对象 let obj ={name:'Tom',age:39} for(let i of obj){ console.log(i) //报错 } obj[symbol.iterator] = function* myTest(){ //返回一个遍历器对象,相当于给对象认为部署了一个iterator接口 yield 1 yield 2 yield 3 } for(let i of obj){ console.log(i) //1 2 3 }
async函数
概念: 真正意义上去解决异步回调的问题,同步流程表达异步操作
本质:Generator的语法糖
语法: async function foo(){ await 异步操作; await 异步操作; }
特点: 1.不需要像Generator去调用next方法,遇到await等待,当前的异步操作完成就往下执行
2.返回的总是Promise对象,可以用then方法进行下一步操作
3.async取代Generator函数的星号*,await取代yield
4.语意上更为明确,使用简单,暂时没有任何副作用
function foo(){ return new Promise(resolve => { setTimeout(resolve,2000) }) } async function test(){ console('开始执行',new Date().toTimeString()) await foo() console('执行结束',new Date().toTimeString()) } text() //开始执行 隔了两秒 执行结束 //async里的await返回值 function fun1(){ return 1 } async function fun(){ let result = await fun1() console.log(result) } fun() //1 async function fun(){ let result = await Promise.resolve('aaa') //直接把Promise对象改为成功状态 console.log(result) //aaa result = await Promise.reject('bbb') console.log(result) //报错 } fun()
class类使用
1.通过class定义类,实现类的继承
2.在类中通过constructor定义构造方法
3.通过new来创建类的实例
4.通过extends来实现类的继承
5.通过super调用父类构造方法
6.重写从父类继承的一般方法
function Person(name,age){ this.name = name this.age = age } let person = new Person('Tom',12) //定义一个人物的类 class Person { //类的构造方法 constructor(name , age){ this.name = name this.age = age } //类的一般方法 showName(){ console.log(this.name) } //放在实例对象的隐式原型上 } let person = new Person('Tom',12) person.showName() //Tom class StarPerson extends Person{ constructor(name,age,salary){ super(name,age)//调用父类的构造方法 this.salary = salary } showName(){ //父类的方法重写 console.log(this.name,this.age,this.salary) } } let p1 = new StarPerson('Jack',20,5000) console.log(p1) p1.showName()
字符串扩展
1.includes(str):判断是否包含指定的字符串
2.startsWith(str):判断是否以指定字符串开头
3.endsWith(str):判断是否以指定字符串结尾
4.repeat(count):重复指定次数
let str = 'a' console.log(str.includes('a')) //true console.log(str.startsWith('b')) //false console.log(str.endsWith('a')) //true console.log(str.repeat(5)) //aaaaa
数组方法的扩展
1.Array.from(v):可以将伪数组或可遍历对象转换成真实数组
2.Array.of(v1,v2,v3):将一系列值转换成数组
3.find(function(value,index,arr){return true}):找出第一个满足条件返回true的元素
4.findIndex(function(value,index,arr){return true}):找出第一个满足条件返回true的元素下标
let arr = [2,3,4,3,6] let a = arr.find(function (item,index){ return item>=4 }) console.log(a) //4
对象方法扩展
1.Object.is(v1,v2) 判断两个数据是否完全相等
2.Object.assign(target,source1,source2) 将源对象的属性复制到目标对象上
3.直接操作__proto__属性
console.log(0 == -0) //true console.log(Object.is(0,-0)) //flase console.log(Object.is(NaN,NaN))//true 因为是用字符串的形式来判断 let obj = {} let obj1 = {name:'Tom' , age:12} let obj2 = {name:'Jack' , age:20} let obj3 = {salary:5000} Object.assign(obj,obj1,obj2,obj3) console.log(obj) //{ name: 'Jack', age: 20, salary: 5000 } let obj1={} let obj2 ={money:50000} obj1.__proto__ =obj2 console.log(obj1.money); //obj1.__proto__指向了obj2这个对象,obj1可以通过原型链寻找得到这个对象的属性
深度克隆
let str = 'abcd' let str2 = str str2 = '' console.log(str) //abcd //拷贝数组/对象 没有生成新的数据,而是复制了一份引用 let arr = {1,4,{name:'Tom',age:12}} let arr2 = arr arr2[0] = 'abcd' console.log(arr[0]) //abcd
浅拷贝(对象/数组): 特点:拷贝的是引用,修改拷贝以后的数据会影响原数据,使得原数据不安全
深拷贝(深度克隆): 特点:拷贝的时候生成新数据,修改新数据不会影响原数据
拷贝数据: 基本数据类型:拷贝后生成一份新的数据,修改拷贝以后的数据不会影响原数据
对象数组:拷贝后不会生成新的数据,而是拷贝的是引用。修改拷贝之后的数据会影响原来的数据
拷贝数据的方法:
1.直接赋值给一个变量 浅拷贝
2.Object.assign() 浅拷贝
3.Array.prototype.concat() 浅拷贝
4.Array.prototype.slice(startIndex,endIndex) 截取子数组 浅拷贝
5.ISON.parse(JSON.stringify()) 深拷贝(深度克隆),拷贝的数据里不能有函数,处理不了,因为这两个方法只能传入原生的JS对象或数组,传入函数转过来发现函数变成null
let obj = {name:'Tom'} let obj2 = Object.assign(obj) console.log(obj2) obj2.name = 'Jack' console.log(obj.name) //Jack let arr = [1,2,{name:'Tom'}] let arr2 = arr.concat() arr2[2].name = 'a' console.log(arr[2].name) //a let arr3 = arr.slice() //相当于传整个数组[1,2,{name:'a'}] arr3[2].name = 'b' console.log(arr[2].name) //b let arr = [1,2,{name:'Tom'}] let arr2 = JSON.stringify(arr) //arr2是个JSON数组,是个字符串 arr2 = JSON.parse(arr2) arr2[2].name = 'Jack' console.log(arr[2].name) //Tom
如何实现深度克隆? 拷贝数据里有对象或数组,还要继续遍历对象或者数组拿到里面的每一项的值,一直到拿到的都是基本数据类型,然后再去复制,这就是深度克隆
知识点储备: 如何判断数据类型:arr ---> Array null--->Null
1.typeof返回的数据类型:String Number Boolean Undefined Object Function
2.Object.prototype.toString.call(obj)
let result = 'abcd' resunlt = null result = [1,2,3] console.log(Object.prototype.toString.call(result)) //[Object String] [Object Null] [Object Array] console.log(Object.prototype.toString.call(result).slice(8,-1)) //String Null Array for in 循环对象的到属性名 数组得到下标 function checkType(tarhet){ return Object.prototype.toString.call(target).slice(8,-1) } console.log(checkType(result)) //Array //实现深度克隆 针对对象数组 function clone(target){ //判断拷贝的数据类型 //result是最终克隆的数据 let result,targetType = checkType(target) if(targetType === 'Objcect'){ result = {} } else if(targetType ==='Array'){ result = [] } else{ return target } //遍历目标数据 for(let i in target){ //获取遍历数据结构的每一项值 let value = target[i] //判断目标结构里的每一值是否存在对象/数组 if(checkType(value) ==='Object' || checkType(value) === 'Array'){ //继续遍历取到的value值 result[i] = clone(value) }else{ //获取到的value是基本数据类型或者函数 result[i] =value } } return result } let arr = [1,2,{age:12}] let arr2 = clone(arr) arr2[2] = 'a' console.log(arr , arr2); //[ 1, 2, { age: 12 } ] [ 1, 2, 'a' ]
Set和Map容器
1.Set容器:无序不可重复的多个value的集合体 Set() Set(array) add(value) delete(value) has(value) clear() size()
2.Map容器:无序的key不重复的多个key-value的集合体 Map() Map(array) set(key,value) //添加 get(value) delete(value) has(value) clear() size()
let set = new Set([1,2,3,4,2,1]) console.log(set) //[1,2,3,4] set.add(7) console.log(set.size)//5 set.clear()//清空set let map = new Map([['key','value'],[36,'age']]) map.set(78,'hh') console.log(map) //Map { 'key' => 'value', 36 => 'age', 78 => 'hh' } map.delete(36) console.log(map)//Map { 'key' => 'value' , 78 => 'hh' }
Array.prototype.includes(value) :判断数组中是否包含指定value
let arr = [1,2,3,4,'abc'] console.log(arr.includes('a')) //false