let
声明的变量在let
命令所在的代码块中有效。不存在变量提高,只能先声明后使用。javascript
若是区块中存在let
和const
命令,这个区块对这些命令声明的变量,从一开始就造成了封闭做用域。凡是在声明以前就使用这些变量。html
var a = 1; { a = 2; //ReferenceError let a = 'a'; console.log(a); //'a'; }
在相同块级做用域中,不能用let
重复声明同一变量。即便已存在的变量是经过var
声明的。java
let a = 1; let a = 2; //报错 let a = 1; var a = 2; //报错,var声明有变量提高做用
在块级做用域中,用let
声明的变量只在当前做用域中有效,且不会受到外部的影响,因此块级做用域能够替代自执行函数表达式。node
理论上,函数在块级做用域中声明行为和let
相似,但在es6浏览器环境中,为了兼容老版本,函数声明与var
声明变量相似,会提高到全局做用域头部,和当前块级做用域的头部,为了不差别,能够将函数声明写成函数表达式。react
let fn = function () {}; //函数表达式
声明常量必须立刻赋值且不能再改变。const
和let
有相似的特色:在块级做用域内有效,声明不提高,存在暂存死区,不可重复声明。git
复合型数据如object
,声明后不可在从新赋值,但能够修改这个值自己,好比修改属性和新增属性。冻结对象可使用Object.freeze
方法。es6
const json = Object.freeze({}); //常规模式下修改json无效,严格模式下报错
javascript
的顶层对象是window
,node
的顶层对象是global
,ES6
规定用let
const
class
声明的变量不在是顶层对象的属性。github
let a = 1; window.a //undefined
从数组和对象中提取值,对变量进行赋值,称为解构(destructuring)web
数组的解构赋值,按照对应的顺序赋值,若是值数量超出则多余的值被抛弃,若是值不够则为undefined
。正则表达式
let arr = [1, [2, 3]]; let [a, [b, c]] = arr;
对象的解构赋值必需要属性名相同,顺序毫无影响。若是属性名不一样,须要写成以下形式。
let {a: b} = {c: 1}; b //1
实际上对象解构赋值的是后者。
let {a} = {a: 1} //简写 let {a: a} = {a: 1} //全写
字符串解构赋值和数组相似。
let [a, b, c] = 'hello'; console.log(a,b,c) //h,e,l
数组解构赋值默认值,当等号右边的值 === undefined
时,默认值生效。
let [a = 1, b = 2] = [undefined, null]; console.log(a, b); //1 null
以上代码逻辑是:
if ([undifined, null][0] === undefined) { a = 1; } else { a = [undifined, null][0] }
对象解构赋值默认值,当对象属性值严格等于undefined
时。
let {a, b=2} = {1, undefined} a,b //1,2 let {a: b=1} = {a: undefined} b //1
事实上,只要某种数据结构具备 Iterator
接口,均可以采用数组形式的解构赋值。
函数参数的解构赋值,传入的参数不是数组或对象,而是变量。
let fn = ( [a, b] ) => { return a + b; }; fn ([1, 2]); //3
[[1,2],[3,4]].map([a,b]=> a+b); //[3,7]
函数参数也可以使用默认值
let fn({a=1, b=2} = {}) { return [a,b]} fn({a:10}) // [10,2]
等号右边若是不是对象,会先转成对象,转换失败则报错。
let {toString: s} = 123; s === Number.prototype.toString let {toString: s} = true; s === Blooean.prototype.toString
undefined
null
不能转成对象,结构赋值报错。
let {a} = undefined; //TypeError let {b} = null; //TypeError
解构赋值应用:
//交换变量的值 let a = 1, b = 2; [a,b] = [b, a]; //函数返回多个值 let fn = () => {x: 1, y: 2} //提取json数据 let {a, b} = obj;
ES6
提供for...of
方法遍历字符串。
新增的其余方法:startsWidth()
endsWidth()
includes()
。
let s = 'hello word!'; s.startsWith('hello'); //true s.endsWidth('word'); //true s.includes('o'); //true
charAt()
用于返回给定位置的字符,对于编码大于0xFFFF的字符用at()
方法。
'ab'.charAt(0) //'a' '𠮷a'.charAt(0) //'\uD842' '𠮷a'.at(0) //'𠮷'
用于字符串拼接,{}
中能够进行运算、引用对象、调用函数,非字符串类型会被转成字符串。能够嵌套使用,{}
中能够再使用模版字符串。若是字符串中有反引号要用反斜杠转义。
let name = 'zq'; `your name is ${name}`;
模版字符串中空格和和缩紧都会被保留,能够用trim()
方法消除。
`<ul> <li><li> </ul>`.trim();
RegExp
构造函数参数有两种状况。
//参数一:字符串,参数二:修饰符 let reg = new RegExp('abc','i'); //参数一:正则表达式 let reg = new RegExp(/abc/);
以上代码中,第二种只能传一个参数,返回原有正则的拷贝,不容许传第二个参数添加修饰符。
let reg = RegExp(/abc/, 'i'); //报错
ES6
容许给RegExp
构造函数传入第二个参数添加修饰符,即便第一个参数是正则,但会覆盖原有正则表达式的修饰符。
let reg = new RegExp(/abc/g, i).flags //'i'
新增flags
属性,返回正则表达式的修饰符。
//ES5的source属性 /abc/i.source //'abc' //ES6的flags属性 /abc/i.flags //'i'
ES6
在Number
对象上提供了新的方法。
Number.isFinite()
判断是否为有限数值。
Number.isFinite('1') //false Number.isFinite(NaN) //false Number.isFinite(1.01) //true Number.isFinite(Infinity) //false
Number.isNaN()
检测一个值是否为NaN
,只有NaN
才会返回true
,其余值一概返回false
。
全局方法isFinite()
和isNaN()
会将传入的值转成数字类型再判断,Number.isFinite()
和Number.isNaN()
方法参数必须是数值类型,不然直接返回false
。
isNaN('NaN') //true Number.isNaN('NaN') //false
ES6
将全局方法parseInt()
和parseFloat()
放到Number
对象上,行为不变。
Number.isInteger()
用来判断一个数是否为整数。
小数和整数采用相同的存储方式,小数点后全为零也为整数。
Number.isInteger(2) //true Number.isInteger(2.0) //true
Math.trunc()
方法返回数值的整数部分。
Math.trunc(1.1) //1 Math.trunc(-1.1) //-1 Math.trunc('1.1') //1 Math.trunc('a') //NaN
可使用Math.floor()
和Math.ceil()
方法模拟Math.trunc()
。
Math.trunc = Math.trunc || function(x) { return x < 0 ? Math.ceil(x) : Math.floor(x); };
ES6
新增了三角函数:
Math.sinh(x)
返回x的双曲正弦Math.cosh(x)
返回x的双曲余弦Math.tanh(x)
返回x的双曲正切Math.asinh(x)
返回x的反双曲正弦Math.acosh(x)
返回x的反双曲余弦Math.atanh(x)
返回x的反双曲正切ES6
新增了指数运算符**
。
let a = 2; a = a**3; //8 //能够简写成 a **= 3
ES6
容许为函数的参数设置默认值,即直接写在参数定义的后面。使用默认值时,不能有同名参数。
function (x = 1) {} function (x, x=1) {} //报错
默认参数不是传值,而是每次都从新计算。
let y = 10; function fn (x = y+1) { console.log(x); } fn(); //11; y++; fn(); //12;
函数参数是默认声明的,不能用let
或const
再次声明,能够用var
再次声明。
function (x) { let x = 1; //报错 var x = 1; //正常 }
函数默认值与解构赋值默认值结合使用。
//只使用解构赋值默认值 function fn ({a, b = 2}) { console.log (a, b); } fn ({a:1}); //1, 2 fn ({a:1, b:3}); //1, 3 fn (); //报错 //使用解构赋值默认值和函数参数默认值 function fn ({a, b = 2} = {}) { console.log (a, b); } fn() //undefined, 2
函数默认值参数不是最后一个参数,则不能省略,能够用undefined
代替,不能用null
代替。
function fn (x, y=1, z) { console.log(x, y, z); }; fn(1,2) //1,2,undefined fn(1,undefined,2); //1,1,2
将函数参数默认值设成undefined
表示此参数能够省略。
function fn (x=undefined, y) {} fn(,2);
指定了默认值之后,函数的length
属性,将返回没有指定默认值的参数个数。若是设置了默认值的参数不是尾参数,那么length
属性也再也不计入后面的参数。
function fn (x, y=1, z) {}; fn(1,2,3).length; //1
一旦设置了参数的默认值,函数进行声明初始化时,参数会造成一个单独的做用域(context)与函数内部不是同一个做用域。等到初始化结束,这个做用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2 //参数做用域以下: { let x = 2; let y = x; }
ES6
引入 rest
参数(形式为...变量名
),用于获取函数的多余参数,rest
参数搭配的变量是一个数组,该变量将多余的参数放入数组中。...变量
后不能再有参数,不然报错。
函数的length
属性不包括rest
参数。
function fn(x, ...rest) { console.log(Array.isArray(rest)); console.log(rest); }; fn(1,2,3).length; //1 //true //[2,3]
从 ES5
开始,函数内部能够设定为严格模式。ES7
规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,不然会报错。
函数的name
属性,返回该函数的函数名。若是将一个匿名函数赋值给一个变量,ES5
的name
属性,会返回空字符串,而 ES6
的name
属性会返回实际的函数名。
let fn = () => {} //es5 fn.name //'' //es6 fn.name //'fn'
若是将一个具名函数赋值给一个变量,则 ES5
和 ES6
的name
属性都返回这个具名函数本来的名字。
let fn = function a() {}; //es5 es6 fn.name //'a'
this
对象,就是定义时所在的对象,而不是使用时所在的对象。new
命令,不然会抛出一个错误。arguments
对象,该对象在函数体内不存在。若是要用,能够用 rest
参数代替。yield
命令,所以箭头函数不能用做 Generator
函数。箭头函数根本没有本身的this
,致使内部的this
就是外层代码块的this
。
除了this
,如下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments
、super
、new.target
。
不能用call()
、apply()
、bind()
这些方法去改变this的指向。
扩展运算符用三个点号表示,功能是把数组或类数组对象展开成一系列用逗号隔开的值(数组),和...rest相反。
扩展运算符后面还能够放置表达式。
let x = 1; ...(x > 0 ? ['a','b'] : []) //'a','b'
若是扩展运算符后面是一个空数组,则不产生任何效果。
[...[], 1] //[1]
扩展运算符能够展开数组,因此再也不须要apply方法,将数组转为函数的参数。
Math.max.apply(null, [14, 3, 77]) // ES6 的写法 Math.max(...[14, 3, 77])
扩展运算符可用于复制数组,合并数组。
let arr1 = [1,2]; //ES5 let arr2 = arr1.concat(); //ES6 let arr2 = [...arr1]; //ES6 let [...arr2] = arr1;
扩展运算符还能够将字符串转为真正的数组。
[...'hello'] // [ "h", "e", "l", "l", "o" ]
任何 Iterator
接口的对象, 均可以用扩展运算符转为真正的数组。
经过 push
函数,将一个数组添加到另外一个数组的尾部。
let arr1 = [1,2,3]; let arr2 = [4,5]; arr1.push(...arr2);
扩展运算符其余应用: 复制数组,合并数组,展开字符串(有Iterato接口的对象),**
let arr = [1,2]; let arr1 = [...arr]; //复制数组 let arr2 = [...arr, ...[3,4]]; //合并数组 let arr3 = [...'hello']; //展开字符串
Array.from
方法用于将两类对象转为真正的数组:相似数组的对象和可遍历(iterable
)的对象(包括 ES6
新增的数据结构 Set
和 Map
)。将类数组转成数组
let arrayLike = { '0': 'a', '1': 'b', '2': 'c', length: 3 }; // ES5的写法 var arr1 = [].slice.call(arrayLike); // ['a', 'b', 'c'] // ES6的写法 let arr2 = Array.from(arrayLike); // ['a', 'b', 'c']
只要有length
属性的对象就叫作相似数组的对象,就能够被转化。
let obj = {length: 2} Array.form(obj) //[undefined, undefined]
对于尚未部署该方法的浏览器,能够用 Array.prototype.slice
方法替代。
const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj) )();
实际应用中,常见的相似数组的对象是 DOM 操做返回的 NodeList
集合,以及函数内部的 arguments
对象。Array.form()
均可以转换。
Array.from
还能够接受第二个参数,做用相似于数组的 map
方法,用来对每一个元素进行处理,将处理后的值放入返回的数组。若是 map
函数里面用到了 this
关键字,还能够传入 Array.from
的第三个参数,用来绑定 this
。
Array.from([1, 2, 3], (x) => x * x); //等同于 Array.from([1,2,3]).map(x => x * x);
若是参数是一个真正的数组,Array.from
会返回一个如出一辙的新数组。
Array.from([1,2,3]) //[1,2,3]
Array.of
方法用于将一组值,转换为数组。
Array.of(3,4) // [3,4] Array.of(2) // [2]
和Array()
方法不一样,传入一个值时,表示数组的长度。
Array(2) //[undefinde, undefined]
find
方法找出第一个符合条件的数组成员。它的参数是一个回调函数,全部数组成员依次执行该回调函数,直到找出第一个返回值为 true
的成员,而后返回该成员。若是没有符合条件的成员,则返回 undefined
。
[1,2,3].find(v => v>2); //3 [1,2,3].find((v, i, arr) => { return v>2 });
数组实例的 findIndex
方法的用法与 find
方法很是相似,返回第一个符合条件的数组成员的位置,若是全部成员都不符合条件,则返回-1。
这两个方法均可以接受第二个参数,用来绑定回调函数的 this
对象。
fill
方法使用给定值,填充一个数组。还能够接受第二个和第三个参数,用于指定填充的起始位置和结束位置。
[1,2,3].fill('a'); //['a', 'a', 'a'] [1,2,3,4,5].fill('a', 2, 4); //[1, 2, 'a', 'a', 5]
若是填充的类型为对象,那么被赋值的是同一个内存地址的对象,而不是深拷贝对象。
let arr = new Array(2).fill({name: 'Jim'}); arr[0].name = 'Tim'; // [{name: 'Tim'}, {name: 'Tim'}]
keys()
是对键名的遍历,values()
是对键值的遍历,entries()
是对键值对的遍历。keys(), values(), entries()
返回一个遍历器对象。能够用 for...of
循环进行遍历。
includes()
判断数组是否包含给定的值,返回布尔值,NaN
也能实现。它还有第二个参数,表示查找的起始位置,为负数则表示从后往前。
而 indexOf()
方法对 NaN
无效,会返回-1;
includes 为 ES2016 引入的方法。
相比于 indexOf,返回的是元素第一次出现的位置,再比较是否等于 -1,内部使用 === 判断,对 NaN 不适用。
数组的空位指,数组的某一个位置没有任何值。
Array(3); //[,,]
ES5 对空位的处理不一致。大多数状况下会被忽略。
// forEach方法 [,'a'].forEach((x,i) => console.log(i)); // 1 // filter方法 ['a',,'b'].filter(x => true) // ['a','b'] // every方法 [,'a'].every(x => x==='a') // true // reduce方法 [1,,2].reduce((x,y) => return x+y) // 3 // some方法 [,'a'].some(x => x !== 'a') // false // map方法 [,'a'].map(x => 1) // [,1] // join方法 [,'a',undefined,null].join('#') // "#a##" // toString方法 [,'a',undefined,null].toString() // ",a,,"
ES6 会将空位转为 undefined。
Array.from 方法、扩展运算符(...)、entries()、keys()、values()、find() 和 findIndex() 会将数组的空位,转为 undefined ;for···of 会遍历空位。
直接写入变量和函数,做为对象的属性和方法。
let a = 1; let obj = { a, method() { return this.a } }
这种写法用于函数的返回值。
function getPoint() { const x = 1; const y = 10; return {x, y}; }
定义对象有两种方法。
obj.a = 1; obj['c' + 'd'] = 2;
若是使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一。ES6 容许字面量定义对象时,用方法二(表达式)做为对象的属性名,即把表达式放在方括号内。
let lastWord = 'last word'; const a = { 'first word': 'hello', [lastWord] : 'world' }; a['first word'] // "hello" a[lastWord] // "world" a['last word'] // "world"
属性名表达式若是是一个对象,默认状况下会自动将对象转为字符串[object Object]。
let obj1 = { a: 1 }; let obj2 = { b: 2 } let json = { [obj1] : 'value1', [obj2] : 'value2' } json //Object {[object Object]: 'value2'}
[obj1] 会把 [obj2] 覆盖掉,而 json 最后只有一个 [object Object] 属性。
为了解决相等运算符(==)和严格相等运算符(===)的缺点,Object.is 用来比较两个值是否全等。
+0 === -0 //true NaN === NaN // false Object.is(+0, -0) // false Object.is(NaN, NaN) // true
Object.assign 方法用于对象的合并,将源对象(source)的全部可枚举属性,复制到目标对象,属于浅拷贝。
此方法的第一个参数是目标对象,后面的参数都是源对象。
若是目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
const target = { a: 1, b: 1 }; const source1 = { b: 2, c: 2 }; const source2 = { c: 3 }; Object.assign(target, source1, source2); target // {a:1, b:2, c:3}
若是只有一个参数,Object.assign 会直接返回该参数。
const obj = {a: 1}; Object.assign(obj) === obj // true
若是首参不是对象,则会先转成对象,而后返回,undefined 和 null 没法转成对象,报错。若是不是首参,只有字符串会以数组形式拷贝入目标对象,其余都不会产生效果。
typeof Object.assign(2) // "object"
let obj = {a: 1}; Object.assign(obj, undefined) === obj // true Object.assign(obj, null) === obj // true const v1 = 'abc'; const v2 = true; const v3 = 10; const obj = Object.assign({}, v1, v2, v3); console.log(obj); // { "0": "a", "1": "b", "2": "c" }
对象的每一个属性都有一个描述对象(Descriptor),用来控制该属性的行为。Object.getOwnPropertyDescriptor 方法能够获取该属性的描述对象。
let obj = { foo: 123 }; Object.getOwnPropertyDescriptor(obj, 'foo') // { // value: 123, // writable: true, // enumerable: true, // configurable: true // }
描述对象的 enumerable 属性,称为”可枚举性“,若是该属性为 false,就表示某些操做会忽略当前属性。
有四个操做会忽略 enumerable 为 false 的属性。
for...in
循环:只遍历对象自身的和继承的可枚举的属性。Object.keys()
:返回对象自身的全部可枚举的属性的键名。JSON.stringify()
:只串行化对象自身的可枚举的属性。Object.assign()
: 忽略 enumerable 为 false 的属性,只拷贝对象自身的可枚举的属性。for...in 循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
Object.keys 返回一个数组,包括对象自身的(不含继承的)全部可枚举属性(不含 Symbol 属性)的键名。
Object.getOwnPropertyNames 返回一个数组,包含对象自身的全部属性(不含 Symbol 属性,可是包括不可枚举属性)的键名。
Object.getOwnPropertySymbols 返回一个数组,包含对象自身的全部 Symbol 属性的键名。
Reflect.ownKeys 返回一个数组,包含对象自身的全部键名,无论键名是 Symbol 或字符串,也不论是否可枚举。
用来读取或设置当前对象的 prototype
对象。实现上,__proto__
调用的是Object.prototype.__proto__
。
ES5 引入了 Object.keys
方法,返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键名。
ES6 引入了跟 Object.keys
配套的 Object.values
和 Object.entries
,做为遍历一个对象的补充手段,供 for...of
循环使用。
Object.values() 方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值。
Object.entries() 方法返回一个数组,成员是参数对象自身的(不含继承的)全部可遍历(enumerable)属性的键值对数组。
const obj = { foo: 'bar', baz: 42 }; Object.entries(obj) // [ ["foo", "bar"], ["baz", 42] ]
ES7 将扩展运算符引入了对象。
可用于解构赋值:
let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; x // 1 y // 2 z // { a: 3, b: 4 }
解构赋值不是最后一个参数,因此会报错。解构赋值要求等号右边是一个对象,不然报错。
解构赋值的拷贝是浅拷贝,且不能复制继承自原型对象的属性。
用于拷贝对象 和 合并对象
let z = { a: 3, b: 4 }; let n = { ...z }; n // { a: 3, b: 4 }
这等同于使用 Object.assign
方法。
let ab = { ...a, ...b }; // 等同于 let ab = Object.assign({}, a, b);
与数组的扩展运算符同样,对象的扩展运算符后面能够跟表达式。
const obj = { ...(x > 1 ? {a: 1} : {}), b: 2, };
ES5 的对象属性名都是字符串,这容易形成属性名的冲突,为了保证每一个属性的名字都是独一无二的,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的缘由。
它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
let s = Symbel(); typeof s // 'Symbel'
s 是一个独一无二的值。
Symbol 函数前不能使用 new
命令,不然会报错。这是由于生成的 Symbol 是一个原始类型的值,不是对象。也就是说,因为 Symbol 值不是对象,因此不能添加属性。基本上,它是一种相似于字符串的数据类型。
Symbol 函数能够接受一个字符串做为参数,表示对 Symbol 实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。
let s1 = Symbol('foo'); s1 // Symbol(foo) s1.toString() // "Symbol(foo)"
若是 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,而后才生成一个 Symbol 值。
Symbol 函数的参数只是表示对当前 Symbol 值的描述,所以相同参数的Symbol函数的返回值是不相等的。
Symbol 值不能与其余类型的值进行运算,会报错。可是,Symbol 值能够显式转为字符串。也能够转为布尔值,可是不能转为数值。
let sym = Symbol('My symbol'); String(sym) // 'Symbol(My symbol)' sym.toString() // 'Symbol(My symbol)' Boolean(sym) // true !sym // false
let mySymbol = Symbol(); // 第一种写法 let a = {}; a[mySymbol] = 'Hello!'; // 第二种写法 let a = { [mySymbol]: 'Hello!' }; // 第三种写法 let a = {}; Object.defineProperty(a, mySymbol, { value: 'Hello!' }); // 以上写法都获得一样结果 a[mySymbol] // "Hello!"
Symbol 值做为对象属性名时,不能用点运算符。
在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中。
ES6
模块经过export
命令显式指定输出的代码,再经过import
命令输入。使用模块自动采用严格模式。严格模式详解
export
用于规定模块的对外接口,输出变量,函数,类。
//写法1 export let a = 1; export function b () {}; //写法2 let a = 1; function b () {}; export {a, b}; //报错 let a = 1; export a;
一般输出的变量就是原本的名字,能够用 as
修改。
function a () {}; let b = 1; export { a as fnA, b as vB };
export
输出的接口和模块内部的变量是动态绑定关系,变量值改变,经过接口获取的值也相应改变。
//test.js export let a = 1; setTimeout(() => a=2, 1000); import {a} from './test' //a = 1, 1s后变成2
export
必须处于模块顶层,若是处于块级做用域会报错。import
也是如此。
function () { export let a = 1; //报错 }
使用import
加载模块。import - MDN
import {a, b} from './test'
import
后跟一个大括号,括号内指定须要导入的变量,变量名需对应。但能够经过as
修改。
import {a as vA, b as vB} from './test';
import
后的from
用来指定模块的路径,绝对路径或相对路径,.js
能够省略。若是模块有配置文件,则不带路径。
import react, {Component} from 'react';
import
有提高效果,会提高到模块头部,先执行。
因为import
是静态执行,不能使用表达式和变量。好比from
后的路径不能用一个变量代替。
import
会执行所加载的模块,能够直接跟模块名。但屡次加载相同模块只执行一次,import
语句是单例模式。
import 'module_name'; import {a} from './test'; import {b} from './test'; //等同于 import {a,b} from './test';
模块总体加载:
import * as myModule from './my_module.js'; //以myModule为命名空间,在myMoudle下能够找到全部接口,不容许修改。
导入默认值 :
export default function () {}; import fn from './test';
- 导入默认值可使用任意名字代替输出值。
import
后不用大括号。export default
后跟的变量名或函数名称在模块外部无效。- 一个模块只能有一个默认输出,
export default
只能使用一次。export default
表示将后面的值赋给default
,再输出一个叫default
的变量或函数。export default
后不能有变量声明语句。
//test.js function fn () {}; export default fn; //等同于 export {fn as default};
import {default as foo} from './test'; //等同于 import foo from './test';
export default let a = 1; //报错 export default 10; //正确
import
和export
的复合写法:
export {foo, fn} from 'module'; //等同于 import {foo, fn} from 'module'; export {foo, fn};
加载javascript
脚本使用<script>
标签,可以使用defer
或async
实现异步加载,defer
会等到页面渲染完,其余脚本执行完再执行,async
只要资源加载完就终断页面渲染当即执行,不能保证多个async
脚本按顺序执行。
在浏览器中可使用<script>
标签加载模块,但须要type='module'
属性。
<script src='path/test.js' type='module'></script>
带有type='module'
的<script>
都是异步加载,等同于自动打开了defer
属性,也能够加async
属性,让模块加载完当即执行。
也能够直接在<script>
标签内加载模块。
<script type='module'> import a from './test.js'; </script>