es6
1.环境搭建
- 方法一
下载node.js,在git-bash.exe中输入 node -v 显示node.js版本
输入 npx es10-cli create es2019初始化项目
cd 到项目目录
npm start
访问http://localhost:8080
- 方法二
使用npx命令 npm版本 >5.2.0
npm install es10-cli -g
es10-cli create projectName
cd projectName
npm start
- 方法三
如果都失败
git clone https://github.com/cucygh/es-cli.git es2020
cd 2020
npm install
npm start
- 如何切换npm源
参考文章:http://www.imooc.com/article/254541
- 配置编辑器
2.ES6语法
- 作用域
- 全局作用域
- 块状作用域
- 函数作用域
- 动态作用域
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
</body>
<script type="text/javascript">
//全局作用域
var abc = 1234 //全局变量
console.log(abc)
abcd = 2345 //作为window(全局对象)的属性存在 不是真正意义上的全局变量
console.log(abcd)
function test (){
ab = 45 //不是函数作用域 是全局作用域 挂在window上作为window的属性
}
test()
//函数作用域
function test1(){
var a =3 //局部作用域 函数作用域
return a + 4 //通过return 或者闭包的形式向外传递数据
}
console.log(test1())
console.log(a) //报错 Uncaught ReferenceError: a is not defined
function test3(){
var a =3
function test4(){
var b=4 //函数作用域会向上找 如果a +b+c,找不到c会找window对象 没有就返回undefined
return a+b
}
return test4 //闭包
}
//块状作用域
function test2(){
var a =3
if(a===3){ //可以认为花括号内部就是一个独立的块作用域
let b=4 //不会向上找了 没用上下级作用域链 使用var会变量提升
console.log('abc')
}else{
console.log('abcd')
}
console.log(b)
return a+ 4
}
console.log(test2())
//动态作用域
window.a=3
function test(){
console.log(this.a)
}
test()
test.bind({a:100})()
//bind 之后返回一个新的函数,这个函数可以保持传递的this上下文
</script>
</html>
Let
- let声明的变量拥有块级作用域
- let声明的全局变量不是全局对象(window)的属性
- 用let重定义变量会抛出一个语法错误
- let声明的变量不会进行变量提升
<script type="text/javascript">
{
let a =1
console.log(a)
}
console.log(a) //块状作用域 在外部不能访问 Uncaught ReferenceError: a is not defined
var b =3
let c =4
console.log(b,c)
console.log(window.b,window.c) //var定义的全局变量可以通过window访问 let定义的全局变量不能
var b =4 //var定义的变量可以重复
console.log(b)
let c =5 //let定义的变量不可以重复 Identifier 'c' has already been declared
console.log(c)
//let定义的变量不会变量提升
</script>
const
- const拥有let的特性,除此之外const只能定义常量
- const定义的变量不能修改 Assignment to constant variable
- const不能先声明再赋值 Missing initializer in const declaration
//const拥有let的特性,除此之外const只能定义常量
const a =2
a=3
console.log(a) //Assignment to constant variable. 不能修改变量
const b
b=3 //不能先声明在赋值 Missing initializer in const declaration
阅读:
1.什么是作用域
JavaScript深入之词法作用域和动态作用域
深入理解js中声明提升,作用域(链)和this关键字
输出什么 如何根据i的顺序输出
for(var i=0;i<3;i++){
setTimeout(function(){
console.log(i)
},1000);
} =>输出3个3
https://www.cnblogs.com/wl0804/p/11987833.html
以下代码发生什么
console.log(a)
let a =1 ==>Uncaught ReferenceError: Cannot access 'a' before initialization
Array
- es5中数组遍历有多少种方法
- 优点与缺点
<script type="text/javascript">
const arr =[1,2,3,4,5];
//for循环
for (let i = 0; i < arr.length; i++) {
if(arr[i]===2){
continue;
}
console.log(arr[i])
}
//forEach
arr.forEach(function(item){
//不支持break与continue语法
console.log(item)
})
//every
arr.every(function(item){
console.log(item)
//默认不继续循环遍历
return true
})
//every实现break功能
arr.every(function(item){
if(item===2){
return false
}
console.log(item)
})
//every实现continue功能
arr.every(function(item){
if(item===2){
}else{
console.log(item)
}
return true
})
//for in 主要是操作对象的 也可以遍历数组 但是会有问题
//数组也是对象的一种
arr.a = 8 //数组的索引不应该是a
for(let index in arr){
console.log(index,arr[index])
}
//for in支持break与cotinue
for(let index in arr){
if(index ==2){ //这里的index是字符串,而不是数值,需要用==才能break成功 ===判断数值和类型,==只判断数值不判断类型
break;
}
console.log(index,arr[index])
}
es6遍历语法
//for of 遍历自定义数据结构 既不是数组也不是object
for(let item of arr){
console.log(item)
}
const price= {
A:[1.5,2.5,3.5],
B:[3,4,5],
C:[0.5,0.8,1.2]
}
for(let key in price){
console.log(key,price[key])
}
//后面继续讲for of
- es5中将伪数组转换成数组该怎么办
伪数组具备数组的一些特性,具备长度都能遍历,不能直接调用数组方法
- es6中如何做
<script type="text/javascript">
//转换 es5中是这样用的 但是不去执行这段代码
//吧arguments转换成数组
let args=[].slice.call(arguments) //collection
let imgs=[].slice.call(document.quarySelectorAll('img')) //NodeList
console.log(args)
//es6做法 Array.prototype.from 伪数组转换成数组
let args = Array.from(arguments)
let imgs = Array.from(document.quarySelectorAll('img'))
imgs.forEach()
let array = Array(5)
for( let i=0,len=array.length;i<len;i++){ //使用forEach不行
array[i]=1
}
console.log(array)
//Array.from(arrayLike,mapFn,thisArg)
//伪数组:按照索引方式存储数据的 具备一个length属性{0:'a',1:'b',length:2}
let array = Array.from({length:5},function(){return 1})
console.log(array)
</script>
- es5中如何创建一个新数组
- es6中应该如何做
//生成新数组 push pop
let array = Array(5)
let array = ['','']
//Array.prototype.of
let array = Array.of(1,2,3,4,5)
console.log(array)
//Array.prototype.fill
let array = Array(5).fill(1)
console.log(array)
//Array.fill(value,start,end)
let array = [1,2,3,4,5]
console.log(array.fill(8,2,4))
- es5中如何查找一个元素
- es6中如何做
//es5查找
let array = [1,2,3,4,5]
// 判断有无(空或非空) 关注的是满足条件的所有元素 返回成数组
let find = array.filter(function (item){
return item ===1
return item %2 ===0 ==>2 4
})
console.log(find)
// es6 Array.prototype.find 关注的是满足条件的第一个值
let find= array.find(function(item){
return item %2 ===0 //=>2
})
console.log(find)
//Array.prototype.findIndex 返回的是索引
let find= array.findIndex(function(item){
return item %2 ===0 //=1
})
console.log(find)
javascript有哪些元素是可遍历的
如何给数据结构自定义遍历
find()和es5的filter()有什么区别
Class
- es5中如何声明一个类
- es6中如何做的
es5中声明类
<script type="text/javascript">
let Animal = function(type){
this.type=type;
// this.eat = function(){
// console.log('eat food')
// }
}
//将方法挂在原型链上
//将共有的属性方法放到原型链上去
Animal.prototype.eat = function(){
console.log('eat food food')
}
let dog = new Animal('dog')
let cat = new Animal('cat')
// cat.eat = function(){
// console.log('error')
// }
cat.constructor.prototype.eat = function(){
console.log('error')
}
console.log(dog)
console.log(cat)
dog.eat()
cat.eat()
</script>
es6中声明类
class Animal{
constructor(type){
this.type=type
}
eat(){
console.log('eat food')
}
}
let dog = new Animal('dog')
let cat = new Animal('cat')
console.log(dog)
console.log(cat)
dog.eat()
cat.eat()
get&set属性操作
es6读写属性
let _age=4
class Animal{
constructor(type){
this.type=type
}
get age(){ //属性
return _age;
}
set age(value){
if(value<7&&value>4){
_age=value
}
}
eat(){
console.log('eat food')
}
}
let dog = new Animal('dog')
console.log(dog.age)
dog.age =5
console.log(dog.age)
方法
- es5中如何操作一个方法
- es6中如何操作
- 对象实例方法 类的静态方法
es5中操作方法
let Animal = function(type){
this.type=type;
//this.eat= function(){}
}
//实例对象方法
Animal.prototype.eat = function(){
Animal.walk()
console.log('eat food food')
}
//类的静态方法 不能用实例(this)调用
Animal.walk= function(){
console.log('i am walking')
}
let dog = new Animal()
dog.eat()
es6操作方法
class Animal{
constructor(type){
this.type = type
}
eat(){
Animal.walk()
console.log('eat food')
}
static walk(){
console.log('i am walking')
}
}
let dog = new Animal()
dog.eat()
继承
- es5中怎么继承一个类
- es6中怎么做
es5中继承一个类
let Animal = function(type){
this.type=type;
//this.eat= function(){}
}
//实例对象方法
Animal.prototype.eat = function(){
Animal.walk()
console.log('eat food food')
}
//类的静态方法 不能用实例(this)调用
Animal.walk= function(){
console.log('i am walking')
}
let Dog = function (){
//用call改变this的指针 指向dog的实例 实现了一部分父类继承
//在dog的构造函数中要执行Animal构造函数 初始化父类的构造函数
Animal.call(this,'dog')
}
//值类型 引用类型
//关联Dog和Animal的原型链
Dog.prototype = Animal.prototype
let dog = new Dog()
dog.eat()
es6中类的继承
class Animal{
constructor(type){
this.type = type
}
eat(){
Animal.walk()
console.log('eat food')
}
static walk(){
console.log('i am walking')
}
}
class Dog extends Animal{
constructor(type){
super(type)
this.age = 2
}
}
let dog = new Dog()
dog.eat()
console.log(dog.age)
Function Updates
- es5中怎么处理函数参数的默认值
- es6中怎么做
es5中操作
function f(x,y,z){
if(y ===undefined){
y=7
}
if(z ===undefined){
z=42
}
return x+y+z
}
console.log(f(1))
//es6中
function f(x,y=7,z=x+y){
//console.log(arguments.length) 输出传入参数的个数
//es6中不使用arguments
//console.log(Array.from(arguments)) //这里arguments是伪数组
console.log(f.length) //能获取到没有默认值的参数个数 方法定义的参数 而不是执行时给的参数
return x+y+z
}
console.log(f(1)) //16
console.log(f(1,undefined,43)) //51
- es5中怎么处理不确定参数的问题
- es6中如何去做
es5中的操作
function sum(){
let num=0
// Array.prototype.forEach.call(arguments,function(item){
// num = num+item
// })
Array.from(arguments).forEach(function(item){
num = num+item
})
return num
}
console.log(sum(1,2,3))
es6中的操作
function sum(base,...nums){ //所有的(函数传参的)参数都放在nums中 Rest parameter
//加上base,则是把第一个参数放入base中,其余的参数放入nums中
let num = 0
nums.forEach(function(item){ //nums是个数组类型
num = num+item
})
return base*2 + num
}
console.log(sum(1,2,3,4))
参数个数确定
//计算三角形周长
function sum(x=1,y=2,z=3){
return x+y+z
}
let data = [4,5,6]
console.log(sum(data[0],data[1],data[2]))
//es5中操作
console.log(sum.apply(this,data))
//es6中操作 spread操作
console.log(sum(...data))
- es6中的箭头函数是什么
- ()=>{}
//箭头函数
let hello = (name,city) => { //有参数且只有一个参数时,()可以省略
console.log('hello',name,city)
}
hello('world','beijing')
let sum = (x,y,z) => x + y + z //箭头后面是表达式 可以省略花括号和return
let sum = (x,y,z) =>({ //以对象形式返回,加个(),{}是对象的花括号
x: x,
y: y,
z: z
})
let sum = (x,y,z) => {
return{
x: x,
y: y,
z: z
}
}
let test = {
name: 'test',
say: function(){
console.log(this.name)
}
}
test.say() //谁调用function this就指向谁
let test = {
name: 'test',
say: () => {
console.log(this.name,this) //定义的时候this指向是什么 执行的时候还是什么
//放到浏览器中执行 this指向window
}
}
练习
如何用箭头函数来实现一个数组排序的问题
箭头函数对this的处理还有什么妙用
- 对象
- es5中Object属性能简写吗
- es6中如何处理的
//es5
let x =1
let y=2
let z = 3
let obj = {
x,
y,
hello: function(){
console.log('hello') 常规函数 es5中不允许在Object对象中写异步函数
}
}
obj[z] = 5
console.log(obj)
//es6
let x =1
let y=2
let z = 3
let obj = {
x,
y,
[z]:6,
[z+y]:8,
* hello(){ //异步函数
console.log('hello')
}
}
// function* functionName() {
// }
console.log(obj)
obj.hello()
- es6中除了用Object存储数据
- Set 所存储的数据必须是唯一的 不允许重复 重复的数据会自动过滤
- Set里面的元素是任意值
//Set
let s = new Set()
let s = new Set([1,2,3,4]) //Set可接受的对象是可遍历的 不仅仅是数组
s.add('hello')
s.add('world')
s.add('hello').add('world').add('hello')
console.log(s)
//删除指定数据
s.delete('hello')
console.log(s)
//全部清空
s.clear()
console.log(s)
//查找 true/false
console.log(s.has('world'),s.size)
//读数据
console.log(s.keys(),s.values())
//键值对
console.log(s.entries())
s.forEach(item => {
console.log(item)
})
for(let item of s){
console.log(item)
}
//改数据 先删在增加
- es6中Map是什么,解决什么问题,怎么使用
- Map的key为任意值
let map = new Map([[1,2],[3,4]]) //可以传入可遍历对象 与Set的区别在于 key为任意值
//添加数据
map.set(5,6)
//修改数据
map.set(1,3)
//删除数据
//map.delete(1)
//map.clear()
console.log(map)
//统计数据
console.log(map.size)
//查找数据
console.log(map.has(3))
//取数据
console.log(map.get(1))
console.log(map.keys(),map.values(),map.entries())
// map.forEach(function(item){
// console.log(item)
// })
map.forEach((value,key) => { //value key
console.log(value,key)
})
for(let [key,value] of map){ //key value
console.log(key,value)
}
let o = function(){
console.log('o')
}
map.set(o,4)
console.log(map)
//map性能比Object稍微有点优势
- es5中怎么把一个对象复制到另一个对象上
- es6如何做
//es6中
const target = {}
const source = {b:4,c:5}
Object.assign(target,source)
console.log(target)
const target = {
a:{
b:{
c:{
d:3
}
},
e: 1,
f: 2,
h: 4 //拷贝过去h没有了 因为assign是浅复制
}
}
const source = {
a:{
b:{
c:{
d:1
}
},
e: 5,
f: 6
}
}
Object.assign(target,source) //浅复制 对于不是引用类型的值 做数据的替换
//对于引用类型的值 不再遍历 把引用的地址换一下
//递归 assign处理 实现深拷贝
console.log(target)
练习
如果目标对象传入的是undefined和null将会怎样
如果源对象的参数是undefined和null将会怎样
如果目标对象是个嵌套的对象 ,子对象的属性会被覆盖吗
-
weakSet weakMap
-
不常用 基本与Set Map相同 api也相同
-
weakSet存储的数据只能是对象
-
weakMap只允许接收对象类型的key
-
RegExp
- es6中的y修饰符是什么含义
- es5支持y修饰符吗
const s = 'aaa_aa_a'
const r1 = /a+/g //全局语法任意位置匹配
const r2 = /a+/y //sticky 粘连 就是要从剩余的_aa_a中匹配,因为是下划线所以匹配为空 匹配要连续
console.log(r1.exec(s)) //aaa
console.log(r2.exec(s)) //aaa
console.log(r1.exec(s)) //aa
console.log(r2.exec(s)) //null
- es5如何在正则中处理中文问题 如果是多个字节
- es6中如何处理
//unicode u修饰符
let s = '𠮷'
let s2 = '\uD842\uDFB7'
console.log(/^\uD842/.test(s2))
console.log(/^\uD842/u.test(s2)) //遇到中文字符的时候加u
console.log(/^.$/.test(s)) //.匹配任意字符
console.log(/^.$/u.test(s))
//unicode码点怎么在正则中使用 u+20BB7
console.log(/\u{20BB7}/u.test(s))
console.log(/\u{61}/u.test('a'))
console.log(/𠮷{2}/u.test('𠮷𠮷'))
console.log(/[a-z]/i.test('\u212A'))
console.log(/[a-z]/iu.test('\u212A'))
http://www.fileformat.info/info/unicode/char/20bb7/index.htm
阅读
unicode及编码方式概述
unicode转utf-16的转码公式
sticky
练习
sticky模式有什么实际应用场景
上面提到的\uD842\uDFB7 是四个字节 加上u标识符会正确的识别出是两个字符,在javascript里一个字符是多少字节
U+20BB7是如何计算出\uD842\uDFB7
- Template
- es5中字符串换行,包含变量或表达式,包含逻辑运算怎么办
- es6怎么做的
const a = 20
const b =10
const c = 'javascript'
//es5
const str = 'my age is' + (a+b) + 'i love' + c
//es6
const str = `my age is ${a+b} i love ${c}`
console.log(str)
//es5
const retailPrice = 20
const wholeSalePrice = 16
const type = 'retail'
let showTxt = ''
if(type === 'retail'){
showTxt = '您此次的购买单价是:'+ retailPrice
}else{
showTxt = '您此次的购买批发价是:'+wholeSalePrice
}
console.log(showTxt)
//es6
function Price(strings,type){
let s1 = strings[0]
const retailPrice = 20
const wholeSalePrice = 16
let showTxt = ''
if(type === 'retail'){
showTxt = '购买单价是:'+ retailPrice
}else{
showTxt = '购买批发价是:'+wholeSalePrice
}
return `${s1}${showTxt}`
}
let showTxt =Price`您此次的${'retail'}`
console.log(showTxt)
//es5
let s1 ='第一行'+
'第二行'
//es6
let s1 = `第一行
我是第二行`
console.log(s1)
练习
用Tag函数解决业务中的一个字符串模板问题
- destructure
- es5从一个复杂的数据结构中提取数据是如何做的
- es6如何去做
- 解构赋值
let arr = ['hello','world']
let firstName = arr[0]
let surName = arr[1]
console.log(firstName,surName)
let arr = ['hello','world']
let [firstName,surName] = arr
console.log(firstName,surName)
let arr = ['a','b','c','d']
let[firstName,,thirdName] = arr
console.log(firstName,thirdName)
let arr = 'abcd'
let[firstName,,thirdName] = new Set([1,2,3,4]) //一般支持可遍历的
console.log(firstName,thirdName)
let user = {name:'s',surName:'t'};
[user.name,user.surName] = [1,2]
console.log(user)
//循环
let arr = ['hello','world']
for(let i =0;i<arr.length;i++){
item = arr[i]
console.log(item)
}
let user ={name: 's',surName:'t'}
for(let [k,v] of Object.entries(user)){
console.log(k,v)
}
let arr =[1,2,3,4,5,6,7,8,9]
let [firstName,curName, ...last] = arr
console.log(firstName,curName,last)
let arr =[]
let [firstName = 'hello',curName, ...last] = arr
console.log(firstName,curName,last)
- 对象的解构赋值
//Object
let options = {
title: 'menu',
width: 100,
height: 200
}
let{title:title2,width,height} = options
console.log(title2,width,height)
let options = {
title: 'menu',
width: 100,
height: 200
}
let{title,...last} = options
console.log(title,last)
let options = {
size:{
width: 100,
height: 200
},
items: ['cake','donut'],
extras: true
}
let { size:{width: width2, height}, items: [item1] ,extras} = options
console.log(width2,height,item1,extras)
练习
一个函数需要传入很多参数,是否可以利用解构赋值来简化操作
如何在业务开发中对接口数据进行解构赋值
- Promise
- es5中的回调地狱 a回调b b回调c c回调d
- es6是如何通过异步操作来实现的
//es5中的异步加载js
function loadScript (src) {
let script = document.createElement('script') //向页面动态创建一个dom节点
script.src = src
document.head.append(script)
}
function test(){ //等1.js加载完成之后再让test执行
console.log('test')
}
loadScript('1.js') //js单线程 加载js后,异步操作放到异步队列中执行,会立马执行test()
test()
————————————————————————————————————————————————————————————
加载一个js文件
function loadScript (src,callback) {
let script = document.createElement('script')
script.src = src
//script.οnlοad=function (){callback()}
script.onload = ()=>{
callback()
}
document.head.append(script)
}
function test(){
console.log('test')
}
loadScript('1.js',test)
——————————————————————————————————————————————————————————————
es5中加载多个js文件
function loadScript (src,callback) {
let script = document.createElement('script')
script.src = src
//script.οnlοad=function (){callback()}
script.onload = ()=>{
callback()
}
document.head.append(script)
}
function test(){
console.log('test')
}
loadScript('1.js',function(script){
loadScript('2.js',function(script){
loadScript('3.js',function(script){
})
})
})
function loadScript(src){
//pending undefined
return new Promise((resolve,reject)=> {
let script = document.createElement('script')
script.src = src
script.onload = () => resolve(src) //fullfilled result
script.onerror = () => reject(err) //rejected error
document.head.append(script)
})
}
loadScript('1.js').then(loadScript('2.js')).then(loadScript('3.js'))
//promise.then(onFullfilled,onRejected)
-
then的语法
- .then是promise对象原型上方法,只要是promise对象就可以调用.then方法
- 支持的语法then(onFullfilled,onRejected)对应着 resolve()与reject()
- (onFullfilled,onRejected)两个参数都为函数类型(第一个必选,第二个可选)
- 这里loadScript(‘2.js’)不是方法 而是方法的返回值
- 如果onFullfilled,onRejected这两个参数被遗漏或着不是函数 则忽略掉这两个内容
- loadScript(‘2.js’)表达式会被计算 所以执行了
-
为什么then可以链式调用
- then是返回一个新的promise实例
- 没有onFullfilled,onRejected这两个参数时(非函数),返回一个新的空promise对象
1.js 2.js 3.js执行的过程
loadScript('1.js')
.then(() =>{
return loadScript('4.js') 返回一个promise对象
//注意加return与不加return时的情况区别
},(err) => {
console.log(err)
})
.then(()=>{
loadScript('3.js')
},(err)=>{
console.log(err)
})
- 把一个数字转换成promise对象
- 使用Promise.resolve()与Promise.reject()静态方法
function test(bool){
if(bool){
return new Promise((resolve,reject)=>{
resolve(30)
})
}else{
return Promise.resolve(42) //可以将非异步操作转换成异步操作
}
}
test(1).then((value) =>{
console.log(value)
})
function test(bool){
if(bool){
return new Promise((resolve,reject)=>{
resolve(30)
})
}else{
return Promise.reject(new Error('ss')) //可以将非异步操作转换成异步操作
}
}
test(0).then((value) =>{
console.log(value)
},(err)=>{
console.log(err)
})
- promise对异常的处理
- catch是promise对象原型链上的方法
- 捕获链式操作上reject抛出的异常
function loadScript(src){
//pending undefined
return new Promise((resolve,reject)=> {
let script = document.createElement('script')
script.src = src
script.onload = () => resolve(src) //fulfilled result
script.onerror = (err) => reject(err) //rejected error
document.head.append(script)
})
}
loadScript('1.js')
.then(() =>{
return loadScript('4.js') //返回一个promise对象
})
.then(()=>{
return loadScript('3.js')
})
.catch((err) =>{ //catch是promise对象原型链上的方法 捕获链式操作上reject抛出的异常
console.log(err)
})
- promise并行异步操作
//模拟三个并发场景
const p1 = Promise.resolve(1)
const p2 = Promise.resolve(2)
const p3 = Promise.resolve(3) //不用关心哪个数据先返回
Promise.all([p1,p2,p3]).then((value) =>{ //Promise.all返回的还是一个Promise对象
console.log(value)
})
- promise 竞争 线路1 线路2 先到先得
//竞争 先到先得 1线路 2线路
const p1 = () =>{
return new Promise((resolve,reject) =>{
setTimeout(function(){
resolve(1)
},1000)
})
}
const p2 = () =>{
return new Promise((resolve,reject) =>{
setTimeout(function(){
resolve(2)
},0)
})
}
Promise.race([p1(),p2()]).then((value)=>{
console.log(value)
})
练习
按顺序加载脚本的代码不太直观看出顺序执行的过程,如果按顺序延时执行是不是更好理解
请用Promise实现一个接口
- reflect 反射
- 什么是反射机制
- java的反射机制是在编译阶段不知道哪个类被加载,而是在运行的时候才加载,执行
console.log(Math.floor.apply(null,[3.72]))
console.log(Reflect.apply(Math.floor,null,[3.72]))
let price =91.5
if(price >100){
console.log(Math.floor.apply(null,[price]))
}else{
console.log(Math.ceil.apply(null,[price]))
}
console.log(Reflect.apply(price>100 ? Math.floor : Math.ceil,null,[price]))
let d = new Date()
console.log(d.getTime)
let d = Reflect.construct(Date,[]) //调用不同的类 去动态实例化对象
console.log(d.getTime(),d instanceof Date)
const student = {}
const r1 =Object.defineProperty(student,'name',{value:'mike1'})
console.log(student,r1)
const r2 =Reflect.defineProperty(student,'name',{value:'mike2'})
console.log(student,r2)
const obj = {x:1,y:2}
Reflect.deleteProperty(obj,'x')
console.log(obj)
console.log(Reflect.get(obj,'y'))
console.log(Reflect.get([3,4],1))
//获取对象下的属性的标识符
const obj = {x:1,y:2}
console.log(Reflect.getOwnPropertyDescriptor(obj,'y'))
console.log(Object.getOwnPropertyDescriptor(obj,'x'))
//获取某个对象的原型对象是什么
let d = new Date()
console.log(Reflect.getPrototypeOf(d))
//判断对象上有无该属性
const obj1 = {x:1,y:2}
console.log(Reflect.has(obj1,'x')) //has方法Object没有
//判断对象是否可扩展
Object.freeze(obj) //冻结obj 使其不可扩展 不能新增属性了
console.log(Reflect.isExtensible(obj))
//判断某个对象下的自由属性 自身属性 不是原型链的属性
console.log(Reflect.ownKeys(obj))
console.log(Reflect.ownKeys([1,2]))
//Reflect提供的禁止扩展的api
Reflect.preventExtensions(obj)
console.log(Reflect.isExtensible(obj))
// Reflect set
const obj2 = {x:1,y:2}
Reflect.set(obj2,'z',4)
console.log(obj2)
const arr = ['duck','duck','duck']
Reflect.set(arr,2,'goose')
console.log(arr)
//修改实例对象的原型对象
const arr1 = ['duck','duck','duck']
console.log(Reflect.getPrototypeOf(arr))
Reflect.setPrototypeOf(arr,String.prototype)
console.log(Reflect.getPrototypeOf(arr))
- Proxy
- 代理功能
- 中介场景
let o = {
name :'xiaoming',
price: 190
}
let d = new Proxy(o,{ //代理相当于中介 中间商赚差价
get(target,key){ //target就是我们代理的对象
if(key === 'price'){
return target[key]+20
}else{
return target[key]
}
}
}) //第一个参数你要代理谁 第二个参数代理后能做什么
console.log(d.price,d.name)
//后端数据排序后 进行还原 (只读不可写)
let o = {
name :'xiaoming',
price: 190
}
let d = new Proxy(o,{
get(target,key){
return target[key]
},
set(target,key,value){
return false; //不让你赋值
}
})
d.price =300 //没起作用 拦截了赋值操作 暴露的是d 而不去暴露o
console.log(d.price,d.name)
es5中的操作方法
let o = {
name :'xiaoming',
price: 190
}
for(let [key] of Object.entries(o)){
Object.defineProperty(o,key,{
writable:false
})
}
o.price =300 //不起作用
console.log(o.name,o.price)
//有不合理的操作,如何保护我们的数据 校验
//数据结构不会被破坏 写数据时校验规则
let o = {
name :'xiaoming',
price: 190
}
let d = new Proxy(o,{
get(target,key){
return target[key] || ''
},
set(target,key,value){
if(Reflect.has(target,key)){
if(key ==='price'){
if(value >300){
return false
}else{
target[key] =value
}
}else{
target[key] =value
}
}else{
return false;
}
}
})
d.price = 400
d.name = 'chen'
d.age = 400
console.log(d.price,d.name,d.age)
//解耦
let o = {
name :'xiaoming',
price: 190
}
let validator = (target,key,value) =>{
if(Reflect.has(target,key)){
if(key ==='price'){
if(value >300){
return false
}else{
target[key] =value
}
}else{
target[key] =value
}
}else{
return false;
}
}
let d = new Proxy(o,{
get(target,key){
return target[key] || ''
},
set: validator
})
d.price = 400
d.name = 'chen'
d.age = 400
console.log(d.price,d.name,d.age)
//监听错误
window.addEventListener('error',(e) =>{
console.log(e.message)
// report('/') 上报逻辑
},true)
//提升用户体验 监控违规操作 触发报错
let o = {
name :'xiaoming',
price: 190
}
//校验规则
let validator = (target,key,value) =>{
if(Reflect.has(target,key)){
if(key ==='price'){
if(value >300){
//不满足规则就要触发错误
throw new TypeError('price 超过了 300')
}else{
target[key] =value
}
}else{
target[key] =value
}
}else{
return false;
}
}
let d = new Proxy(o,{
get(target,key){
return target[key] || ''
},
set: validator
})
d.price = 400
d.name = 'chen'
d.age = 400
console.log(d.price,d.name,d.age)
//给主键随机生成id 只读且唯一
class Component{
// constructor(){
// this.id = Math.random().toString(36).slice(-8)
// } 不行
// get id() {
// return Math.random().toString(36).slice(-8)
// } 不行
constructor(){
this.proxy = new Proxy({
id:Math.random().toString(36).slice(-8)
},{})
}
get id(){
return this.proxy.id
}
}
let com1 = new Component()
let com2 = new Component()
for(let i =0; i<10;i++){
console.log(com1.id,com2.id)
}
com1.id = 'abc'
console.log(com1.id,com2.id)
- 在代理使用过程中 如何撤销代理
//如何撤销代理
let o = {
name :'xiaoming',
price: 190
}
let d = Proxy.revocable(o,{ //现在d包含代理的数据 以及撤销的操作 不仅仅是数据了
get(target,key){
if(key === 'price'){
return target[key]+20
}else{
return target[key]
}
}
})
console.log(d.proxy.price,d)
setTimeout(function(){
d.revoke()
setTimeout(function(){
console.log(d.proxy.price)
},100)
},1000)
练习
组件初始化的时候都赋值一个可读且随机的id 该怎么做
临时代理有哪些应用场景
如何把接口的数据用代理进行包装
- Generator
- es6如何让遍历停下来
//es5循环
// function loop(){
// for(let i =0; i<5;i++){
// console.log(i)
// }
// }
// loop()
//es6
function * loop(){
for(let i =0; i<5;i++){
yield console.log(i) //使用yield暂停函数的运行
}
}
const l = loop()
l.next()
l.next()
function * gen(){
let val
val = yield 1
console.log(val)
}
const l = gen()
l.next() //next找yield或者函数结尾 就会暂停或者结束
l.next()
function * gen(){ //generator是一个函数 比普通函数多了*
let val
val = yield * [1,2,3] //加*表示后面是个可遍历的对象
console.log(val)
}
const l = gen()
console.log(l.next()) //会返回当前执行的状态与结果
console.log(l.next())
function * gen(){
let val
val = yield [1,2,3]
console.log(val)
}
const l = gen()
console.log(l.next(10))
console.log(l.next(20))
function * gen(){
let val
val = (yield [1,2,3])+7
console.log(val)
}
const l = gen()
console.log(l.next(10))
console.log(l.return(100))
console.log(l.next(20))
//es5 抽奖
function drow(first=1,second = 2,third = 3){
let firstPrice = ['1A','1B','1C','1D','1E'];
let secondPrice = ['2A','2B','2C','2D','2E','2F','2G'];
let thirdPrice = ['3A','3B','3C','3D','3F','3G','3H','3I','3Q','3S'];
let result =[]
let random
//抽一等奖
for (let i = 0; i < first; i++) {
random = Math.floor(Math.random()*firstPrice.length)
console.log(Math.random()*firstPrice.length,random)
result = result.concat(firstPrice.splice(random,1))
}
for (let i = 0; i < second; i++) {
random = Math.floor(Math.random()*secondPrice.length)
result = result.concat(secondPrice.splice(random,1))
}
for (let i = 0; i < third; i++) {
random = Math.floor(Math.random()*thirdPrice.length)
result = result.concat(thirdPrice.splice(random,1))
}
return result
}
let d = new drow()
for(let value of d){
console.log(value)
}
//es6
function * drow(first=1,second = 2,third = 3){
let firstPrice = ['1A','1B','1C','1D','1E'];
let secondPrice = ['2A','2B','2C','2D','2E','2F','2G'];
let thirdPrice = ['3A','3B','3C','3D','3F','3G','3H','3I','3Q','3S'];
let count = 0
let random
while(1){
if(count<first){
random = Math.floor(Math.random()*firstPrice.length)
yield firstPrice[random]
count++
firstPrice.splice(random,1)
}else if(count<first+second){
random = Math.floor(Math.random()*secondPrice.length)
yield secondPrice[random]
count++
secondPrice.splice(random,1)
}else if(count<first+second+third){
random = Math.floor(Math.random()*thirdPrice.length)
yield thirdPrice[random]
count++
thirdPrice.splice(random,1)
}else{
return false
}
}
}
let d = drow()
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
console.log(d.next().value)
//数到3的倍数就加1
function * count(x = 1){
while(1){
if(x%3===0){
yield x
}
x++
}
}
let c = count()
console.log(c.next().value)
console.log(c.next().value)
console.log(c.next().value)
练习
用generator实现一个斐波那契数列
用generator给自定义数据结构写一个遍历器
- Iterator
- 如何让不支持遍历的数据结构"可遍历"
es5遍历方法
let authors ={
allAuthors: {
a:['克莱尔','东野圭吾','lp'],
b:['neal','arthru','ribert'],
c:['j.r.tole','j.m.r','terry p.k']
},
address:[]
}
let r =[]
for(let [,v] of Object.entries(authors.allAuthors)){
r = r.concat(v)
}
console.log(r)
es6遍历实现
let authors ={
allAuthors: {
a:['克莱尔','东野圭吾','lp'],
b:['neal','arthru','ribert'],
c:['j.r.tole','j.m.r','terry p.k']
},
address:[]
}
authors[Symbol.iterator] = function (){
let allAuthors = this.allAuthors
let keys = Reflect.ownKeys(allAuthors)
let values = []
return {
next(){
if(!values.length){
if(keys.length){
values = allAuthors[keys[0]]
keys.shift()
}
}
return{
done:!values.length,
value:values.shift()
}
}
}
}
let r =[]
for(let v of authors){
r.push(v)
}
console.log(r)
使用generator改造遍历
authors[Symbol.iterator] = function * (){
let allAuthors = this.allAuthors
let keys = Reflect.ownKeys(allAuthors)
let values = []
while(1){
if(!values.length){
if(keys.length){
values = allAuthors[keys[0]]
keys.shift()
yield values.shift()
}else{
return false
}
}else{
yield values.shift()
}
}
}
练习
什么是自定义遍历 如果有复杂的数据结构会使用自定义遍历吗
什么是迭代协议 可迭代协议
generator和iterator的关联关系理解了吗
- Module
- es6如何把代码进行模块化设计
基本的导入导出
// export const name ='hello'
// export let addr = 'beijing'
// export var list = [1,2,3]
const name ='hello'
let addr = 'beijing'
var list = [1,2,3]
export default name //默认导出只有一个
export {
addr,
list
}
_______________________________________________________________
import name,{addr as addr2,list} from 'lesson2-19-mod'
console.log(name,addr2,list)
- 导入导出函数
export function say(content){
console.log(content)
}
export function run(){
console.log('running')
}
import {say,run} from 'lesson2-19-mod'
say('hello world')
run()
- 导出一个对象
export default {
code: 1,
message: 'success'
}
import obj from 'lesson2-19-mod'
console.log(obj)
- 导入导出多个对象
const data = {
code:1,
message: 'success'
}
const des = {
age : 20,
addr: 'beijing'
}
export default {
data,
des
}
import obj from 'lesson2-19-mod'
let {data,des} = obj
console.log(data,des)
- 类的导入导出
class Test{
constructor(){
this.id = 2
}
}
// export default Test
export{
Test
}
import {Test} from 'lesson2-19-mod'
let test = new Test()
console.log(test.id)
___________________________________
默认导入导出
export default class{
constructor(){
this.id = 2
}
}
import Test from 'lesson2-19-mod'
let test = new Test()
console.log(test.id)
- 导入导出多个类
export class Test{
constructor(){
this.id = 2
}
}
export class Animal{
constructor(){
this.name = 'dog'
}
}
export default class People{
constructor(){
this.id = '132'
}
}
import * as mod from 'lesson2-19-mod'
let test = new mod.Test()
console.log(test.id)
let animal = new mod.Animal()
console.log(animal.name)
let people = new mod.default()
console.log(people.id)
被导出的模块是否能在本模块使用
export function say(){
console.log('hello')
}
export function run(){
say()
}