ES6深入了解
let 变量
块级作用域
循环或者判断语句内存在
重复声明
重复申明覆盖前面的内容
没有变量提升
定义在使用的后面会报错
不像var一样,把申明内容提至最前
不与顶层对象挂钩
var num=100
console.log(window.num)//100
let num=100
console.log(window.num)//undefined
conset 常量
//const对象里的子级内容可以改变
const myobj={
name:"kerwin",
age:100
}
myobj.name="tiechui"
//冻结对象以及他的子级,孙子级及以下冻不住——freeze
const myobj=Object.freeze({
name:"kerwin",
age:100
})
常量
不能重新赋值
不能重复定义
块级定义域
申明不提升
不与顶层对象挂钩
解构赋值
写一个格式相同的数组或对象,利用相同结构赋值获取自己需要的值
var arr=["xiaoming","tiechui","shanzhen"]
let [x,y,z]=arr
//x,y,z已被arr赋值
var a=10
var b=20
var [b,a]=[a,b]
//交换值
var arr2 =[1,2,[3,4,[5]]]
var [q,w,[e,r,[t]]]=arr2
conslo.log(t)
//相同结构取值
var obj={
namr:"kerwin",
age:100,
location0:"dalian"
}
let {name,age,loaction0}=obj
document.write(name)
document.write(age)
document.write(location0)
模板字符串
//老式字符串拼接
let name="tiechui"
let oli="<li>\
<b>"+name+"</b>\
</li>"
//模板字符串
let name="tiechui"
let oli=`<li>
<b>${name}</b>
</li>`
拓展
字符串拓展
includes函数
判断字符串中是否存在字符
let myname="kerwin"
console.log(myname.includes("e"))//true
console.log(myname.startwith("k"))//true
console.log(myname.endwith("n"))//true
console.log(myname.include("e",2))//false,从索引值为2后面找有没有e出现
console.log(myname.endwith("n",3))//false,从索引值为3的前面找
repeat函数
repeat()方法返回一个新字符串,表示将原字符串重复n次
let myname="kerwin"
console.log(myname.repeat(3))//kerwinkerwinkerwin
console.log(myname.repeat(0))//""
console.log(myname.repeat(3.5))//kerwinkerwinkerwin
console.log(myname.repeat("3"))//kerwinkerwinkerwin
数值拓展
二进制和八进制表示法
let count1=100
let counet2=0x100//16
let count3=0o100//8
let count4=0b100//2
isFinite与isNaN方法
减少全局性方法,使得语言逐步模块化
//判断是不是数
let num1=Number.isFinite(100)//true
let num2=Number.isFinite(100/0)//false
let num3=Number.isFinite(InFinity)//false
let num4=Number.isFinite("100")//false
//判断是不是不是个数(仅限number中)
let num1=number.isNaN(100)//false
let num2=Number.isNaN(NaN)//true
let num3=Number.isNaN("kerwin")//false
let num4=Number.isNaN("100")//false
它们与传统的全局方法isFinite()和isNaN的区别在于,传统方法先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效,Number.isFinite()对于非数值一律返回false,Number.isNaN()只对于NaN次啊返回true,非NaN一律返回false
isInteger,判断是不是整数
let num1=Number.isInteger(100)//true
let num2=Number.isInteger(100.0)//true
let num3=Number.isInteger("kerwin")//false
let num4=Number.isInteger("100")//false
极小常量Number.EPSILON
它表示一个1与大于1的最小浮点数之间的差。2.220446049250313e-16
funtion isEqual(a,b){
return Math.abs(a-b)<Number.EPSILON
}
console.log(isEqual(0.1+0.2,0.3))//true
console.log(0.1+0.2===0.3)//false,0.1+0.2>0.3
Math.trunc
将小数部分抹掉,返回一个整数
console.log(Math.trunc(1.2))//1
console.log(Math.trunc(1.8))//1
console.log(Math.trunc(-1.2))//-1
console.log(Math.trunc(-1.8))//-1
Math.sign
判断一个数到底是整数、负数还是零。对于非数值,会先将其转换为数值。
Math.sign(-100)//-1
Math.sign(100)//+1
Math.sign(0)//+0
Math.sign(-0)//-0
Math.sign("kerwin")//NaN
数组拓展
pop,删除栈底元素
拓展运算符
let arr1=[1,2,3]
let arr2=[4,5,6]
console.log([...arr1,...arr2])
Array.from
将类数组对象转换为真正的数组
function test(){
console.log(Array.from(arguments))
}
test(1,2,3)
let oli=document.querySelectorAll("li")
console.log(Array.from(oli))
Array.of
将一组值转化为数组,即新建数组
let arr1=Array(3)
console.log(arr1)//[,,]
let arr2=Array.of(3)
console.log(arr2)//[3]
find,findIndex
该方法主要是应用于查找第一个符合条件的数组元素
它的参数是以一个回调函数。在回调函数中可以写你要查找元素的条件,当条件成立为true时,返回该元素。如果没有符合条件的元素,返回值为undefined
let arr=[11,12,13,14,15]
let res=arr.find(function(item){
return item>13
})
console.log(res)//14
let res=arr.findIndex(function(item){
return item>13
})
console.log(res)//3
fill,空白填充
let arr=new Array(3).fill("kerwin")
console.log(arr)
let arr1=[11,22,33]
console.log(arr1.fill("kerwin",1,2))
flat() flatMap()
集成扁平化
let arr=[1,2,3,[4,5,6]]
let arr1=arr.flat()
console.log(arr,arr1)
函数拓展
1、默认参数
function ajax(url,method="get",async=true){
console.log(url,method,async)
}
ajax("/bbb")
2、-rest参数 剩余参数
function(x,y,...data){//展开运算符
console.log(data)
}
name属性
console.log(test.name)==name
对象简写
对象简写
let name="moduleA"
let obj={
name,//name:name
test1(){
},
test2(){
}
}
对象属性 表达式
let name="moduleB"
let obj={
name,
[name+"test2"](){
}
[name+"test2"](){
}
}
拓展运算符
let obj={
name:"kerwin"
}
let obj1={
...obj//不是赋值obj地址,而实内容,可以单独修改
}
Object.assign
对象拼接,会将拼接的对象拼接进第一个对象(第一个对象会被改变),最好设置一个空数组
Object.is判断两个值是否完全相等(===不能判断NaN)
箭头函数
()可以省略
{}可以省略,只有一句代码,只有返回值的时候
没有arguments
this的问题,箭头函数this是父级作用域的
var test1=function(){
console("1111")
}
var test2=()=>{
console.log(2222)
}
//(只有一个形参的时候)可以省略
var test = a =>{
console.log(111,a)
}
test("kerwin",100)
//{}可以省略,只有一句代码,只有返回值的时候
var test = a => 100*a
console.log(test(10))
//this问题
<body>
<input type="text" id="mytext">
<script>
mytext.oninput=function(){
setTimeout(function(){
console.log(this)
},1000)
}
</script>
</body>
//这里this拿到的是window,而不是mytext
//解决方案1
<body>
<input type="text" id="mytext">
<script>
mytext.oninput=function(){
var that=this//先用that保存父级
setTimeout(function(){
console.log(that.value)
},1000)
}
</script>
</body>
//解决方案2
<body>
<input type="text" id="mytext">
<script>
mytext.oninput=function(){
setTimeout(()=>{
console.log(this.value)
},1000)
}
</script>
</body>
//霸道的箭头函数
symbol
第七种数据类型(undefined、null、Boolean、string、number、object)
let name=Symbol()
let age-Symbol()
var obj={
[name]:"kerwin",
[age]:100
}
Symbol()函数可以接受一个字符串作为参数,表示对Symbol实例的描述。这主要是为了在控制台显示,比较容易区分
let name=Symbol("name")//这样写symbol就容易区分,不会全显示symbol()=****
let age=Symbol("age")
var obj={
[name]:"kerwin",
[age]:100
}
console.log(obj)
注:
1、不能运算
2、显示调用toString()
3、隐式转换boolean
getOwnPropertySymbols()拿出里面所有的symbol函数
Iterator 迭代器
作用:
1、为各种数据结构,提供一个统一的、简便的访问接口
2、使得数据结构的成员能够按某种次序排列
3、ES6创造了一种新的遍历命令for…of循环,Iterator接口主要供for…of循环
let arr=["kerwin","tiechui","gangdaner"]
for(let i of arr){
console.log(i)//of是数组里的值,in是索引
}
Interayor的遍历过程
1、创造一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象
2、第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
3、第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。
4、不断调用指针对象的next方法,直到它指向数据结构的结束位置
let i=arr[symbol.iterator]()
console.log(i.next())
console.log(i.next())
console.log(i.next())
console.log(i.next())
ES6规定,默认的Iterator接口部署在数据结构的symbol.iterator属性,或者说,一个数据结构只要具有symbol.iterator属性,就可以认为是“可遍历的”(iterator)。symbol.iterator属性本身就是一个函数,就是当前数据结构默认的遍历器生成函数。执行这个函数,就会返回一个遍历器
原生默认具备Iterator接口的数据结构如下
Array
Set
Map
String
arguments对象
Nodelist对象
let obj={
0:"kerwin",
1:"tiechui",
2:"gangdaner",
length:3,
[Symbol.iterator]:Array.prototype[Symbol.iterator]
}
for(let i of obj){
console.log(i)
}
let obj2={
data:['kerwin','tiechui','gangdaner'],
[Symbol.iterator](){
let index=0;
return{
if(index<this.data.length){
return{
value:this.data[index++],
done:false
}
}else{
return {
value:undefined,
done:true
}
}
}
}
}
for(let i of obj2){
console.log(i)
}
set结构
它类似于数组,但成员的值都是唯一的,没有重复值(去重的好东西)
let s1=new set([1,2,3,2,3])
console.log(s1)
let s2=new set()
s2.add(1)
s2.add(2)
s2.add(3)
console.log(s2)
size:返回set实例的成员数
set.prototype.add(value):添加某个value
set.prototype.delete(value):删除某个value,返回一个布尔值,表示删除是否成功
set.prototype.has(value):返回一个布尔值,表示该值是否为set成员
set.prototype.clear():清楚所有成员,没有返回值
遍历
set.prototype.keys():返回键名的遍历器
set.prototype.values():返回键值的遍历器
set.prototype.entries():返回键值对的遍历器
set.prototype.foreach():遍历每个成员
Map结构
类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
let m1=new map()
m1.set("name","kerwin")
m1.set({a:1},"大连")
console.log(m1)
let m2=new map([
["name","kerwin"],
[{a:1},"大连"]
])
size:返回Map结构的成员数
Map.prototype.set(key.value):添加key对应得value,返回Map结构本身
Map.prototype.get(key):获取key对应得value
Map.prototype.delete(key):删除某个键
Map.prototype.has(key):某个键是否在当前Map对象之中
map.prototype.keys():返回键名的遍历器
map.prototype.values():返回键值的遍历器
map.prototype.entires():返回所有成员的遍历器
map.prototype.foreach():遍历Map的所有成员
proxy代理
它的作用是在对象和对象的属性值之间设置一个代理,获取该对象的值或者设置该对象的值,以及实例化等等多种操作,都会被拦截住,经过这一层我们可以统一处理,我们可以认为它就是“代理器”
proxy本质上属于元编程非破坏性数据劫持,在原对象的基础上进行了功能的衍生而不影响原对象,符合松耦合高内聚的设计理念
get方法
let target={}
let proxy=new proxy(target,{
get(target,prop){
return target[prop]
}
})
set方法
const proxy_set = new Proxy({}, {
set: function (target, prop, value, receiver) {
target[prop] = value;
console.log('property set: ' + prop + ' = ' + value);
return true;
}
})
console.log("======proxy_set=======")
console.log('name' in proxy_set); // false
proxy_set.name = 'duXin'; // property set: name = duXin
console.log('name' in proxy_set); // true
has方法
const targetObj = {
_secret: 'easily scared',
eyeCount: 4
};
const proxy_has = new Proxy(targetObj, {
has: (target, key) => {
console.log("key==",key)
if (key.includes('_')) {
return false;
}
return key in target;
}
})
console.log('eyeCount' in targetObj); // true
console.log('_secret' in proxy_has); // false
reflect对象
reflect可以用于获取目标对象的行为,它与object类似,但是更易读,为操作对象提供了一种更优雅的方式。它的方法与proxy是对应的
//代替object的某些方法
const obj={
};
reflect.defineprototype(obj,'name',{
value:'kerwin',
writable:false,
configurable:false
})
//修改某些object方法返回结果
//老写法
try{
object.defineproperty(target,property,attributes);
//success
}catch(e){
//fail
}
//新写法
if(reflect.defineproperty(target,property,attributes)){
//success
}else{
//fail
}
//命令式变为函数行为
const obj={
name:"kerwin"
}
//老写法
consoel.log("name"in obj)//true
//新写法
console.log(reflect.has(obj,"name"))//true
//老写法
delete obj.name
//新写法
reflect.deleteproperty(obj,"name")
//配合proxy
let target = new set()
const proxy=new proxy(target,{
get(target,key){
const value=reflect.get(target,key)
//遇到function都手动绑定一下this
if(value instanceod function){
console.log('访问${value}方法了')
return value.bind(target)
//不能是call apply
}
return value
}
set(){
return reflect.set(...arguments)
}
})
promise
promise是异步编程的一种解决方案,比传统的解决方案回调函数,更合理和更强大。ES6将其写进了语言标准,同意了用法,原生提供了promise对象
指定回调函数方式更灵活易懂
解决异步回调地狱的问题
回调地狱
当一个回调函数嵌套一个回调函数的时候
就会出现一个嵌套结构
当解套的多了就会出现回调地狱的情况
比如我们发送三个ajax请求第一个正常发送
第二个请求需要第一个请求的结果中的某一个值作为参数
第三个请求需要第二个请求的结果中的某一个值作为参数
promise的使用
//语法
var q = new Promise(function(resolve,reject){
//放异步
settimeout(()=>{
//成功兑现承诺
resolve()
//失败拒绝承诺
//reject()
},2000)
})
//pending 执行中
//fulfilled 兑现承诺
//reject 拒绝承诺
//q是promise对象
q.then(function(){
//兑现承诺,这个函数被执行
}).catch(function(){
//拒绝承诺,这个函数被执行
})
promise对象的状态
promise对象通过自身的状态来控制异步操作。promise实例具有三种状态异步操作为完成(pending)
异步操作成功(fulfilled)
异步操作失败(rejected)这三种的状态的变化途径只有两种
从“未完成”到“成功”
从“未完成”到“失败”一旦状态发生变化,就凝固了,不会再有新的状态变化。这就是promise这个名字的又来,它的英文意思是“承诺”,一旦承诺成效,就不得再该笔拿了。这意味着,promise实例的状态比纳湖啊只可能发生一次。因此,promise的最终结果只有两种
generator函数
generator函数是ES6提供的一种异步编程解决方案
geneator函数是一种状态机,封装了多个内部状态
执行generator函数会返回一个遍历器对象们,也就是说,generator函数除了状态机,还是一个遍历器对象生成函数。返回的遍历器对象,可以一次遍历generator函数内部的每一个状态
//基本语法
function *gen(){
console.log(1)
tield;
console.log(2)
yield;
console.log(3)
}
let g=gen()
g.next()
g.next()
g.next()
class语法
//1类的写法
classperson{
constructor(anme,age);
this.name=name;
this.age=age;
}
say(){
console.log(yhis.name,this.age)
}
let obj=new person("kerwin",100)
console.log(obj)
//getter与setter
class list{
constructor(ele){
this.element=ele
}
get html(){
return this.element.innerHTML
}
}
class继承
class Person{
constructor(name,age){
this.name=name
this.age=age
}
say(){
console.log(this.name,"hello")
}
}
//extend原型继承
class Student/*子类*/ extends Person/*父类*/{
constructor(name.age,grade){
super(name,age)//Person.call(this,name,age)
this.grade=grade
}
say(){
super.say()//继承上面的say
console.log(this.name,"你好")
}
}
var obj = new Student()
console.log(obj)
Module语法
1、私密不漏
2、重名不怕
3、依赖不乱
注意script引用记得加type=“module”(依赖不乱)
export{
***
*****
}
//导出函数
import{} from ' ./'
//导入函数
import{A1,A2,test as A_test} from ' ./'
import{B1,B2,test as b_test} from './'
//解决重名问题
export default c
//默认导出c
模块化
js现在有两种模块。一种是ES6模块,简称ESM;另一种是commonJS模块,简称cjs
commonjs模块是nodejs专用的,与ES6模块不兼容。语法上面,两者最明显的差异是,commonjs模块使用require()和module.exports,ES6模块使用import和export
ES6模块不是对象,而实通过export命令显示指定输出的代码,再通过import命令输入
//写法1
export default A1
import a1from "./1.js"
export {A1,A2}
import {A1,A2} from "./1.js"
import {A1as a1,A2 as a2} from "./1.js"
import * as obj from "./1.js"