柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • 前端必备

    • HTML
    • CSS
    • JavaScript
    • ES6
      • 变量
        • 作用域
        • 空值运算符
        • 逻辑赋值操作符
      • 字符串拓展
        • 字符串方法
        • 模板字符串
      • 数组拓展
        • 数组复制
      • 正则拓展
        • 正则方法
      • 对象拓展
        • 对象简写
        • 属性名表达式
        • 拓展运算符
        • 可选链操作符
        • 对象方法
        • 私有特征
      • 函数拓展
        • 装配参数
        • 剩余参数
        • 函数Name
        • 箭头函数
      • Symbol
        • 遍历Symbol
      • Iterator
      • Set
      • Map
      • Proxy
      • Promise
        • Promise方法
        • Promise.all()
        • Promise.race()
        • Promise手写
      • Generator
      • Class
      • Modlule
        • 动态导入
      • 异步遍历器
      • WeakRefs
      • 异常捕获
    • Git
  • 技术拓展

  • 前端技巧

  • Vue

  • 前端
  • 前端必备
柏竹
2020-02-18
目录

ES6

ES6 是 JavaScript 语言的标准 , 可以编写些复杂的大型项目 (企业级)

教程网站 : 点击跳转 (opens new window)

# 变量

# 作用域

如果变量定义在 花括号{} 内 , 那么该 变量的作用范围也就仅限于 花括号{}内 (let定义)

if(true){
    let i = 10;
}
// 无法打印
console.log(i);

如果变量采用 var 导致为全局变量

var与let区别

var let
重复声明 允许(旧覆盖新) 不允许
作用范围 全局范围 仅限花括号内
声明提前(声明前调用) 允许(但不会显示数据) 不允许

# 空值运算符

空值合并运算符 ?? (和 || , && 用法一样) , 当左侧变量为 null/undefined 时 , 返回右侧变量 , 否则返回左侧

示例 : (可通过以下代码区分 || 和 ?? 区别)

console.log(undefined || "Sans") // Sans
console.log(undefined ?? "Sans") // Sans
console.log(NaN || "Sans") // Sans
console.log(NaN ?? "Sans") // NaN
console.log(null || "Sans") // Sans
console.log(null ?? "Sans") // Sans
console.log(0 || "Sans") // Sans
console.log(0 ?? "Sans") // 0

# 逻辑赋值操作符

逻辑赋值操作符 ??= , &&= , ||= , 可在判断的时候进行赋值

let a = true;
let b = false;
a ||= b // a = a || b; (true)
a &&= b // a = a && b; (false)
let obj = {name:'Sans'}
obj.age ??= 22
consoel.log(obj.age) // 22

# 字符串拓展

# 字符串方法

对象方法示例 : 点击跳转 (opens new window)

方法 说明
str.padStart(number, string) 在开头填充指定字符直到number的长度
str.padEnd(number, string) 在末尾填充指定字符直到number的长度
str.trimStart() 清除开头的所有空格符
str.trimEnd() 清除结尾的所有空白符
str.replace(reg , targetStr) 按正则替换为targetStr
str.replaceAll(replaceStr , targetStr) 将所有replaceStr替换为targetStr

# 模板字符串

教程 : 点击跳转 (opens new window)

以往在拼接 H5标签时 , 是通过 ""/' 引号的 , 如果添加了换行和变量 , 那么会显得很难阅读 .

模板字符串正式解决了这一痛点

let name = 'Sans';
// 引号拼接
let node = "<span>\
	<b>" + name + "</b>\
	</span>";

// 模板字符串 (支持表达式)
let node2 = `<span>
		<b>${name}</b>
	</span>`;

let node3 = `<span>
		<b>${name===''?'名称不存在':name}</b>
	</span>`;

// 原型 <span><b>Sans</b></span>

# 数组拓展

拓展运算符 用法展示 :

let arr = [1,2,3];

// 复制
let arr2 = [...arr];

// 提取
let {a,..b} = arr;
console.log(a,b) // 1 [2,3]

Array.from()

arguments可以在形参中获取没有实参中的内容 , 但获取到的数据并非是数组形式 , 需要借助 ==Array.from()== 能够将 类数组结构 转换为 数组

function test(){
    console.log(Array.from(arguments))
}
test(1,2,3,4)

Array.flat()

数组扁平化 . 进行将递归层级的数组进行降维

// 案例1
let arr = [
    ['北京','上海','广州'],
    ['南京','厦门','南宁']
]
console.log(arr.flat()); // ['北京','上海','广州','南京','厦门','南宁']

// 案例2
let arr2 = [{
        name: "A",
        list: ['北京','上海','广州']
    },{
        name: "B",
        list: ['南京','厦门','南宁']
    }];
let res = arr2.flatMap(item => {
    return item.list;
})
console.log(res); // ['北京','上海','广州','南京','厦门','南宁']

at()

拿取指定索引数据 , 负数则为倒数元素进行索引 , 字符串也可以行

let arr = ['no1','no2','no3','no4']
console.log(arr.at(0)) // arr[0] (no1)
console.log(arr.at(-1)) // arr[arr.length-1] (no4)

# 数组复制

以下数组复制 , 只是复制了指针 , 并非开辟内存空间

const a1 = [1, 2];
const a2 = a1;

a2[0] = 2;
a1 // [2, 2]

以下代码 , 复制形式 开辟了内存空间

const a1 = [1, 2];
const a2 = a1.concat();
const a3 = [...a1]

a2[0] = 2;
a1 // [1, 2]

# 正则拓展

教程 : 点击跳转 (opens new window)

# 正则方法

方法 说明
str.match() 获取 正则匹配值 的数组 (全局匹配末尾加g)
str.matchAll(reg) 获取 正则匹配值 的数组
str.replace() 获取 正则匹配值替换预期值 的新字符串
str.search() 获取 正则匹配的首个索引 , 不存在 -1
str.test() 是否有 正则匹配值
str.exec(str) 获取 正则匹配值 的数组 (详细
// ES6 新特性 exec()
let str = "今天是2022-11-11";
// exec()
console.log(/[0-9]{4}-[0-9]{2}-[0-9]{2}/.exec(str)) // ['2022-11-11', index: 3, input: '今天是2022-11-11', groups: undefined]
console.log(/([0-9]{4})-([0-9]{2})-([0-9]{2})/.exec(str)) // ['2022-11-11', '2022', '11', '11', index: 3, input: '今天是2022-11-11', groups: undefined]
console.log(/(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/.exec(str)) // ['2022-11-11', '2022', '11', '11', index: 3, input: '今天是2022-11-11', groups: {day: '11',month: '11',year: '2022'}]
// ES6 新特性 matchAll()
let str = `
<ul>
	<li>111</li>
	<li>222</li>
	<li>333</li>
	<li>444</li>
</ul>
`;

let reg = /<li>(?<content>.*)<\/li>/g;
for(let item of str.matchAll(reg)){
    console.log(item.groups.content)
}
/*
111
222
333
444
*/

# 对象拓展

# 对象简写

const foo = 'bar';
const baz = {
    foo,
    name: 'Sans',
    test(){...}
};

# 属性名表达式

可以通过变量进行定义变量名

let name = 'sans'
let obj = {
    [name]: 'zs'
}
console.log(obj); // {sans: 'zs'}

# 拓展运算符

可以跟数组一样 使用 ... 进行操作

let obj1 = {name: 'zs'};
let obj2 = {age: 12};
console.log({...obj1, ...obj2});

// 等同于 
// {}空对象 是将 obj1和obj2分别合并到新的空对象
console.log(Object.assign({}, obj1, obj2));

# 可选链操作符

可选链操作符 ? , 作用是 判断操作符前面的变量是否为 null/undefined , 如果是 则不会进行往后的链式调用

let obj1 = {
    name: 'sans',
    location: {
        city:'广东'
    }
}
let obj2 = {
    name: 'sans'
}

console.log(obj1.location.city) // 广东
console.log(obj2.location.city) // 报红
console.log(obj2?.location?.city ?? '这人很懒,啥也没写') // undefined

意图 : 尽可能避免没有意义的报红警告

# 对象方法

对象方法示例 : 点击跳转 (opens new window)

方法 说明
Object.assign(targetObj, ...sourceObj) 克隆对象 ( 可拷贝多个对象至目标对象)
Object.is(obj1, obj2) 比较对象 (比 == , === 更为严谨)
Object.keys(obj) 获取 对象所有属性名 的数组
Object.values(obj) 获取 对象所有属性值 的数组
Object.entries(obj) 获取 对象所有 属性名和属性值 的二维数组
Object.getOwnPropertyDescriptors() 获取 获取所有属性描述信息
Object.fromEntries(arr) 将 键值对的二维数组/Map对象 转为对象 (逆操作)

Object.fromEntries()

// 用法1
let arr = [['name','zs'],['age',22]];
console.log(Object.fromEn tries(arr))
// 用法2
let map = Map();
map.set("name","zs");
map.set("age",22);
console.log(Object.fromEntries(map))
// 用法3
let str = "name=zs&age=22"
let seatchParams = new URLSearchParams(str);
console.log(Object.fromEntries(seatchParams))
// 用法4
let obj = {
    "广东": ["广州","佛山","深圳"],
    "广西": ["南宁","贵港"],
    "江苏": ["南京"]
}
let myarr = Object.entries(obj)
let mynewarr = myarr.map(([key,value])=>{
    []
})
console.log(Object.fromEntries(myarr))

# 私有特征

ES13更新中的新功能 , 通过在 变量/方法 前面添加 # 代表私有 , 不过访问是需要调用内部方法进行访问

class people{
    #obj = {}
    
    get(key){
        return this.#obj[key]
    }
    set(key, value){
        this.#obj[key] = value
    }
}

let store = new people();
store.set("name","Sans");
store.set("age",22);

// console.log(store.#obj) 报红
console.log(store)

# 函数拓展

# 装配参数

函数可以定义可选默认值

// url必选 , 其余可选
function ajax(url, method="get", async=true){....}
ajax("/test");
ajax("/test", 'post');
ajax("/test", 'post', false);

# 剩余参数

多个变量的时候可以采用 ...

function test(...arr){
    console.log(arr); //[1,2,3,4]
}
test(1,2,3,4);
let obj {
    code: 200,
    data: "zs"
}
let {name, ...others} = obj

应用场景 ()

function ajax(options){
    const defaultOptions = {
        methods: 'get',
        async: true
    }
    options = {...defaultOptions, ...options}
    ...
}
ajax({
    url: '...'
})

# 函数Name

函数变量可以通过 name属性 进行获取 函数的名称

function test(){....}
console.log(test.name)

# 箭头函数

简写函数的作用

let test = function(e){...}
let test = (e)=>{...}

简写情况 :

  • 参数只有一个的情况 ; 省略 方法括号 ()
  • 函数体只有一条语句的情况 ; 省略返回 return

注意 :

  • 函数体只有一条语句的情况且是返回一个对象 , 必须在对象外的 {}花括号 加上 ()括号
  • 箭头函数没有this , this是访问父作用域 (箭头函数应用严紧)

# Symbol

Symbol 是一种新的 原始数据类型 , 表示独一无二的值 !

// 实例 Symbol类型数据
let s = Symbol();
console.log(typeof s)

let s2 = Symbol();
console.log(s === s2) // false

Symbol实例中可添加参数 作为标识 (方便理解) ==let s = Symbol('name')==

这一特性解决了 属性名的冲突 问题 , 示例 :

let obj = { name : 'sans' }

let name = Symbol('name');
obj[name] = 'zs';

console.log(obj[name]) // zs
console.log(obj.name) // sans

主要意图是 该对象别人使用相同名称时 , 可防止冲突 , 因此 封装者 一般会采用这种方式

规范用法

let keys = {
	name: Symbol('name'),
    age: Symbol('age'),
    test: Symbol('test')
}
let obj = {
    [keys.name]: 'Sans',
    [keys.age]: 22,
    [keys.test]() {
        console.log('方法测试');
    }
}
console.log(obj);
obj[keys.test]();

# 遍历Symbol

Symbol属性名 不能被 for...in/for...of 遍历 , 也不会被Object.keys()/Object.getOwnPropertyNames()/JSON.stringify()返回

Object.getOwnPropertySymbols() 获取指定对象的所有Symbol属性名

Reflect.ownKeys() 获取指定对象的所有属性

let obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj.name = 'sans';
obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);
const reflectSymbols = Reflect.ownKeys(obj);

console.log(objectSymbols) // [Symbol(a), Symbol(b)]
console.log(reflectSymbols) // ['name', Symbol(a), Symbol(b)]

// 遍历
reflectSymbols.forEach(item =>{
    console.log(item,'=>',obj[item])
})

注意 :

  • 不能进行运算
  • toString()打印显示 实例本身
  • 隐式转换boolean
  • map不能遍历 Symbol类型

# Iterator

教程 : 点击跳转 (opens new window)

Iterator迭代器 是一种机制 , 为不同数据结构提供了统一的访问机制

let arr = ['zs','ls','ww'];
let i = arr[Symbol.iterator]();
console.log(i.next()); // {value: 'zs', done: false}
console.log(i.next()); // {value: 'ls', done: false}
console.log(i.next()); // {value: 'ww', done: false}
console.log(i.next()); // {value: undefined, done: true}

原生具备 Iterator接口 的数据结构 :

  • Array
  • Set
  • Map
  • String (每个字符的遍历)
  • arguments对象
  • NodeList对象

ES6规定 , Iterator接口默认在数据结构的 Symbol.iterator属性 (本身是个迭代器生成函数)

数据结构如果具备有 Symbol.iterator属性 那么可认为是 可遍历的

对 Object类型对象 封装 仅限访问

let list = Symbol('list');
let obj = {
    code: 200,
    name: 'sans',
    // 仅限访问list
    [list]: ['zs','ls','ww'],

    // 迭代器 访问
    [Symbol.iterator](){
        let index = 0;
        return {
            // 迭代器包含有 next()
            // 采用箭头函数原因 : this越过函数本身 , 引用对象
            next: ()=>{
                return{
                    value: this[list][index++],
                    done: index>=(this[list].length+1)?true:false
                }
            }
        }
    }
}

// 迭代器测试
let i = obj[Symbol.iterator]();
console.log(i.next()) // { value: 'zs', done: false }
console.log(i.next()) // { value: 'ls', done: false }
console.log(i.next()) // { value: 'ww', done: false }
console.log(i.next()) // { value: undefined, done: true }
console.log(i.next()) // { value: undefined, done: true }

// for..of遍历
for(item of obj){
    console.log(item) 
}

# Set

Set类似数组结构 , 但成员的值都是唯一的 , 没有重复的值

let set = new Set([1,2,3,2,4,4,5,5]);
console.log(s); // Set(5) { 1, 2, 3, 4, 5 }
// 转Array
let arr = [...set];
let arr2 = Array.from(set);

Set基本属性和方法

  • size : 获取Set总数
  • Set.prototype.add(value) : 添加值
  • Set.prototype.delete(value) : 删除值
  • Set.prototype.has(value) : 判断是否包含有
  • Set.prototype.keys() : 获取键名 遍历器
  • Set.prototype.values() : 获取值 遍历器
  • Set.prototype.entries() : 获取键值对 遍历器
  • Set.prototype.forEach() : 遍历每个成员

数组手写去重

let set = [11,2,3,'sans',{name:'sans'},{name:'ww'},{name:'sans'},11,123123,undefined,NaN,NaN]

// 方式1
function uni(arr){
	let res = new Set();
	return set.filter(item =>{
		let id = JSON.stringify(item);
		console.log('id',id)
		if(res.has(id)){
			return false;
		}else{
			res.add(id);
			return true;
		}
	})
}
console.log(uni(set));

//方式2
function uni2(arr){
    let res = new Set();
    arr.forEach(item => res.add(item));
    return res;
}
console.log(uni2(set));

//方式3
function uni3(arr){
    return [...new Set(arr)];
}
console.log(uni3(set));

# Map

Map类似对象结构 , 键值对的集合 , 但 键 可以是各种类型

let map = new Map([
    ['name','sans'],
    ['age',22]
])
// 等同于
let map2 = new Map();
map2.set('name','sans');
map2.set('age',22);
console.log(map); // Map(2) { 'name' => 'sans', 'age' => 22 }
console.log(map2); // Map(2) { 'name' => 'sans', 'age' => 22 }

Map基本属性和方法 包含有 Set应用的方法 点击跳转

# Proxy

Proxy代理 主要作用是 为对象设置个拦截 (监听) , 实时获取对象数据/设置对象数据 等操作

let obj = {};
let proxy = new Proxy(obj,{
    get(target, key){
    	console.log('get', target, key);
        return target[key];
    },
	set(target, key, value){
		console.log('set', target, key, value)
		target[key] = value;
	}
})

proxy.name='sans'
console.log(proxy.name)

其他类型的操作

let s = new Set();
let proxy = new Proxy(s,{
    get(target, key){
		let v = target[key];
		// 如果访问的是方法 , 修正this指向
		if(v instanceof Function) return v.bind(target);
        return v;
    },
	set(target, key, value){
		console.log('set', target, key, value)
	}
})

proxy.add('sans')
console.log(proxy) // Set(1) { 'sans' }

ES5 旧版 , 弊端仅限于对象的属性使用

let obj = {};

// 监听 obj对象的name属性 
Object.defineProperty(obj, "name", {
    get(){
        console.log('get')
    },
    set(){
        console.log('set')
    }
})

obj.name = 'sans'
console.log(obj.name)

# Promise

Promise是回调的升级版 , 在处理花费较长时间的任务时 , 使用 Promise 可以进行异步处理 , 防止堵塞

学习来源 : 点击跳转 (opens new window)

基本结构 :

// 参数封装有一个执行器函数
let pro = new Promise((resolve, reject)=>{
	if(true){
        resolve('succee');
    }else{
        reject('fail')
    }
})

pro.then( res =>{
    console.log('succee')
}).catch( err =>{
    console.log('fail')
}).finally(()=>{
	sonsole.log("一定执行的")
})

响应结构说明 :

  • Prototype : 原型类型
  • PromiseState : pending(等待) / fulfilled(完成) / rejected(拒绝)
  • PromiseResult : 响应数据

案例1 : (检测图片有效)

const imageUrl = '';

const imgPromise = (url) => {
    return new Promise( (resolve, reject) => {
        const img = new Image();
        img.src = url;
        // 加载成功
        img.onload = () => {
            resolve(img);
        }
        img.onerror = () => {
            reject(new Error('图片有误'));
        }
    } );
};

imgPromise(imageUrl)
	.then( img => {
    	console.log('success : ',img)
	})
	.catch(err => {
    	console.log('error: ',err)
	})

案例2 : (随机数判断)

new Promise((resolve, reject) => {
  setTimeout(() => {
      let num = Math.floor(Math.random() * 11);//0-10的随机数
  	  if (num >= 5) {
  	    resolve(num);
  	  } else {
  	    reject(num);
  	  }
  	},1000)
}).then(res => {
  console.log("执行了成功时的回调 , 数值为:"+ res);
}).catch(err => {
  console.log("执行了失败时的回调 , 数值为:"+ err);
})

# Promise方法

# Promise.all()

all()方法 用于处理多个异步任务 , 所有执行完后才调用then

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果1');
  }, 1000);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果2');
  }, 2000);
})

//Promise.all([])接收多个异步任务 , 放入数组中
Promise.all([p1, p2]).then(results => {//results接收多个参数 , 所以是数组
  console.log(results);//["结果1", "结果2"]
})

# Promise.race()

race()方法 当中的任务谁先完成就执行谁

let p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果1');
  }, 1000);
})
let p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('结果2');
  }, 2000);
})
//Promise.race([])中接收多个异步任务 , 放入数组中
Promise.race([p1, p2]).then(result => { //p1和p2 公用同一result , 谁先完成接收谁
  console.log(result);
})

# Promise手写

学习来源 : 点击跳转 (opens new window)

class Commitment {
    // 状态
    static PENDING = '待定';
    static FULFILLED = '成功';
    static REJECTED = '拒绝';
    // 构造方法
    constructor(func) {
        this.status = Commitment.PENDING;
        this.result = null;
        // 保存函数
        this.resolveCallbacks = [];
        this.rejectCallbacks = [];
        // 传入异常对象进行操作
        try {
            func(this.resolve.bind(this), this.reject.bind(this));
        } catch (err) {
            this.reject(err);
        }

    }
    // 失败
    resolve(res) {
        // 事件后执行
        setTimeout(() => {
            if (this.status === Commitment.PENDING) {
                this.status = Commitment.FULFILLED;
                this.result = res;
                this.resolveCallbacks.forEach(call => {
                    call(res)
                });
            }
        });
    }
    // 成功
    reject(res) {
        // 事件后执行
        setTimeout(() => {
            if (this.status === Commitment.PENDING) {
                this.status = Commitment.REJECTED;
                this.result = res;
                this.rejectCallbacks.forEach(call => {
                    call(res)
                });
            }
        });
    }
    then(onFULFILLED, onREJECTED) {
        return new Commitment((resolve, reject) => {
            // 不是函数则传递空函数
            onFULFILLED = typeof onFULFILLED === 'function' ? onFULFILLED : () => { };
            onREJECTED = typeof onREJECTED === 'function' ? onREJECTED : () => { };
            // 如果外部也使用了异步 , 很有可能还是 待定状态
            if (this.status === Commitment.PENDING) {
                this.resolveCallbacks.push(onFULFILLED);
                this.rejectCallbacks.push(onREJECTED);
            }
            if (this.status === Commitment.FULLFILLED) {
                // 异步处理
                setTimeout(() => {
                    onFULFILLED(this.result);
                })
            }
            if (this.status === Commitment.REJECTED) {
                // 异步处理
                setTimeout(() => {
                    onREJECTED(this.result);
                });
            }
        });
    }
}

// 测试实例
console.log('No.1');
let commitment = new Commitment((resolve, reject) => {
    console.log('No.2');
    setTimeout(() => {
        reject('这次一定');
        console.log('No.4');
    });
});
commitment.then(
    res => { console.log(res) },
    err => { console.log(err) }
)
console.log('No.3');

测试步骤说明 : (按照No.x步骤说明)

  1. (待定) new实例
  2. (待定) 异步操作 , 执行 then() , 由于是待定状态进行 数组保存函数(resolve/reject)
  3. (成功) 执行 reject() 里面还有一个异步处理(外部先执行了)
  4. (成功) 执行外部异步 , 最后和 reject() 共同跑完

# Generator

Generator函数 是ES6 的一种异步机制 . 可理解为状态机 (封装有多种状态)

示例 :

function *gen(){
	console.log(11)
	let res1 = yield
    console.log(`11接收到${res1}`)
	console.log(22)
	yield '33'
	console.log(33)
}

let g = gen()
let res1 = g.next()
let res2 = g.next('11')
let res3 = g.next()
console.log(res1,res2,res3) 
/**
11
11接收到11
22
33
{ value: undefined, done: false } { value: '33', done: false } { value: undefined, done: true }
 */

注意 :

  • 第一个传入参数是无意义
  • Generator作为理解 , 目前流行 Promise语法糖

# Class

JavaScript类的概念应用 和Java类似

示例 :

class Person{
    // 构造函数
    constructor(name, age){
        this.name = name
        this.age = age
    }
    
    say(){
        console.log(this.name, this.age)
    }
}

let person = new Person('sans',22);
person.say();

注意 :

  • 属性名也支持 属性名表达式用法 示例跳转
  • 属性和方法可以进行 state静态修饰
  • class可以 使用 extends 进行继承

# Modlule

JavaScript一直以来没有过模块化体系 , ES6为此增强了 , 提供了 Modlule模块化开发

ES6模块化重点解决了以下问题 :

  • 异步加载 (节点加载问题)
  • 私密不漏 (外部访问问题)
  • 重名不怕 (函数重名问题)
  • 依赖不乱 (循序调用问题)

Modlule模块化 功能由 export , import 关键字组成

  • export : 规定模块对外应用的接口 (俗称 暴露/导出)
  • import : 提取其他模块提供的接口 (俗称 引用/导入)

模块引用 (已模块化形式进行加载)

// 异步加载 (节点加载前 , 可直接访问节点)
<script src=".." type="module"></script>

如果其他模块访问也必须写上该属性 ==type="module"==

模块访问

ES6 采用 导入/导出 (引用/暴露) 的形式进行外部引用

// 模块 1 (导出
function A1(){
    console.log("访问A1");
}
export default A1

// 模块 2 (导入
import A1 from './1.js'
A1();

导入/导出 多个 写法

写法1

function A1(){...}
function A2(){...}
export default { A1, A2 } // 看做一个对象

import obj

写法2

function test(){...}
export function A1(){...}
export function A2(){...}
export default test

import textA,{A1,A2} from './1.js'

写法3 (常用)

export function A1(){}
export function A2(){}
export function A3(){}

// 模块2 按需导入
import {A1} from './1.js'
// 模块2 所有导入
import {* as mod1} from './1.js'

注意 :

  • 模块导入可能有多个 函数/属性/..
  • 模块不导出就没法进行通信
  • 多模块 导入所引用的名称不能重复发名称
  • 多模块 假如出现重名问题 可以进行 进行重新命名 重名写法 : ==import test as testA1==
  • 模块导入时 , 导入所有引用 可以直接用 * 替代 但必须重新命名
  • 隔离性好 , 那个导入那个用 , 跨出范围不能用 (模块范围)
  • 多模块 引用时他们名称必须一致 , 否则不行
  • 模块导出时 采用了 default关键字 , 在导入时需要 自定义起名 , 且无需写大括号引用

# 动态导入

标准用法是静态的 , 会直接使所有模块进行导入 . ES11 新增了按需导入 模块

定义模块加载 :

async funtion test(){
    let res;
    if(true){
    	res = await import("./1.js")
	}else{
    	res = await import("./2.js")
	}
	console.log(res)
}

获取模块路径

通过 ==import.meta== 进行获取模块的路径

# 异步遍历器

==for await==异步遍历器 , 需要异步生成器使用

function timer(t){
	return new Promise(resolve=>{
        setTimeout(()=>{
            resolve("data-"+t)
        }, t)
    })
}

// 异步生成器
async function *gen(){
    // 请求异步任务
    yield timer(1000)
    yield timer(2000)
    yield timer(3000)
}

async function test(){
    let g = gen();
    let list = [g.next(), g.next(), g.next()]
    
    for await(let i of list){
        console.log("op :>>",Date.now())
        console.log(i)
        console.log("ed :>>",Date.now())
    }
}

# WeakRefs

WeakRef (opens new window) 集合对象允许保留对原对象的弱引用 , 而不会阻止被弱引用对象被 GC 回收

一般情况 采用 Set , Map 存数据时 , 传入的原始数据如果赋值 null / undefined / 丢失 等情况 , 集合中的数据是不会丢失的 , 因此采用 WeakRefs集合对象

WeakRef 延伸的集合对象 : (可点击跳转)

  • WeakSet (opens new window)
  • WeakMap (opens new window)

示例 : (Map执行和Set差不多)

let obj = {
    name : 'Sans'
}
 
let s = new WeakSet();

s.add(obj)
obj = null
// 执行后访问 s 为空

DOM节点对象

即使丢失了还会存在

<body>
    <button id="like">按钮</button>
</body>
<script type="text/JavaScript"> let like = document.getElementById("like");
    let map = new WeakMap();
    // 因为不能穿简单类型
    map.set(like, {click: 0});
    
    like.onclick = function(){
        let buttom = map.get(like);
        buttom.click++;
        console.log(buttom.click);
    }

    setTimeout(function() {
        document.body.removeChild(like)
    }, 3000);
    
    // 即使DOM节点被删除了 , 但在后面map访问时 like依旧存在
</script>

**解决方案 : ** DOM节点对象使用 WeakRef进行封装 , deref()能够提取 原始DOM节点

<body>
    <button id="like">按钮</button>
</body>
<script type="text/JavaScript"> 
    let like = new WeakRef(document.getElementById("like"));
    let wmap = new WeakMap();
    // like.deref() 等同于 document.getElementById("like")
    wmap.set(like.deref(), {click: 0});
    
    like.deref().onclick = function(){
        let buttom = wmap.get(like.deref());
        buttom.click++;
        console.log(buttom.click);
    }

    setTimeout(function() {
        document.body.removeChild(like.deref())
    }, 2000);
</script>

注意 :

  • 只能存储复杂类型 对象 / 函数 / 数组 , 基本类型不能
  • 不存在引用计数 +1 (原数据指向丢失集合则丢失)
  • 不能使用for循环
  • DOM节点对象引用 , 即使body消失了 , 集合是不会消失的 , 除非把该DOM节点对象设为null 除非该对象获取到的是 原始DOM节点!

# 异常捕获

和Java差不多 , 捕获回调的数据只能传递 包含cause属性的对象

function getData(){
    try{
        let i = 1/0; // 异常
    }catch{
        throw new Error("说明不符合规则",{cause:'有问题'})
    }
}

try{
    getData()
}catch(err){
    console.log(err, err.cause)
}
#ES6
上次更新: 2023/03/12, 00:43:49

← JavaScript Git→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式