ES6~ES13
定义变量
-
let
-
不能在定义之前访问
-
变量不能重定义
-
块级作用域,包含if语句,switch语句等,不限于函数块
简易选项卡案例改进
·<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> * { margin: 0; padding: 0; } ul { list-style: none; } .header { display: flex; width: 500px; } .header li { flex: 1; height: 50px; line-height: 50px; text-align: center; border: 1px solid black; } .box { position: relative; } .box li { position: absolute; left: 0; top: 0; width: 500px; height: 200px; background-color: yellow; display: none; } /* 给第一个样式先来个激活状态 */ .header .active { background-color: orange; } .box .active { display: block; } </style> </head> <body> <ul class="header"> <li class="active">1</li> <li>2</li> <li>3</li> <li>4</li> </ul> <ul class="box"> <li class="active">111</li> <li>222</li> <li>333</li> <li>444</li> </ul> <script> var headerItems = document.querySelectorAll(".header li") var boxItems = document.querySelectorAll(".box li") //用for循环给每li添加自定义属性标识,并且设置标题的点击事件 //用let定义,每次循环都是新的i for (let i = 0; i < headerItems.length; i++) { /* headerItems[i].dataset.index=i; */ headerItems[i].onclick = handler //点击事件函数 function handler() { //辨识点击哪个标题 var index = i //移除激活类名 for (var m = 0; m < headerItems.length; m++) { headerItems[m].classList.remove("active") boxItems[m].classList.remove("active") } //添加激活状态 headerItems[index].classList.add("active") boxItems[index].classList.add("active") } } </script> </body> </html>
-
-
const:定义后作为常量存在,不能再重新赋值,不能只定义不赋值
应用于网页中一些作为参考的数据
-
let块级作用域案例:最常用的情景
解构赋值
快速从对象和函数中获取里面的成员
-
数组
var arr=["1","2","3"] let[x,y,z]=arr console,log(x,y,z)
-
对象
var obj={ name:"1", age:"2", location:"3" } //因为location变量名已经被window占用,不能重名,可以自己用冒号重命名 let {name,age,location:mylocation}=obj console.log(name) console.log(age) console.log(mylocation)
字符串模板
``${}`:大括号内是一个小型的函数环境,他会被编译
字符串扩展
includes函数
判断字符串中是否存在指定字符
第二个参数是可选的,当写上后查询时不包含此下标
字符串名.includes(“查询字符”,参数) | 参数后是否包含 |
字符串名.startswith(“查询字符”,参数) | 参数后的第一个下标是否是查询字符 |
字符串名.endswith(“查询字符”,参数) | 参数前最后一个下标是否是查询字符 |
repeat函数
将原字符串重复n次返回一个新字符串
字符串名.repeat(整数) | |
字符串名.repeat(小数) | 会自动取整 |
字符串名.repeat(0) | 空字符串 |
数值扩展
可以编译二进制与八进制
isFinite,isNaN方法
-
isNaN() 判断不是数字
-
isFinite() 判断是数字
-
isFinite() 有两个方法 : isFinite() 和 Number.isFinite()
-
Number.isFinite() 与全局的 isFinite() 函数不同
全局的 isFinite() 会先把检测值转换为 Number ,然后在检测。
Number.isFinite() 不会将检测值转换为 Number对象,
如果检测值不是 Number 类型,则返回 false。
-
isInteger方法
Number.isInteger(数)
用来判断一个数值是否为整数。
JavaScript 内部,整数和浮点数采用的是同样的储存方法,所以 25 和 25.0 被视为同一个值。
极小常量Number.EPSILON
是 JavaScript 能够表示的最小精度。误差如果小于这个值,就可以认为已经没有意义了,即不存在误差了。
Math方法扩展
-
Math.trunc
方法用于去除一个数的小数部分,返回整数部分。- 内部使用
Number
方法将其先转为数值。 - 对于空值和无法截取整数的值,返回
NaN
。 - 对于负数取整,他会选取数值较小的那个
- 内部使用
-
Math.sign
方法用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。
它会返回五种值。
- 参数为正数,返回
+1
; - 参数为负数,返回
-1
; - 参数为 0,返回
0
; - 参数为-0,返回
-0
; - 其他值,返回
NaN
。
- 参数为正数,返回
数组扩展
展开运算符…
-
展开拼接
var a=[1,2,3] var b=[4,5,6] 拼接两数组 //conlose.log(a,concat(b)) var c=[...a,...b]
-
展开复制
var a=[1,2,3] //var b=a.slice() //var b=a.concat() var b=[...a] b[0]="ha"
-
参数-实参-形参
- 解决arguments不能用于箭头函数的问题
var test=(...arr)=>{ console.log(arguments) } test(1,2,3,4)
-
a对应1,b对应2,…arr对应[3,4,5]
而且…arr放在最后最后一个参数
var test=function(a,b...arr)=>{ console.log(arr) } test(1,2,3,4,5)
- 找出后端所传数据的最值
var arr=[1,2,3,4,5,6,7,8,9] var res=Math.max(...arr)
- 伪数组转换
function test(){ var arr=[...arguments] console.log(arr) } test(1,2,3,4,5)
Array.from
将伪数组转为真正的数组
// NodeList对象
let ps = document.querySelectorAll('p');
Array.from(ps).map(function () {
});
// arguments对象
function foo() {
var args = Array.from(arguments);
}
Array.of
将一组值,转换为数组。
因为参数个数的不同,会导致Array()的行为有差异。
Array() // []
Array(3) // [, , ,]
Array(3, 11, 8) // [3, 11, 8]
Array.of(3) // [3]
Array.of(3, 11, 8) // [3,11,8]
数组实例的 find() 和 findIndex()
-
find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的
- 成员,则返回undefined。
[1, 4, -5, 10].find((n) => n < 0) // -5 [1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10 //find方法的回调函数可以接受三个参数,依次为当前的值、下标和原数组。
-
findIndex方法,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
[1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2 这两个方法都可以接受第二个参数,用来绑定回调函数的this对象。
-
findLast,findLastIndex:逆序寻找
fill方法
fill方法可以填充一个数组。
fill方法用于空数组的初始化非常方便。数组中已有的元素,会被全部抹去。
['a', 'b', 'c'].fill(7)
// [7, 7, 7]
flat,flatMap方法
数组降维操作
var newArray = arr.flat(参数)
//不传递参数的时候默认为一层
let arr = [1,2,[3,[4,[5]]]]
const reasut = arr.flat()
console.log(reasut)
// [1, 2, 3, [4,[5]]]
//传递参数
const reasut2 = arr.flat(3)
console.log(reasut2)
// [1, 2, 3, 4, 5]
//传入Infinity时,相当于扁平化最深层次的数组
const reasut3 = arr.flat(Infinity)
console.log(reasut3)
// [1, 2, 3, 4, 5]
//当数组里面有空项的时候,会过滤掉空值
const arr2 = [1, , 2, [3]]
const reasut4 = arr2.flat()
console.log(reasut4)
// [1, 2, 3]
对象扩展
属性简写
var obj={getname:getname}
可以写成
var obj={getname
var obj={getName:function(){}}
可以写成
var obj={getName(){}}
属性名表达式
定义对象的属性,有两种方法。
-
直接用标识符作为属性名
-
用表达式作为属性名
将表达式放在方括号之内
let obj = { [a]: 123 } let a=module //obj = { module: 123 }
扩展运算符…
可以将一个对象转为用逗号分隔的参数序列之中。
let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
-
注意:如果扩展运算符后面是一个空对象,则没有任何效果。
如果扩展运算符后面不是对象,则会自动将其转为对象。
如果扩展运算符后面是字符串,它会自动转成一个类似数组的对象。
对象的扩展运算符等同于使用Object.assign()方法。
扩展运算符可以用于合并两个对象。 -
对象的合并
-
…方法
新建一个新的数组,合并的对象如果有相同的键名,那么后面对象对应的属性值会覆盖前面对象对应的属性值 ,属性值是最后一次赋值的值;
语法:
Obj = {...o1,...o2,...o3,...o4}
-
Object.assign
将后面的的数组合并到第一个数组上
语法:
Object.assign(o1,o2,o3)
-
-
对象的复制
语法:
newObj = {...oldObj}
let o1 = { name:"张三", age:18 }; //(1)赋值的是引用,指向的是同一个对象; let o2 = o1; console.log(o2,o2===o1); //{name: "张三", age: 18} true //(2)复制对象,两个是不同的对象: let o3 = {...o1}; console.log(o3,o3===o1); //{name: "张三", age: 18} false
Object.is()
-
双等号==
将执行类型转换,
-
三等号
不进行类型转换(如果类型不同, 只是总会返回 false)
-
Object.is
基本上与三等号相同,但是对于NaN和-0和+0进行特殊处理
Object.is(NaN,NaN)将为
true
,在==
和===
中将是false
,
函数扩展
函数的默认参数
普通函数和箭头函数均适用
//当调用函数时忘记传参,会使用默认值
function test(a=1.b=2){
return a+b
}
剩余参数…
用于获取函数的多余参数,这样就不需要使用arguments对象了。
// arguments 变量的写法
function sortNumbers(){
return Array.prototype.slice.call(arguments).sort();
}
// rest 参数的写法
const sortNumber = (...numbers) => number.sort();
name属性
返回函数的函数名
function foo() {}
foo.name // "foo"
箭头函数
-
语法:
var 变量=(0=>{})
-
只有一个形参的时候可以省略()
-
当大括号内只有一句代码或只有返回值,{}与return可以省略
var newlist =list.map(function(item){ return `<li>${item}</li>` }) //可以转化为 var newlist =list.map(item=>`<li>${item}</li>`)
当{}里面只有一个对象时,不省略{}
-
arguments:没办法用箭头函数
在函数没有形参的情况下,调用函数时传实参给函数,在函数内使用此关键字可以得到所传实参的伪数组。
var test=function(){ console.log(a,b,c) console.log(arguments[0],arguments[1],arguments[2]) //转化为真数组 console.log(Array.from(arguments)) }) test(1,2,3)
-
箭头函数的this指向父级作用域的
//如果直接在计时器内用this,会指向window,所以用that在外面暂存this mytext.oninput=function(){ var that=this setTimeout(()=>{ console.log(that.value) },1000) } //箭头函数可以直接指向外面的父级元素 mytext.oninput=function(){ setTimeout(()=>{ console.log(this.value) }1000) }
-
案例:用户数据修改
<input type="text" id="myusername">
<input type="tel" id="myage">
<button id="btn">修改</button>
<div id="box"></div>
<script>
//后端数据
var obj = {
name: "xiaohong",
age: 100,
location: "guangdong",
id: "2154285424252"
}
//后端数据渲染
function render({name,age,location}) {
box.innerHTML = `name${name},age${age},location:${location}`
}
render(obj)
btn.onclick=function(){
var name=myusername.value
var age=myage.value
var newobj={
...obj,
name,
age
}
//重新渲染
render(newobj)
}
</script>
模块化语法
-
模块化之前的痛点
引用js文件时
- 私密代码依然会被访问
- 会出现变量名重复
- 多个js文件互相引用会出现一定的顺序依赖
-
模块化语法——私密不怕
分两步
-
外部js文件导出:
export{ a,b,c...//你想被别人导入的函数名 }
-
本文件导入:
<script type="module"> import{a,b,c...你想导入的函数名} from `文件路径` </script> 之后便可以直接调用函数
-
-
模块化语法——重名不怕
-
文件导入:
<script type="module"> import{a,重名函数 as 重命名} from `文件路径` </script> 之后便可以直接调用函数-以重命名方式
-
-
模块化语法——依赖不乱
分两步
-
在外部js文件中先引入需要的其他js文件
<import>{...}from`路径` 之后便可以直接调用函数
-
本文件导入时引入顺序可以不按顺序
-
Symbol
Symbol是ES6中引入的一种新的基本数据类型,用于表示一个独一无二的值,用于保护变量属性
-
创建语法:
let a = Symbol(); console.log(a); //Symbol()
-
作为属性:
-
赋值与读取语法:
let keys={ name:Symbol(), age:Symbol(), test:Symbol() } let obj={ [keys.name]:"haha", [keys,age]:100 [keys.test](){ console.log("test") } } //通过obj找到test方法并执行 obj[keys.test]()
-
另外,可以对Symbol传参,目的是为了使属性更清晰
let keys={ name:Symbol(name), age:Symbol(age), test:Symbol(test) }
-
for in
只能遍历出普通属性,不能遍历symbol属性
Object.getOwnPropertySymbols(对象名)可以遍历symbol属性
Reflect.ownKeys(对象名)`可以遍历普通属性与symbol属性
//用reflect获得属性与属性值 Reflect.ownKeys(对象名).forEach(item=>{ console.log(item,obj[item]) })
-
-
作为常量
例如: const VIDEO=symbol() const IMAGE=symbol() function play(type){ switch(type){ case VIDEO: console.log("视频") break; case IMAGE console.log("图片") break; } } play(IMAGE)
Iterator迭代器
为各种数据结构提供统一的,简便的访问接口,js可以为它执行如for…of,map(),filter()等迭代方法
原生具备Iterator接口的数据结构
-
Array
-
Map
-
Set
-
String
-
TypedArray
-
函数的 arguments 对象
-
NodeList 对象
原理
- 得到遍历对象,本质是一个指针对象
- 调用next方法,指针指向数据结构的第一个成员
- next方法调用之后会返回一个对象,这个对象有2个属性
- value 是本次迭代的返回值。
- done 是一个bool值,迭代结束的标识,结束就是true
for…of例子
-
语法
for(var i of [1,2,3]){ console.log(i); }
-
原因:数据身上有 iterator方法,而这个方法可以通过被[Symbol.iterator]内置属性引用。
-
内部机制:
const arr=["a","b","c"] //引出iterator const iter=arr[Symbol.iterator]() console.log(iter) //调用next方法遍历 console.log(iter.next()) console.log(iter.next()) console.log(iter.next())
手动实现iterator迭代器
对象是非线性的,无序列化的,所以大多数对象不能用for of遍历
…展开运算符,遇到有迭代器的对象使用时会自动转化为数组
let obj = {
code: 200,
name: "obj",
list: ["a", "b", "c"],
//迭代器
[Symbol.iterator]() {
let index = 0
return {
next: () => {
return {
value: this.list[index++],
done: index === (this.list.length + 1) ? true : false
}
}
}
}
}
//for of遍历功能实现
for (let i of obj) {
console.log(i);
}
//...展开转换为数组
console。log([...obj])
//观察next返回
const iter = obj[Symbol.iterator]()
console.log(iter)
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
console.log(iter.next())
Set结构
类似于数组,但成员值唯一不重复,主要用于为数组去重
let s=new Set([1,2,3,3,4])
//返回值是一个对象1,2,3,4
//转化为数组
console。log([...s])
-
属性
set结构.size
:获取长度 -
方法
set结构.add().add().add()
:添加值,可以链式添加set结构.has(值)
:判断有没有某个值set结构.delete(值)
:删除值set结构.clear()
:清空数组
-
遍历
因为set结构没有索引记住,所以健名就是键值
-
forEach
-
for(let i of set结构{}
:遍历每个成员 -
for(let i of set结构.keys(){}
:返回键名的遍历器 -
for(let i of set结构.values(){}
:返回键值的遍历器 -
for(let i of set结构.entries(){}
:返回每对键值与键名成数组的遍历器对于数组使用此方法
let arr=["aa","bb","cc"] for(let i of arr.entries()){ console,log(i) } //[0:"aa"] //[1:"bb"] //[2:"cc"] let arr=["aa","bb","cc"] for(let [index,item] of arr.entries()){ console,log(index,item) } //0:"aa" //1:"bb" //2:"cc"
-
-
复杂数组去重
let list=[1,2,3,"haha","haha",[1,2],[3,4],[1,2],{name:"haha"},{name:"haha"},undefined,undefined] function uni(arr){ let res=new Set() return arr.filter((item)=>{ //将每一项转化为字符串判断 let id=JSON.stringify(item) if(res.has(id)){ return false } else{ res.add(id) return true } }) } console.log(uni(list))
Map结构
类似于对象,是键值对的集合,各种类型的值都可以当做键
let m=new Map([
["name","haha"],
["age",100],
[{a:1},"大连"]
])
console.log(m2)
//转化为数组
console.log([...m])
-
属性与方法
-
size
-
set
-
delete
-
has
-
clear
-
set结构.get(键名)
:获取键,当键名是一个对象时用变量名引用例如 let o={a:1} let m=new Map([ [o,"大连"] ]) console.log(m.get(o))
-
-
遍历:键名与键值不一样
keys(),values(),entries(),for of
forEach
m.forEach((item,index)=>{ console.log(item,index) })
Proxy代理
Proxy 在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写
let obj = {}
//参数:代理对象,get(),set()
let proxy = new Proxy(obj, {
get() {
console.log("get")
},
set() {
console.log("set")
}
})
//对代理proxy进行设置才有效
//proxy.a
//get
//undefined
//proxy.a="a"
//set
//'a'
Reflect对象
Reflect 可以用于获取目标对象的行为,它与 Object 类似,但是更易读,它提供了一些方法与Proxy中方法一致。
定义,修改一个对象的属性
Reflect.get(target,name,receiver)
const obj = {
};
Reflect.defineProperty(obj, 'name', {
value: 'haha',
writable: false,
configurable:false
});
Reflect对象的方法与Proxy对象的方法一一对应
只要是Proxy对象的方法,就能在Reflect对象上找到对应的方法
let target = new Set()
const proxy = new Proxy(target, {
get(target, key) {
const value = Reflect.get(target,key)
if (value instanceof Function) {
console.log(`${value}`)
return value.bind(target)
//不能 是 call apply
}
return value
},
set() {
return Reflect.set(...arguments)
}
})
proxy.add(1)
promise
专门解决回调地狱
-
语法
每一个异步事件,在执行的时候都会有三个状态:执行中 / 成功 / 失败
借助成功状态,用Promise解决回调地狱
代码理解:
new Promise(function (resolve, reject) {
ajax({
url: '1',
success (res) {
resolve(res)
}
})
}).then(function (res) {
// 发送第二个请求
return new Promise(function (resolve, reject) {
ajax({
url: '2',
data: { a: res.a, b: res.b },
success (res) {
resolve(res)
}
})
})
}).then(function (res) {
ajax({
url: '3',
data: { a: res.a, b: res.b },
success (res) {
console.log(res)
}
})
})
Generator 函数
封装的异步任务,或者说是异步任务的容器
执行 Generator 函数会返回一个遍历器对象,可以依次遍历 Generator 函数内部的每一个状态。
使用 yield 表达式,定义不同的内部状态
function *gen(){
console.log(1)
yield;
console.log(2)
yield;
console.log(3)
}
let g = gen()
g.next()
g.next()
g.next()
Class
基础语法
class Person {
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
}
let obj = new Person("haha",100)
console.log(obj)
getter与setter
class List{
constructor(ele){
this.element = ele
}
get html(){
return this.element.innerHTML
}
set html(arr){
this.element.innerHTML = arr.map(item=>`<li>${item}</li>`).join("")
}
}
let obj = new List(document.querySelector("#list"))
obj.html = ["a","b","c"]
静态属性与方法
静态属性和静态方法
class Person {
static name = "person"
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
static p(){
console.log("eat")
}
}
let obj = new Person("kerwin",100)
console.log(Person.name)
Person.p()
Class继承
注意:子类必须在constructor()方法中调用super(),否则就会报错。
class Person {
static name = "person"
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name,this.age)
}
static eat(){
console.log("eat")
}
}
class Student extends Person{
constructor(name,age,score){
super(name,age)
this.score = score
}
say(){
super.say()
console.log(this.score)
}
static p(){
super.eat();
console.log("student eat")
}
}
let obj = new Student("zzy",100,200)
console.log(obj)
obj.say()
Student.p()