es6
es6
js开源后,然后让ECMA定制标准,2015.6之后的版本称为ES6
关键字
let
console.log(n)
let n = 40 // 没有隐式提前
es5没有代码块作用域,es6存在
if(1){
let a = 10 // let声明的作用域在for代码块中里面
}
console.log(a) // 报错
let a = 10
let a = 40
// 报错,会报错
暂时性死去
var pi = 'a'
if(true) {
console.log(pi)
// 如果下行代码注释就不报错
const pi = '3.14'
}
// 报错,说是pi没有声明就使用
应用
- 闭包问题
- 在for里面如果要声明变量或是函数,用let来声明
const
比let多一个功能
const a = 10
a = 20 // 报错,一旦用const声明赋值后,就不能更改 只能初始化一次
注意:在声明的时候就赋值
解构赋值
在js里面数据模型只有两种,对象和数组
按照某种数据模型,解析并赋值给声明的标识符
var obj = {name: 'jack',age: 32}
// 变量修饰符 数据模型 = 数据源
var {name,age} = obj
// 隐式代码 var name = obj.name; var age = obj.age
数据模型两种 对象和数组
练习
// 写隐式代码
var obj2 = {x1: 30,x2 : 34}
var {x1,x2} = obj2
// var x1 = obj2.x1; var x2 = obj.x2
// -----------------------------------
var obj3 = {}
var {x1:{x2},x3} = obj3
// var x1 = obj3.x1; var x2 = obj3.x1.x2; x3 = obj3.x3
// 会报错 var x2 = obj3.x1.x2 obj3.x1是一个基本类型,不能有.语法糖取值
// ------------------------------------
var [a,b,c] = obj
// a = obj[0] b = obj[1] c = obj[c]
function fn(x,y) {
pass
}
var obj = {x1: 100,x2 s: 44}
fn(obj)
let [pwd,setpwd] = fn()
setpwd(pwd)
// 推出 fn()返回的是一个数组; 数组里面一个为基本类型,一个是函数
fn() {
return [pwd,function(arg) {}]
}
let [a,{son: [{age,se:{son:[x1,y1]}}]}] = Obj;
/*
let a
let
*/
let y1 = Obj[1].son[0].s2.son[1]
let obj = {a}
let {a = 20} = obj
// -----------------------
let obj = {a: undefined}
let {a=10} = obj
// 这是一种特殊的情况,a = 10
实际应用
用于交换两个值
var a = 3,b = 4
var [a,b] = [b,a]
解析从函数返回的值
function fn() {
returen [2,3]
}
var [a,b] = fn()
// 也可以忽略某些值
var a = [3,4,5]
// 至解析3和5
var [c, ,d] = a
剩余数据全部抛出
function fn() {
returen [2,5,6,7,43]
}
var [a, ...b] = fn()
// 注意:...后面如果是逗号会抛出SyntaxError,因为剩余元素必须是数组的最后一个元素
数据模型作为参数
function fn({a,b}) {
}
var a = [2,3]
fn(a)
// 隐士代码 {a,b} = a = [2,3]
数据类型
Symbol
es6新增的基本数据类型
是一个内置全局函数,生成一个独一无二的数据
代表独一无二的,用变量保留起来,即使是相同的名字的变量,也代表了不同的。
作用:可以防止变量冲突的问题
假如 obj里面有一个函数fn 要用obj1来调用
就可以先复制一份obj里面的fn ,在调用
但如果obj1里面原本就有fn,则会出现名字冲突,此时就可以用Symbol解决问题
var names = Symbol()
var names3 = Symbol()
console.log(names == names3) // false
内置对象
新增容器
像document window Image都是浏览器提供的引用数据,在后端是不能使用的,js提供内置对象才可以在后端使用
Map
一个Object的key只是字符串或是Symbol
但时Map的key可以时任意的数据类型,甚至包阔它自己Map
obj = {
0: 'obj'; // 0 在解析的时候会自动加上引号'0'
[10,3]: 'gio' // 报错
}
Map对象的api为get和set来取值和存值
delete删除某个
clear清空数据容器
var m1 = new Map([9,ji],[idf,920])
m1.set('ajig',ajo) // 设置key 可以是任何数据类型
m1.get(ajig) // 取数据的api
m1.delete(idf)
注意
- 用引用数据作为map的key,取值也要使用同一个引用
var m1 = new Map()
var arr = [29,49]
// 存
m1.set('age',30)
m1.set(arr,40)
// 取
console.log(m1.get(arr))
console.log(m1.get('age'))
// Map数据的遍历
m1.forEach(function(el) {
console.log(el) // 遍历取值
})
//-------------------------
for(let [key,value] of m1) {
console.log(key + '=' + value)
}
// -------------------------
for(let key of m1.keys()) {
console.log(key)
}
// ------------------------
for(let key of m1.values()) {
}
// 二维数组和map类型之间的转换
var arr = [[1,10],[2,90],['hello',100]] // 初始化
var m1 = =new Map(arr)
console.log(map)
// map转换为数组
var Array.from(m1) // Array.from()还可以转换伪数组
注意:转为伪数组后m1不改变本身
//Map克隆
let m1 = new Map()
let m2 = new Map(m1) //m2克隆了m1
//------Map合并-----------
let megr = new Map([...m1,...m2])
Set
集合对象允许存储任何类型的唯一值(每一个值都不同),无论是原始值或是对象引用
var s1 = new Set()
s1.add(90)
s1.add(100)
// 集合没有下标,也没有Key 所以取值只能用遍历
s1.forEach(function(el){
console.log(el)
})
应用
-
转换
// Set和Array转换 let sets = new Set([3,'32','ajo']) let arry = [...sets] //String和Set转换 let sets = new Set('sljig') // Set不能用toString来转换
-
数组去重
let arr = [9,23,2,23,13,23,4] let arr2 = [390,302] let sets = new arr([...arr,...arr2]) // 合并 arr = Array.form(sets)
-
差集
let set1 = new Set([3,4,34,22,33,3]) let set2 = new Set([4,23,'ajog',3,34]) // let differ = new Set([...set1].filter(x => !set2.has(x))) let differ = new Set([...set1].filter(function(el) { return !set2.has(el) })) console.log(differ)
-
交集
let set1 = new Set([3,4,34,22,33,3]) let set2 = new Set([4,23,'ajog',3,34]) // let differ = new Set([...set1].filter(x => !set2.has(x))) let differ = new Set([...set1].filter(function(el) { return set2.has(el) })) console.log(differ)
-
并集
let set1 = new Set([3,4,34,22,33,3]) let set2 = new Set([4,23,'ajog',3,34]) let union = new Set([...set1,...set2])
字符串
字符串识别
-
includes()
str.includes(searchString[, position]) //position 可选 在 str 中搜索 searchString 的开始位置,默认值为 0
返回值:如果在字符串的开头找到了给定的字符则返回true;否则返回false
-
startsWith()
str.startsWith(searchString[, position]) //position 可选 在 str 中搜索 searchString 的开始位置,默认值为 0
-
endsWith()
str.endsWith(searchString[, length]) //length 可选 作为 str 的长度。默认值为 str.length
注意:
- 这三个方法只返回布尔值,如果需要知道子串的位置,还是得用 indexOf 和 lastIndexOf 。
- 这三个方法如果传入了正则表达式而不是字符串,会抛出错误。而 indexOf 和 lastIndexOf 这两个方法,它们会将正则表达式转换为字符串并搜索它。
字符串重复
-
repeat()
返回新的字符串,表示将字符串重复指定次数返回。
console.log("Hello,".repeat(2)); // "Hello,Hello,"
如果参数是小数,向下取整
console.log("Hello,".repeat(3.2)); // "Hello,Hello,Hello,"
如果参数是 0 至 -1 之间的小数,会进行取整运算,0 至 -1 之间的小数取整得到 -0 ,等同于 repeat 零次
console.log("Hello,".repeat(-0.5)); // ""
如果参数是 NaN,等同于 repeat 零次
console.log("Hello,".repeat(NaN)); // ""
如果参数是负数或者 Infinity ,会报错:
console.log("Hello,".repeat(-1)); // RangeError: Invalid count value console.log("Hello,".repeat(Infinity)); // RangeError: Invalid count value
如果传入的参数是字符串,则会先将字符串转化为数字
console.log("Hello,".repeat("hh")); // "" console.log("Hello,".repeat("2")); // "Hello,Hello,"
字符串补全
-
padStart
str.padStart(targetLength [, padString]) //targetLength 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。 //padString 可选 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "(U+0020)。
从头部补齐
返回值:在首部填充后形成的新字符串
-
padEnd
str.padEnd(targetLength [, padString]) //targetLength 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。 //padString 可选 填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "(U+0020)。
从尾部补齐
返回值:在原字符串末尾填充指定的填充字符串直到目标长度所形成的新字符串。
模板字符串
用``括起来的字符串,可以在里面加入变量和表达式
// 变量使用 用${}来写js的表达式和变量名
let info = `My Name is ${name},I am ${age+1} years old next year.`
可以换行和空格都会被保留
标签模板,是一个函数的调用,其中调用的参数是模板字符串。
alert`Hello world!`;
// 等价于
alert('Hello world!');
应用:过滤 HTML 字符串,防止用户输入恶意内容。
function f(stringArr,...values){
let result = "";
for (let i = 0; i < stringArr.length; i++) {
values[i] = stringArr[i];
if (values[i]) {
result += String(values[i]).replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">");
}
}
return result;
}
var name = f('<Amy&MIke>');
element.innerHTML = `<p>Hi, ${name}.I would like send you some message.</p>`;
数组
-
Array.of():将参数中所有值作为元素形成数组,参数为空时返回
let arry = Array.of(1,2,3,'ajog',24)
-
Array.from():将类数组对象或可迭代对象转化为数组
Array.from(arrayLike[, mapFn[, thisArg]]) // mapFn:可选,map 函数,用于对每个元素进行处理,放入数组的是处理后的元素。 //thisArg:可选,用于指定 map 函数执行时的 this 对象。
可以转换Set,Map和字符串形式的为数组
-
find():查找数组中符合条件的元素,若有多个符合条件的元素,则返回第一个元素
let arr = Array.of(3,32,1) console.log(arr.find(function(el) { return el > 2 }))
-
findIndex():查找数组中符合条件的元素索引,若有多个符合条件的元素,则返回第一个元素索引
-
fill():将一定范围索引的数组元素内容填充为单个指定的值
let arr = Array.of(1, 2, 3, 4); // 参数1:用来填充的值 // 参数2:被填充的起始索引 // 参数3(可选):被填充的结束索引,默认为数组末尾 console.log(arr.fill(0,1,2)); // [1, 0, 3, 4]
-
entries():遍历键值对
let arr = [3,23,2,'ajog',Symbol()] let arrentry = arr.entries() for(let i = 0;i < arr.length; i++) { console.log(arrentry.next().value) } // --------------for...of...--------- let arr = [3,23,2,'ajog',Symbol()] let arrentry = arr.entries() for(let [key,value] of arrentry) { console.log(value) }
-
keys():遍历键名
let arr = [3,23,2,'ajog',Symbol()] for(let key of arr.keys()) { console.log(key) } console.log(arr.keys())
-
values():遍历键值
let arr = [3,23,2,'ajog',Symbol()] for(let value of arr.values()) { console.log(value) } console.log(arr.values())
-
includes():数组是否包含指定值。注意:与 Set 和 Map 的 has 方法区分;Set 的 has 方法用于查找值;Map 的 has 方法用于查找键名。
[3,23,1,'ajoa'].includes('aa')
返回值: turn 或者false
-
flat()
console.log([1 ,[2, 3]].flat()); // [1, 2, 3] // 指定转换的嵌套层数 console.log([1, [2, [3, [4, 5]]]].flat(2)); // [1, 2, 3, [4, 5]] // 不管潜逃多少层 console.log([1, [2, [3, [4, 5]]]].flat(Infinity)); // [1, 2, 3, 4, 5] // 自动跳过空位 console.log([1, [2, , 3]].flat());<p> // [1, 2, 3]
-
扩展运算符
...
let arr = [3,2,32,'sfao',[3,4,2]] let arr2 = [...arr] 如果里面有引入数据,是浅拷贝,用的是同一个引用
箭头函数
-
箭头函数的this执行的是外层作用域的this
function tool(cb) { cb() // 回调函数 } let obj = { name: "karen", say: function() { console.log(this.name) //karen }, makeMoney: function() { tool(function() { console.log(this,111) // windows 111 }) // 解决方法 tool(()=>{ console.log(this,111) // obj 111 }) } } obj.say() obj.makeMoney
-
如果箭头函数执行体只有一个返回值,大括号可以省掉
如果形参只有一个可以省略参数体的小括号
let fn=(a,b)=> a*b let fn(10,20) //200 let fn=a=>a*a let fn(10) //100
但是最好还是不要省略,提高可读性
-
箭头函数不能用作创建对象,当作构造函数
原因:this指向问题
-
用
...
来取,替代arguments技术var fn=(a,...argums)=>{} // 箭头函数内部时没有arguments的
-
箭头函数不能用apply,bind等方法劫持
应用
function tool(cb) { cb() // 回调函数 } let obj = { name: "karen", say: function() { console.log(this.name) //karen }, makeMoney: function() { tool(function() { console.log(this,111) // windows 111 }) // 解决方法 tool(()=>{ console.log(this,111) // obj 111 }) } } obj.say() obj.makeMoney
模块化开发
引入方式
ES6的模块话开发是按需导入,避免了全局污染
<script type='module'>
import x,{a} from "tis.js" // import要导入a,必须在tis.js文件里面有export到导出a变量
// 默认导出,可以用一个任意的接收
</script>
// 目录地址文件tis.js
export function fn() {}
export abc
// 默认导出:在tis.js文件中只能有一个或0个
var a = 20
var arr = [100,29,30]
var fm=(a,b)=>{console.log(a*b)}
export default {a,arr,fm} // 当做对象导出
类
es6中为了更好的把js设计成面向对象的语言的语法特征
js没有类,是原型的思想设计的类,但学习和使用的时候,用类的思想学习
用类创建对象时,就会运行构造函数,如果不写构造函数,系统会默认有一个空的构造函数运行
// 声明类
class Person{ // 类名首字母大写 非必要但规定
// 类内部的构造函数
constructor(a,b,c){
this.x = a
this.b = b
}
life = 0
say() {
console.log(111)
}
// 静态属性和静态方法 Person类创建的对象p1是不能访问Person类里面的静态属性和静态方法的
static life = 30
static say() {
console.log(222)
}
}
let p1 = new Person // 没有提升的说法,必须先声明,在创建对象
// 匿名类
var fn = class Person{} // Person不能访问
var p2 = new fn()
继承
Student类继承Person类所有的属性和方法,包括静态属性和静态方法
如果父类和子类都有,则子类会覆盖父类的方法
class Student extends Person{
constructor(name) {
super(name) // 让Person类的构造函数的逻辑去创建对象空间
}
}
异步编程
同步任务都在主程序上执行,形成一个执行栈
异步进程处理:当异步任务时间到的时候,才写入任务队列中
异步任务通过回调函数,形成一个任务队列
- 普通事件 onclick resize等
- 资源加载
- 定时器 setTImeout setInterval等
由于线程不断的重复获取任务,执行任务,再获取任务,再执行,所以这种机制被称为时间循环(eventloop)
promise
promise对象的then函数是一个非阻塞的异步函数
promise是一个构造函数,创建了了一个数据容器,不是一个异步函数
ES5出现,ES6里写入了标准
学习promise前提
-
精通回调的思想
// 工具函数 function creatData(callback) { callBack(parseInt((Math.random()*(10-1)+1))) } let obj = { Data: 100, tool: function() { creatData((n)=>{ this.Data = n }) } }
-
精通异步编程的思想
-
异步函数:计时器
let p1 = new Promise(function(n1,n2){
// 主动的产生数据:比如网络请求
let data = {code: 404,info: "假数据"}
// n2 表示触发告知Promise体系 业务错误的数据
if(data.code == 404) {n2(data.info)}
else if(data.code == 200) {n1(data.info)}
})
// 取数据 then函数是一个异步函数
p1.then(function(data){
console.log(data)
},function() {
// 获取错误的业务数据
})
-
then():取数据
-
catch():捕获错误方法
还可以使用catch方法,可以直接捕获错误信息
p1.then(function(data){ // 获取正确的值 console.log(data) },function(err) { // 获取错误的业务数据 })
// 还可以使用catch方法,可以直接捕获错误信息
p1.then((re)=>{
console.log(re)
}).catch(err)=>{
console.log(err)
}返回值:是一个新的promise对象,是then回调函数的返回值:如果是一个promise对象,那么就是它,如果不是一个promise对象,那就把函数的结果包装为一个生成数据了的promise对象
应用:设计工具
#### 任务的队列分类和事件循环
**js执行流程**
1. 先执行js执行栈中的同步任务
2. 异步任务(回调函数)放在任务队列中
3. 一旦执行栈中所有的同步任务执行完毕,系统就会按次序读取任务队列中的异步任务,于是被读取的异步任务结束等待状态,进行执行栈,开始执行
任务指的的是js中运行的代码,脚本,计时器,Promise也是一个任务
```js
// 这三行都是任务 是同步的
function fn() {}
var a = new Array()
var b = fn()
// 计时器,Promise也是一个任务 异步的
setTime(()=>{console.log(2)},1000)
var p1 = new Promise((n1,n2)=>{n1(1000)})
p1.then(()=>{console.log(3)})
异步任务的队列优先级:异步宏任务先执行 然后在执行异步微任务
事件循环:任务开启后,内部执行的可能再次开启任务
- 先执行第一轮宏任务(脚本)中的代码:同步微任务 下一轮任务中的代码 宏任务中:同步微任务下轮排队的宏任务
- 下论排队的宏任务中:执行同步执行宏任务遇到宏任务继续排队~执行下轮排队的宏任务
- 下论排队的宏任务中:执行同步执行宏任务遇到宏任务继续排队~执行下轮排队的宏任务
脚本运行 执行第一个宏任务
- 先执行同步任务
- 添加新的宏任务到队列中,添加新的异步微任务
- 执行异步微任务
任务分为同步和异步