为什么要学习ES6
- es5存在的一些问题
- es6更加简便
- 许多大公司都在用es6
ES6 新特性
ES6编译:
编译器报错关于es6,有两种解决办法:
1.在js顶部添加注释,/*jshint esversion: 6 */
2.在项目根目录下添加.jshintrc配置文件,在配置文件添加一段
{
"esversion": 6
}
在Settings>Languages & Frameworks>JavaScript>Code Quality Tools>JSHint,选择Default,就可以了。或者选择Custom configuration file,设置一个全局的.jshintrc文件,这样就不需要每次新建.jshintrc。
const && let
let
why(not use var) | why(use let) |
var有声明提前 | let没有声明提前 |
var不具有块级作用域 | let具有块级作用域 |
var可以重复声明 | let不能重复声明 |
例子1:声明提前
console.log(a);
var a = 3;
// 打印undefined,不报错,解释结果如下:
// var a;
// console.log(a);
// a = 3;
console.log(b);
let b = 3;
// 报错,解释:let没有声明提前。
例子2:块作用域
for(let i =0;i<10;i++){};
console.log(i);
// 报错,因为let存在{}作用域
for(var j =0;j<10;j++){};
console.log(j);
// 打印10 , 没有{}作用域,j做为全局变量。
// 常见问题
var arr = [];
for(var i =0;i<10;i++){
// 循环,数组中保存一个function。
arr[i] = (function(){
return function(){
return i;
}
})()
}
arr[1]();// arr[1]中保存了function 打印10;
// 解决方法1:使用let
let arr = [];
for(let i =0;i<10;i++){
// 循环,数组中保存一个function。
arr[i] = (function(){
return function(){
// 这里每个function内存中都开辟一个i的变量内存
return i;
}
})()
}
arr[1]();// arr[1]中保存了function 打印对应的i;
// 解决方法2:使用闭包
let crr = [];
for(let i =0;i<10;i++){
// 循环,数组中保存一个function。
crr[i] = (function(num){
return function(num){
// 这里每个function内存中都开辟一个i的变量内存
return i;
}
})(i);
}
// crr[0]()调用方法,方法中用到了外部的变量。
crr[0]()
const
特点:
- const 声明时即赋值,否则报错。
- const声明后的变量不能修改,修改报错。注意:如果时引用类型,const指向的是其引用地址,可以修改引用对象的属性。
- const同let一样具有{}块作用域。
- const不能重复声明
- const没有声明提前(变量提升)
总结:
- let/const 不会污染全局变量,声明的navigator变量不会覆盖window.navigator
- let、const声明的全局变量不会挂载在window上,而是在script上。
- 建议:默认情况下用const,需要改变的变量用let
多行字符串 不用\n
`这是一个
多行
字符串`;
模板字符串 字符连接 替换+号
var name = '小明'; var age = 13; var message = `你好,${name},你今年${age}岁了`
解构赋值
1.变量解构
let [a,b,c] = [1,2,3] // 没有值的为undefined
const [,,...arr] = [1,2,3,4,5] // arr = [3,4,5]
let [a=10,b,c] = [,2,3] // 10,2,3 a默认值10 function(a = 10){}// a有默认值
let [a,[b],c]=[1,[2],3] // 嵌套赋值,[b]不能直接写b,也要解构
2.对象解构
let {foo,bar} = {foo:'hello',bar:'world'};
console.log(foo,bar);// hello world
let {foo='hi',bar} = {bar:'world'}
console.log(foo,bar);// hi world
let {foo:abc,bar} = {bar:'world'} // 为foo设置别名 ,foo不能再使用,打印foo报错
let {foo:abc='hi',bar} = {bar:'world'} // abc 默认值hi
console.log(abc,bar);// hi world
var obj = {obj1:{a:1,b:3},obj2:{c:3,d:8}}
const {obj1:{a:A}} = obj;
// 1. const {} 的解构与obj 想类似,{} —— obj obj1 —— obj1 obj1.a 区别名A
在函数中直接用解构传入参数
const obj = function({min,max})=>{} //{max,min} 为传进来的实参中存在的属性
(x,y)=>({x:x,y:y}) => 写成 (x,y)=>({x,y}) 即可
实例方法:obj:function(){} => 写成 obj(){}
// x,y默认值为0。
function m1({x=0,y=0}={}){
return [x,y];
}
console.log(m1({x:'a',y:'b'}));// x:'a',y:'b';
3.字符串解构
let [a,b,c] = 'string';
console.log([a,b,c]);// s,t,r
let {max,min,random} = Math;
console.log(typeof min);// function
console.log(typeof max); // function
console.log(typeof random); // function
let {length} = 'string';
console.log(length); // 6
字符串扩展
- includes():返回布尔值,表示是否找到了参数字符串。
- startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
- endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
- padStart():首部填充字符
- padEnd():尾部填充字符
箭头函数
add = a=>a+b; add = a=>({'a':a}) // 返回对象需要用括号 add = (a,b)=>a*b; add = () => a*a;
箭头函数中没有arguments,因为箭头函数没有constructor,不是一个对象,可以认为是一个语法糖。
箭头函数没有this指向,由于箭头函数没有作用域链,所以向上查找作用域链。找到该作用域中的this
// 箭头函数没有this的指向,箭头函数内部的this
值只能通过查找作⽤域链来确定
// 如果箭头函数被⼀个⾮箭头函数所包括,那么
this的值与该函数的所属对象相等,否则 则是全局的window对象
var per ={
// 不建议对象方法使用箭头函数,尽量使用普通函数。箭头函数的时候要注意
init:e=>{
console.log(this);
document.onclick =e=>{
// 箭头函数,没有this指向,所以不会指向document,而是往上找,
// init也是一个箭头函数,也不管,继续往上找,最后找到per,window.per,所以指向window
console.log(this);
}
}
}
var mer ={
init:function(){
console.log(this);
document.onclick =e=>{
// 箭头函数,没有this指向,所以不会指向document,而是往上找,找到init,此时init不是箭头函数,this.init调用,指向mer
console.log(this);
}
}
}
===函数的参数设置默认值 function(n = 10){}
function test({a='lisa',b=15}={}){console.log(a,b);}
test({a:'arao',b:15});
()=>{}
foo = v =>(v) // foo = function(v){return v;}
foo = (a,b)=>{return b+a;}
// 不能使用argument ,而是使用...rest
剩余参数由...+具名参数(保存了剩余参数的数组)组合;
function t(a,b,...keys){
// keys是具名参数,是保存了剩余参数的数组。
console.log(a,b,...keys);
}
t(1,2,4,5,6);//rest 是数组[4,5,6]
// 作用:主要是解决arguments问题
// 注意:剩余参数必须写在最后一个,否则报错。
拓展运算符...
var arr = [1,2,3,4,5,6]
function s(a,b,c,d,e){
console.log(a,b,c,d,e);
}
s(...arr); // 将函数解开 [...arr,..arr] ==> [1,2,3,4,5,6,1,2,3,4,5,6]
扩展对象的方法
- 简写
let obj = { name, age, sayhi(){}; }
- 表达式
// 原来如果属性或方法名由变量,需要如下操作:
obj[a+'times']=12;
//es6 方法属性中传入变量表达式
let a = 'count';
let obj = {
[a+'times']:12,
['click'+a](){console.log(111);}
}
- Object.is(arg1,arg2)
// 相当于 === 操作
注意:唯一一点不同的。
Object.is(NaN,NaN);
// true;
NaN === NaN
// false
- Object.assign(obj,arg1,arg2)
// obj是被合并对象,其余是合并对象,所有对象的属性一起浅拷贝到obj上
// 如果参数中存在相同属性,则后面覆盖前面
// 返回obj合并后对象。l === obj
const l = Object.assign({},{a:1},{b:21});
// 例子2:
let obj1 = { a: 0 , b: { c: 0}};
let obj2 = Object.assign({}, obj1);
// obj1.b = 'xxx'; obj2.b不会变,可以这么理解,b保存的是地址,
// 而地址可以看成是普通类型,所以修改b不会触发b地址对应的引用变量改变。
// 要修改b中的元素。
obj2.b.c = 3;
log(JSON.stringify(obj1));
// { a: 1, b: { c: 3}}
log(JSON.stringify(obj2));
// { a: 2, b: { c: 3}}
Symbol:
Symbol是独一无二的,最大的作用是作为私有变量
Symbol无法在for循环中被遍历出来。
let name1= Symbol('name');
let name2 = Symbol('name');
// name1 !== name2;
let obj = {
[b]:Symbol('小b');
c:Symbol();
}
// 用[],不能用.
obj[a] = Symbol();
// 访问方法1
Object.getOwnPropertySymbols(obj);
// 访问方法2 反射
Reflect.ownKeys(obj);
数据处理,数据存储
Set
Set 是一个不重复的集合。可以用Set进行数组的去重
let set = new Set();
// let set = new Set([1,2,3]]);
// 添加成员建议用add,用参数传入对象会报错。
// Set 的方法:
// 添加方法:如果重复添加,则无视
set.add(value);
// 删除方法:
set.delete(value);
// set转化成数组
let arr = [...set];
let brr = Array.from(set);
// Array.prototype.slice.call(set);不能转化set ,转的是类数组。
// forEach循环中,key和value都是同一个值
set.forEach((value,key)=>{console.log(value,key);});
// 全部清除方法:
set.clear();
// 是否存在某个值
set.has(value);
-----------------------------------
//注意:
//set 没有下标,也没有属性,所以不能使用for循环或者for in遍历
//只能用for of 或者 forEach(for of 可以用于遍历数组)
//for(let prop of arr){}
//-------------
//使用size属性获取set类数组的长度,而不是用length
//--------------
//set中引用的对象不能释放
var obj = {};
var set1 = new Set(obj);
// 释放对象:obj对象被释放,但是set中仍存在{}。
obj=null;
// 处理Set中引用对象不能释放问题。----WeakSet
WeakSet:不重复的集合
使用场景:处理Set中引用对象不能释放问题,用于存放dom可以减少内存泄漏问题。
与Set的区别:
1.成员必须为对象
2.因为成员如果没有被外界引用,就会被回收,成员个数取决于回收机制是否执行,所以不能迭代,没有values、keys、entries、forEach等方法,size属性
3.有has、add、delete方法
Map
Map是一个有序的对象,键和值无类型要求。与set较为类似,但map传入的是键值对。
map也无法释放引用对象
var map = new Map();
// map = new Map([['键','值']]); // 打印 '键'=>'值'
// map转数组:[...map]
map.set('键','值');
map.get('键');
map.delete('键');
map.clear();
// map.size;map.entries();map.keys();map.values();map.forEach();map.clear();map.has()
WeakMap
WeakMap 是键值对集合,键是弱引用,必须为对象。
var weakmap = new WeakMap(); // 方法: // has/set/get/delete
Set && Map && WeakSet && WeakMap
Set与Map区别:
Set的key和value都是值
Map是有序的键值对集合
Map方法:set/get/
Set与Map类似:
用于存储数据的不重复集合,引用对象作为成员无法释放
具有方法属性:entries/keys/values/clear/delete/forEach/size
不能够用for in 来遍历。而是要用for of 或者 forEach
Set与Map循环遍历:
for(var [key,value] of set.entries()){console.log(key,value);}
set.forEach((key,value)=>{console.log(key,value);});
for(var [key,value] of map){console.log(key,value);}
WeakSet:
WeakSet成员必须为对象(null除外)。成员是弱引用,如果没有被引用则会销毁,是否存在取决于垃圾回收机制是否运行。不可迭代,没有部分方法,没有size。
方法:add/delete/has
WeakMap:
WeakMap键必须为对象(null除外)。键是弱引用,如果没有被引用则会销毁,是否存在取决于垃圾回收机制是否运行。不可迭代,没有部分方法,没有size。
方法:set/get/has/delete
WeakSet 和 WeakMap 可用于存储dom节点,便于减少内存泄漏。
数组扩展
- Array.from
Array.from(arg1,callback,this);
arg1:要转化为数组的对象
callback:对转换后的arg1数组中每个元素调用函数。
this:指定callback函数中如果有this,则设置this的指向。
[...arr] 扩展运算符转化为数组
es5 :Array.prototype.slide.call(arr); [].slice.call(arr);
- Array.of()
Array.of(args1,args2,...) // 传入类型不限制的元素,并输出数组。
- arr.copyWithin
arr.copyWithin(arg1,arg2);
// 用从arg2索引开始直到结束的元素填充arg1-arg2索引的元素。
[1,2,3,4,5,6,7,8,0].copyWithin(0,4);
// [5,6,7,8,0,6,7,8,0]
- find
- findIndex
arr.find(callback)
// 返回第一个符合的元素
arr.findIndex(callback)
// 返回第一个符合的元素索引
- includes
arr.includes(arg) 返回true或则false
// 替换indexOf
entries && keys && values
entries返回键值对。
next():
1.获取数组迭代器a
let a = [1,2].keys();
2.使用迭代器调用next()
a.next();// 0
a.next();// 1
a.next();// undefined
数组可以用 for of循环。
for (variable of iterable) {}
for of 只能够遍历数组的value,不能够遍历数组的index或者两者.
for(var [key,value] of arr){} //报错
for in 会将原型链上的属性也遍历出来。
Object的原型链上没有迭代器,迭代器定义在Object的静态方法上
对于Object的实例要进行for of 迭代,则使用Object.entries(obj);
数组的原型上定义有迭代器。
for(var key of arr){}
for(var key of arr.entries()){}
for(var key of arr.keys()){}
迭代器iterator
var arr = [1,2,3];
// 创建一个迭代器,Symbol.iterator是一个方法
var ite = arr[Symbol.iterator]()
ite.next() //{value: 1, done: false} done:遍历是否完成
ite.next() //{value: 2, done: false} done:遍历是否完成
ite.next() //{value: 3, done: false} done:遍历是否完成
ite.next() //{value: undefined, done: true} done:遍历是否完成
Generator生成器函数:
作用:可以给没有迭代器接口的元素添加迭代器
生成器函数:
function* generator(){}
yield:暂停执行
next:恢复执行
function* generator(){
console.log(1);
yield 1;
console.log(2);
yield 2;
console.log(3);
}
let gen = generator(); // 返回一个生成器函数,并不会进入函数
gen.next(); // 打印1, {value:1,done:false} value 是 yield 后面的值
// 进入函数,执行完 yield 1 后暂停执行
gen.next(); // 打印2, {value:2,done:false} value 是 yield 后面的值
gen.next(); // 打印3,{value:undefined,done:true}
生成器传参:
function* generator(){
let x = yield 1;
console.log(x);
// 打印undefined
let y = yield 2; // 在调用这个next的时候传入参数,则x为该参数
console.log(x,y);
console.log(3);
return x+y; // 返回 {value: 30, done: true} 其中30->x+y;
}
let gen = generator(); // 返回一个生成器函数,并不会进入函数
gen.next(); //
gen.next(10); // 第二个yield给第一个yield的x传参
gen.next(20); // 第三个yield给第二个yield的x传参
给没有迭代器接口的元素创建迭代器
let obj = new Object({a:1,b:2});
// obj没有迭代器
obj[Symbol.iterator]=objectentries;
function* objectentries(){
let keys = Object.keys(obj);
for(let key of keys){
yield [key,obj[key]];
}
}
// obj有了迭代器接口,可以用for of循环
for(let [key,value] of obj){console.log(key,value);}
异步变同步
可以将异步代码改为同步代码。
// 例子1:ajax
function request(url) {
// request方法获取数据
$.ajax({
url,
method: 'get',
success(res) {
// 获取的数据,通过调用生成器方法,传入给res
getdata.next(JSON.stringify(res));
}
});
}
function* getData(){
console.log('请求数据');
let res = yield request('./About.html');
console.log('About数据请求完成'+res);
let res1 = yield request('./Home.html');
console.log('Home数据请求完成'+res1);
}
let getdata = getData();// 调用生成一个生成器
getdata.next();// 进入生成器函数,恢复执行
//例子2:
function load() {
console.log('loading');
}
function loadhide() {
console.log('hide loading');
}
function showData(){
setTimeout(function () {
console.log('数据成功获取');
// 在数据获取后生成器恢复执行
l.next();
// 应该在这里执行loadhide函数
},1000)
}
// 错误写法:
// load();
// showData();
// loadhide();
function* loadSeries(){
load();
yield showData();
loadhide();
}
let l = loadSeries();
l.next();
JS promise 异步
promise 状态一改变不可逆;只能执行一次。
只有两种情况:
- pending => resolved
- pending => rejected
new Promise((resolve,reject)=>{
img.onload = function () {
resolve();
}
img.onerror = function () {
reject('失败');
}
}).then(value=>{ // resolve 成功后做的事情},reason=>{ // reject 失败后的事情})
var p1 = new Promise((resolve,reject)=>{resolve('成功')}) //打印:Promise {<resolved>: "成功"}
var p2 = p1.then(val=>{console.log(val)},err=>{console.log(err)}) // p2 是一个新的promise对象 Promise {<pending>},其中then 是微任务
// 当then事件执行后再打印p2 ,Promise {<resolved>: undefined}
var p1 = new Promise((resolve,reject)=>{reject('失败');})
.then(null,(err)=>{return 122;}) // return 一个数据,后面then 默认是resolve
.then(val=>{console.log(val)});
关于 返回值
new Promise((resolve,reject)=>{
resolve('成功');
}).then(val=>{
console.log(val);
return new Promise((resolve,reject)=>{
reject('失败'); // 这里是返回了一个promise 对象,后面的then方法相当于这个对象的then方法;
})
}).then(null,err=>{
console.log(err);
})
new Promise((resolve,reject)=>{
resolve('成功');
}).then(val=>{
console.log(val);
// class Hd{
// then(resolve,reject){
// reject('失败');
// }
// }
// return new Hd();
//--------------
//return class{
// static then(resolve,reject){
// reject('失败');
// }
// }
//------------------------
return {
then(resolve,reject){
reject('失败'); // 这里使用then,与上面的promise一样效果
}
}
}).then(null,err=>{
console.log(err);
})
promise 封装ajax
new Promise((res,rej)=>{
var xhr = new XMLHttpRequest();
xhr.open();
// 设置头部 xhr.setRequestHeader();
// 设置返回数据格式 xhr.responseType = 'json';
// 或者使用JSON.parse(xhr.responseText);
xhr.onreadystatechange=function(){
if(this.readystate === 4 || this.status === 200){
res(this.response);
}
}
xhr.send();
}).then(value=>console.log(value))
try catch throw 的使用
try{
if(m='') throw '空字符';
if(m='1') throw '1';
}catch(err){
// err 为throw 的 信息;
// 在这里用err 进行操作。
}
promise 中catch的使用
catch 是 then(null,err=>console.log(err)) 的封装
new Promise((resolve,reject)=>{
reject('失败');
})
.then(value=>{},err=>{console.log(err);})//在then中添加相应的err事件,报错执行
.then(value=>{})
.catch(err=>{console.log('catch'+err)}); // 将catch放到最后,没有添加错误事件的,统一在catch处理,无论哪个then发生错误都触发catch错误
Promise方法
- Promise.resolve();
将任意对象转为promise函数 成功的
- Promise.resolve();
将任意对象转为promise函数 失败的
- all
let p1 = Promise.all(args);
args:promise成员数组
当args中所有成员返回成功时,执行成功的回调函数
当其一返回失败时,执行失败回调函数。
用处:加载大量的图片,素材。用于图片等素材加载。
function loadImg(url){
return new Promise((res,rej)=>{
let img = new Image();
img.onload = function(){
res(img);
}
img.src = url;
})
}
let p1 = loadImg('1.jpg');
let p2 = loadImg('2.jpg');
Promise.all([p1,p2]).then(data=>{console.log('所有的promise元素'+data)},err=>{
console.log('err:其中有promise失败'+err);
})
- race
用于图片超时,将两个promise进行比较,谁先完成执行谁,无论是resolve还是reject
let getImg = function(){
return new Promise((res,rej)=>{
let img = new Image();
img.onload = function(){
res(img);
}
img.src = '1.jpg';
})
}
let timeout = function(){
return new Promise((res,rej)=>{
setTimeOut(function(){
rej(new Error('请求超时'));
},1000)
})
}
Promise.race([getImg(),timeout()])
// 哪个先执行完,执行谁的结果。
- done
在代码的最后执行,不论返回是res还是rej,捕捉任何可能出现的错误
-
Promise.prototype.done = function (onFulfilled, onRejected) { this .then(onFulfilled, onRejected) .catch(function (reason) { // 抛出一个全局错误 setTimeout(() => { throw reason }, 0) }) }
- finally
在代码的最后执行,不论返回是res还是rej,参数是回调函数,可以进行一些结尾的操作和处理。
async && await
async function a(){
console.log(1);
// await 等待行为返回。
// return 会将值给到async返回的promise,如果没有return,则值为undefined
return await 'world';
// var m = await 'hello';
// await 只能放在async函数中。
// console.log(m);
// m = 'hello'
};
a(); // async函数返回一个promise
await 后面如果是一个promise, 如果promise没有返回,则await后面的都不会执行。
async function b(){
await new Promise(res=>{});
// 从右边执行,new Promise,向左遇到await阻塞进程。
// promise没有返回值res或者rej,不会执行下面的语句
console.log('hello');
}
b();
如果有多个await promise对象,只要一个promise状态为reject,就不会继续往下执行
async function c(){
console.log(1);
await Promise.resolve('success1');
await Promise.resolve('success2');// then中以最后一个resolve为最终返回。
await Promise.reject('error');// 遇到promise状态为reject 后面语句不执行。
await Promise.resolve('success3');
}
// 想让await遇到一个rej后还能继续执行
async function c(){
console.log(1);
try{
await Promise.reject('error');// 遇到promise状态为reject 后面语句不执行。
}catch(){}
return await Promise.resolve('success3');
}
// 异步请求ajax
function ajax(url){
return new Promise((res,rej)=>{
var xhr = new XMLHttpRequest();
xhr.open('GET',url);
xhr.addEventListener('readyStateChange',function(){
if(this.readyState === 4 && this.status === 200){
res(this.response);
}
if(this.readyState === 4 && this.status !== 200){
rej(new Error('错误'));
}
})
})
}
async function getMsg(url){
// ajax执行,返回一个res,用res接收返回值
var res = await ajax(url);
// 对请求到的数据进一步操作
var data = await res[0].weather
// 返回 data,给then方法接收
return data;
}
getMsg('1.php').then(v=>v,err=>err).catch(err=>err);
类
类声明不会提升。
类中使用严格模式。
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
// 原型上的方法
sayName(){
console.log(this.name);
}
}
// 使用Object.assign()可以讲多个方法一次性加到对象中,但是不常用
Object.assign(Person.prototype,{
sayAge(){
console.log(this.age);
},
sayHello(){
console.log(this.name+this.age);
}
})
类的继承extends
关于混入类:https://en.wikipedia.org/wiki/Mixin#In_JavaScript
// es5
function Person(name,age){
this.name=name;
this.age = age;
}
function Teacher(name,age,major){
Person.call(this,name,age);
this.major = major;
}
Teacher.prototype = Object.create(Animal.prototype);
Teacher.prototype.constructor = Dog;
class Animal{
constructor(name,age){
this.name=name;
this.age = age;
}
// 静态方法,由Animal调用。
static sayHi(){
return 'hello';
}
}
class dog extends Animal{
constructor(name,age,color){
super(name,age);
// 相当于 Animal.call(this,name,age);
this.color = color;
}
sayHi(){
console.log('sayhi')
// 方法中使用super(相当于超类的原型)
// 可以直接用super.方法();
}
}
getter && setter
从对象中获得一个值,也可以给对象的属性赋值,通常称作setter、getter
/*
Getter 函数的作用是可以让返回一个对象私有变量的值给用户,而不需要直接去访问私有变量。
Setter 函数的作用是可以基于传进的参数来修改对象中私有变量的值。这些修改可以是计算,或者是直接替换之前的值。
*/
class Book {
constructor(author) {
this._author = author;
}
// getter
get writer(){ // getter 方法 是直接返回 this.属性
return this._author;
}
// setter
set writer(updatedAuthor){ // setter方法是传入一个参数将this.属性的值修改
this._author = updatedAuthor;
}
}
const lol = new Book('anonymous');
console.log(lol.writer); // anonymous 实例.getter方法,不需要加()
lol.writer = 'wut'; // 实例.setter方法
console.log(lol.writer); // wut
引入模块文件:require 和import的区别:
- require 运行时调用,一般放在文件开头
- 在js文件中引入模块。
- import编译时调用,必须放在文件开头,可以只引入部分需要的。常用引用方式:import { 函数名,变量名 } from "文件路径"
- require 相当于赋值过程,
- import相当于解构过程,一般会被转化成es5,会被转换成require形式。
- export 文件中导出函数或者变量供其他文件使用,export {函数名,变量名};默认被导出:只(且只能)导出一个值,常用export default function sum(a,b){return a+b;}
- 默认被导入:import 函数名 from "文件路径" ,不用花括号
- import 引入所有的方法:import * as obj from "文件路径" // obj 自定义的一个对象,之后可以通过obj.方法名的方式调用方法,obj.add();