es6 學習心得
1、let/ const聲明變量(項目中常用)
之前使用var關鍵字聲明變量,無論聲明在何處,都會被視為聲明在它的作用域的最頂部(不在大括號內{}即在全局作用域的最頂部),而在es6之前JavaScript只有函數作用域和全局作用域。這就是變量提升。
console.log(a); //輸出undefined if (true) { var a = 1; }
上面的代碼實際上是:
var a; console.log(a); //輸出undefined if (true) { a = 1; }
(1)let聲明變量
let實際上為JavaScript新增了塊級作用域。let聲明的變量只在它所在的代碼塊內有效。
將上面變量提升的例子稍微變化一下:可以看出let聲明的a只在代碼塊內有效。
if(true) { var a = 1; } console.log(a) //輸出1
if(true) { let a = 1; } console.log(a) //報錯ReferenceError: a is not defined
再看一個常見的例子:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); //10
每次循環的i指向的其實都是同一個i,很顯然最後的結果是10。那麽如何達到想要的效果?
·閉包(ES5)
var a = []; for (var i = 0; i < 10; i++) { a[i] = (function (num) { return function () { console.log(num); }; })(i) } a[6](); // 6
·let聲明變量(ES6)
var a = []; for (let i = 0; i < 10; i++) { a[i]= function () { console.log(i); }; } a[6](); // 6
變量i
是let
聲明的,當前的i
只在本輪循環有效,所以每一次循環的i
其實都是一個新的變量。
使用let聲明變量的話,不存在變量提升的情況,必須在聲明以後才使用,否則會報錯,這在語法上稱為“暫時性死區”。並且let不允許在相同作用域內重復聲明變量。
(2)const聲明變量
const聲明的變量是一個只讀變量,一旦聲明就必須馬上初始化並且不能改變值,因此如果用const只聲明而不賦值也會報錯。
const的作用域與let相同,只在當前的塊級作用域內有效。同樣的,也不能變量提升,存在暫時性死區,不能重復聲明。
本質:
const
實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。但對於復合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const
只能保證這個指針是固定的,至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明為常量必須非常小心。
const foo = {}; // 為 foo 添加一個屬性,可以成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另一個對象,就會報錯 foo = {}; // TypeError: "foo" is read-only
總結:因此,可以知道什麽時候用let什麽時候用const:值會改變的變量用let聲明,值是一個不會改變的常量就用const聲明。
2、箭頭函數(項目中常用)
Es6使用“箭頭”(=>)定義函數。箭頭函數使得表達更簡潔。
箭頭函數的寫法:
const fn = (a, b) => a + b;
就相當於ES5標準下的:
var fn = function (a, b) { return a + b; }
箭頭函數還可以與變量解構結合使用。
const full = ({ first, last }) => first + ‘ ‘ + last;
// 等同於 function full(person) { return person.first + ‘ ‘ + person.last; }
使用箭頭函數有幾點需要註意。
(1) 函數體內的this對象,是定義時所在的對象,而不是使用時所在的對象。如果在箭頭函數內使用this,那麽該this是外層的this,換句話說,就是箭頭函數裏根本沒有自己的this,而是引用外層的this。
(2) 不可以當做構造函數,也就是說,不可以使用new命令,否則拋出錯誤。
(3) 不可以使用arguments對象,該對象在函數體內不存在。如果一定要用,可以使用rest參數代替。
上面的第一點尤其要註意,this對象的指向是可變的,但在箭頭函數中,它是固定的。
function foo() { setTimeout(() => { console.log(‘id:‘, this.id); }, 100); } var id = 21; foo.call({ id: 42 }); // id: 42
上面代碼中,setTimeout的參數是一個箭頭函數,該箭頭函數生效是在foo函數生成時,而它真正執行則是在100毫秒後。如果是普通函數,執行時的this執行全局對象window,輸出21。而箭頭函數的this總是綁定在定義生效時所在的作用域,因此輸出42。
3、模板字符串
模板字符串解決了使用+號拼接字符串造成的不便利。模板字符串用(`)反引號標識,可以作普通字符串,也可以定義多行字符串,或者在字符串在嵌入變量。
// 普通字符串 `In JavaScript ‘\n‘ is a line-feed.`
// 多行字符串 `In JavaScript this is not legal.`
// 字符串中嵌入變量 let name = "Bob", time = "today"; `Hello ${name}, how are you ${time}?`
使用模板字符串表示多行字符串,所以的空格和縮進都會被保留在輸出中。
使用${}包裹一個變量或表達式。
4、變量的解構賦值
(1)數組的解構賦值
[基本用法]
let [a, b, c] = [1, 2, 3];
上面代碼表示。可以從數組中提取值,按照對應位置,給變量賦值。
本質上,這種寫法屬於“模式匹配”,只要等號兩邊模式相同,左邊的變量就會被賦予對應的值。
如果解構不成功,變量的值就等於undefined。
let [foo] = []; foo //undefined let [bar, foo] = [1]; foo //undefined
另一種情況是不完全解構,即等號左邊的模式只匹配一部分等號右邊的數組,這種情況下,解構依然成功
let [x, y] = [1, 2, 3]; x // 1 y // 2
[默認值]
解構賦值允許制定默認值。
let [foo = true] = []; foo // true
es6內部使用嚴格相等運算符(===),判斷一個位置是否有值。只有數組成員嚴格等於undefined,默認值才會生效。
let [x, y = ‘b‘] = [‘a‘]; // x=‘a‘, y=‘b‘ let [x, y = ‘b‘] = [‘a‘, undefined]; // x=‘a‘, y=‘b‘ let [x = ‘a‘] = [null]; x // null
null不嚴格等於undefined,因此默認值不生效
(2)對象的解構賦值
解構不僅可以用於數組,還可以應用於對象。
let { bar, foo } = { foo: "aaa", bar: "bbb" }; foo // "aaa" bar // "bbb"
等號左邊的兩個變量的次序,與等號右邊兩個同名屬性的次序不一致,但是對取值完全沒有影響。
let { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined
變量沒有對應的同名屬性,導致取不到值,最後等於undefined
。
對象的解構賦值的內部機制,是先找到同名屬性,然後再賦給對應的變量。真正被賦值的是後者,而不是前者。
let { foo: baz } = { foo: "aaa", bar: "bbb" }; baz // "aaa" foo // error: foo is not defined
foo
是匹配的模式,baz
才是變量。真正被賦值的是變量baz
,而不是模式foo
。
(3)字符串的解構賦值
const [a, b, c, d, e] = ‘hello‘; a // "h" b // "e" c // "l" d // "l" e // "o"
還可以對字符串的length屬性解構賦值
let { length: len } = ‘hello‘; len // 5
(4)數值和布爾值的解構賦值
解構賦值是,登等號右邊是數值或布爾值,則會先轉為對象。
let { toString: s } = 123; s === Number.prototype.toString // true let { toString: s } = true; s === Boolean.prototype.toString // true
(5)函數參數的解構賦值
函數的參數也可使用解構賦值。
function add([x, y]) { return x + y; } add([1, 2]); // 3
(6)用途
變量的解構賦值的用途:
·交換變量的值
let x = 1; let y = 2; [x, y] = [y, x];
·從函數返回多個值
函數只能返回一個值,如果要返回多個值,只能把他們放在數組或對象裏返回。有了解構賦值,取出這些值非常方便。
// 返回一個數組 function example() { return [1, 2, 3]; } let [a, b, c] = example();
// 返回一個對象 function example() { return { foo: 1, bar: 2 }; } let { foo, bar } = example();
·函數參數的定義
解構賦值可以方便地將一組參數與變量名對應。
// 參數是一組有次序的值 function f([x, y, z]) { ... } f([1, 2, 3]);
// 參數是一組無次序的值 function f({ x, y, z }) { ... } f({ z: 3, y: 2, x: 1 });
·提取數據
解構賦值對提取JSON對象中的數據尤其有用。
let jsonData = { id: 42, status: "OK", data: [867, 5309] }; let { id, status, data: number } = jsonData; console.log(id, status, number); // 42, "OK", [867, 5309]
·函數參數的默認值
指定參數的默認值,就避免了在函數內部再寫var foo = config.foo || ‘default foo’。
jQuery.ajax = function (url, { async = true, beforeSend = function () {}, cache = true, complete = function () {}, crossDomain = false, global = true, // ... more config }) { // ... do stuff };
5、函數參數的默認值
(1)默認用法
ES6
之前不能給函數參數指定默認值,只能采用變通的方法。
function log(x, y) { y = y || ‘World‘; console.log(x, y); } log(‘Hello‘) // Hello World log(‘Hello‘, ‘China‘) // Hello China log(‘Hello‘, ‘‘) // Hello World
上面的代碼檢查函數的參數y有沒有賦值,如果沒有,則指定默認值為World。但這樣的缺點在於,如果參數y賦值了,但對應的布爾值為false,則該賦值不起作用。如上面代碼最後一行,y等於空字符,結果還是被改為默認值。
為避免這個問題,通常需先判斷參數y是否被復制,如果沒有,再等於默認值。
if (typeof y === ‘undefined‘) { y = ‘World‘; }
Es6
允許函數的參數設置默認值,直接寫在參數定義的後面。
function log(x, y = ‘World‘) { console.log(x, y); } log(‘Hello‘) // Hello World log(‘Hello‘, ‘China‘) // Hello China log(‘Hello‘, ‘‘) // Hello
(2)與解構賦值默認值結合使用
函數參數默認值可以與解構賦值的默認值,結合起來使用。
function foo({ x, y = 5 }) { console.log(x, y); } foo({}) // undefined 5 foo({ x: 1 }) // 1 5 foo({ x: 1, y: 2 }) // 1 2 foo() // TypeError: Cannot read property ‘x‘ of undefined
上面的代碼只使用了對象的解構賦值默認值,沒有使用函數參數的默認值。只當函數foo的參數是一個對象時,變量x和y才會通過解構賦值生成。如果函數調用時沒提供參數,變量x和變量y就不會生成,因此報錯。提供函數的默認值就可以避免這種情況。
function foo({ x, y = 5 } = {}) { console.log(x, y); } foo() // undefined 5
上面的代碼指定,沒有提供參數,函數的參數默認為一個空對象。
// 寫法一 function m1({ x = 0, y = 0 } = {}) { return [x, y]; } // 寫法二 function m2({ x, y } = { x: 0, y: 0 }) { return [x, y]; }
上面兩張寫法都對函數的參數設定了默認值,區別是寫法一函數參數的默認值是空對象,但設置了對象解構賦值的默認值;寫法二函數參數的默認值是一個有具體屬性的對象,但是沒有設置對象解構賦值的默認值。
// 函數沒有參數的情況 m1() // [0, 0] m2() // [0, 0] // x 有值,y 無值的情況 m1({ x: 3 }) // [3, 0] m2({ x: 3 }) // [3, undefined] // x 和 y 都無值的情況 m1({}) // [0, 0]; m2({}) // [undefined, undefined]
(3)作用域
設置了參數的默認值,函數進行聲明初始化時,參數會形成單獨的作用域,初始化結束,則該作用域消失。
var x = 1; function f(x, y = x) { console.log(y); } f(2) // 2
上面代碼,y的默認值等於變量x。調用函數f時,參數形成一個單獨的作用域。在這個作用域裏,默認值變量x指向第一個參數x,而不是全局變量x,因此輸出的是2。
let x = 1; function f(y = x) { let x = 2; console.log(y); } f() // 1
上面代碼,函數f調用時,參數y=x形成一個單獨作用域,在這個作用域裏,變量x本身無定義,所以指向外層的全局變量x。函數調用時,函數體內部的局部變量x不影響默認值變量x。
var x = 1; function foo(x = x) { // ... } foo() // ReferenceError: x is not defined
上面代碼,參數x=x形成單獨作用域,實際執行的是let x = x,由暫時性死區的原因,這行代碼會報錯“x未定義”。
如過參數的默認值是一個函數,該函數的作用域也遵守這個規則。
let foo = ‘outer‘; function bar(func = () => foo) { let foo = ‘inner‘; console.log(func()); } bar(); // outer
上面代碼,函數bar的參數func的默認值是一個匿名函數,返回值為變量foo。函數參數形成的單獨作用域裏,沒有定義變量foo,因此foo指向外層的全局變量foo,因此輸出outer。
var x = 1; function foo(x, y = function () { x = 2; }) { var x = 3; y(); console.log(x); } foo() // 3 x // 1
上面代碼,函數foo的參數形成一個單獨作用域。改作用域裏,首先聲明變量x,然後聲明變量y,y
的默認值是一個匿名函數。這個匿名函數內部的變量x
,指向同一個作用域的第一個參數x
。函數foo
內部又聲明了一個內部變量x
,該變量與第一個參數x
由於不是同一個作用域,所以不是同一個變量,因此執行y
後,內部變量x
和外部全局變量x
的值都沒變。
var x = 1; function foo(x, y = function () { x = 2; }) { x = 3; y(); console.log(x); } foo() // 2 x // 1
如果將var x = 3的var去除,函數foo的內部變量x就指向第一個參數x,與匿名函數內部的x是一致的,最後輸出2,而外層的全局變量x不受影響。
6、rest參數
引入rest參數(…變量名),用於獲取函數的多余參數,這樣就不需要使用arguments對象。Rest參數搭配的變量是一個數組,將多余的參數放入數組中。
function add(...values) { let sum = 0; for (var val of values) { sum += val; } return sum; } add(2, 5, 3) // 10
add函數是一個求和函數,利用rest參數,可以向該函數傳入任意數目的參數。
// arguments變量的寫法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); }
// rest參數的寫法 const sortNumbers = (...numbers) => numbers.sort();
上面是rest參數代替arguments變量的例子。比較後可發現,rest參數的寫法更自然更簡潔。
arguments對象不是數組,是類似數組的對象,為使用數組方法,需先將其轉為數組。Rest參數就不存在這個問題,它自身就是數組。
// arguments變量的寫法 function sortNumbers() { return Array.prototype.slice.call(arguments).sort(); }
// rest參數的寫法 const sortNumbers = (...numbers) => numbers.sort();
上面是利用rest參數改寫數組push方法的例子。
需註意。Rest參數之後不能再有其他參數,即只能是最後一個參數,否則報錯。
函數的length屬性返回沒有默認值的參數的個數,其中不包括rest參數。
(function (a) { }).length // 1 (function (...a) { }).length // 0 (function (a, ...b) { }).length // 1
7、對象的擴展
(1)Es6中可以直接寫入變量和函數,作為對象的屬性和方法,使書寫更簡潔。
const foo = ‘bar‘; const baz = { foo }; baz // {foo: "bar"}
// 等同於 const baz = { foo: foo };
此時,屬性名為變量名,屬性的值為變量的值。
function f(x, y) { return { x, y }; }
// 等同於 function f(x, y) { return { x: x, y: y }; } f(1, 2) // Object {x: 1, y: 2}
方法也可以簡寫。
在一個模塊對外提供接口時非常適合使用簡潔寫法。
const getName = () => person.name;
const getAge = () => person.age;
commons的寫法:
module.exports = {
getName: getName,
getAge: getAge,
};
Es6 modules的寫法:
export default { getName, getAge };
(2)若自適應字面量方法定義對象(使用大括號),es5中只能像下面這樣定義屬性:
var obj = { foo: true, abc: 123 };
在es6中,就可以把表達式放在方括號內定義對象:
let propKey = ‘foo‘; let obj = { [propKey]: true, [‘a‘ + ‘bc‘]: 123 };
8、class
生成實例對象的傳統方法使通過構造函數,與傳統的面向對象語言差異很大,es6引入class類這個概念,通過class關鍵字可以定義類。Es6的class可以看作是一個語法糖,它的絕大部分功能,es5都可以做到,class寫法只是讓對象的寫法更清晰。
es5生成實例對象:
function Person(name, age) { this.name = name; this.age = age; } Person.prototype.getName = function () { return this.name; } var person = new Person(‘abc‘, 21);
es6用class改寫
class Person { constructor(name, age) { this.name = name; this.age = age; } getName() { return this.name } } var person = new Person(‘abc‘, 21);
constructor是構造方法,this代表實例對象,es5的構造函數Person,對應的就是Person類的構造方法,定義類方法使不需要function關鍵字,直接把函數定義放進去,另外方法之間也不需要逗號分隔。
typeof Person // "function" Person === Person.prototype.constructor // true
上面表明,類的數據類型就是函數,類本身事項構造函數。
class Person { constructor() { // ... } getName() { // ... } }
// 等同於 Person.prototype = { constructor() {}, getName() {} };
類的所有方法都定義在類的prototype屬性上。因此,類的新方法可以添加在prototype對象上。而Object.assign方法可以仿版地一次想類添加多個方法。
Object.assign(Person.prototype, {
getNmae() {},
getAge() {}
});
9、class的繼承
1)Es6中,class可以通過extends關鍵字實現繼承,比起es5的通過修改原型鏈實現繼承方便的多。
class Person { constructor(name, age) { this.name = name; this.age = age; } getName() { return this.name } }
// Student類繼承Person類 class Student extends Person { constructor(name, age, gender, classes) { super(name, age); this.gender = gender; this.classes = classes; } getGender() { return this.gender; } }
不用像es5那樣需要考慮構造函數繼承哈斯原型繼承,只需要使用extends關鍵字並關註一個叫super的方法。
如果不使用super方法,在新建實例時就會報錯。
Es5的繼承,實質是縣創造子類實例對象的this,在將父類的方法添加到this(Parent.apply(this))。 而es6的繼承機制完全不同,實質是先創造父類的實例對象this(所以必須先調用super方法),然後再用子類構造函數修改this。
如果子類沒有定義constructor(),也會被默認添加。即任何一個子類都有constructor方法。
class Student extends Person {} // 等同於 class Student extends Person { constructor(...args) { super(...args); } }
需要註意,只有調用super以後才能使用this,否則報錯。因為上面說過,子類實例的構建,是基於父類實例加工,super方法返回父類實例。
1) super關鍵字既可以當作函數使用也可以當作對象使用。
·Super作為函數調用時,代表父類的構造函數,子類的構造數必須執行一次super函數。
class A {}
class B extends A {
constructor() {
super();
}
}
Super雖然代表了父類A的工業早函數,但返回的是子類B的實例,即super內部的this指的是B,因此super在這裏相當於A.prototype.constructor.call(this)。
class A { constructor() { console.log(new.target.name); } } class B extends A { constructor() { super(); } } new A() // A new B() // B
new.target指向當前正在執行的函數。從上面的代碼可以看出:在super執行時,它指向的是子類B的構造函數,即super內部的this指向B
並且,作為函數是,super只能用在子類的構造函數之中,否則報錯。
·第二種情況,super作為對象。在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。
class A { p() { return 2; } } class B extends A { constructor() { super(); console.log(super.p()); // 2 } } let b = new B();
上面代碼中,子類B的super.p就是把super當做對象使用,此時super在普通方法中,指向A.prototype,因此super.p()就相當於A.prototype.p()。
註意:定義在父類實例上的方法、屬性無法通過super調用。
class A { constructor() { this.x = 1; } print() { console.log(this.x); } } class B extends A { constructor() { super(); this.x = 2; } m() { super.print(); } } let b = new B(); b.m() // 2
super.print()雖然調用的是A.prototype.print(),但A.prototype.print()內部的this指向子類B,因此輸出2,而不是1。實際上執行的是super.print.call(this)。
如果super作為對象,用在靜態方法中,super就指向父類,而不是父類的原型對象。
class Parent { static myMethod(msg) { console.log(‘static‘, msg); } myMethod(msg) { console.log(‘instance‘, msg); } } class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); } } Child.myMethod(1); // static 1 var child = new Child(); child.myMethod(2); // instance 2
上面的代碼,super在靜態方法中指向父類,在普通方法中指向父類的原型對象。
10、promise(項目中ajax.js中使用)
promise的作用與回調方法(callback)一樣,都是在某種情況下執行設定好的方法。但promise的多重鏈式調用能使代碼更整潔,避免出現“回調地獄”(回調嵌套太多層)。在es6中,promise成為了原生對象可以直接使用。
Ajax請求的傳統寫法:
改為promise寫法:
很顯然,promise的寫法把異步調用中使用回調函數的場景改為了.then()、.catch()等函數鏈式調用的方式,基於promise可以把復雜的異步調用方式進行模塊化。
Promise的原理分析:
Promise對象共有三個狀態,分別是:
·pending(進行中)
·resolved(已完成,又稱為fullfilled)
·rejected(已失敗)
由異步操作的結果決定當前是什麽狀態。狀態的改變只有兩種可能:
·從pending變為fullfilled
·從pending變為rejected
只要這兩種情況發生,狀態就不會再改變了,因此狀態是不能逆向改變的。
構建promise:
Promise的構造函數接受一個函數作為參數,該函數的兩個參數分別為resolve和reject兩個函數。
·Resolve函數將promise對象的狀態由pending變為resolved,異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去。
·reject函數將狀態由pending變為rejected,異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。
Promise的實例方法:
Promise對象擁有兩個實例方法then()和catch()。
·then()方法接受兩個函數作為參數,第一個是狀態變為resolved時調用,第二個則是狀態變為rejected是調用,第二個函數是可選的。
Promise實例生成以後,可以用then
方法指定resolved
狀態和rejected
狀態的回調函數,即成功和失敗的回調函數。
promise
構造函數中通常都是異步的,所以then
方法往往都先於resolve
和reject
方法執行。這兩個函數作為成功和失敗的回調函數,都接受promise對象傳出的值作為參數。
then()方法將返回一個新的promise。
因此then可以鏈式調用,在新的對象上添加失敗或成功的回調。
·catch()方法的作用是捕獲promise的錯誤。
與then()方法的rejected回調作業幾乎一致。
我們知道,如果 Promise 狀態已經變成resolved
,再拋出錯誤是無效的。
上面代碼中,Promise 在resolve
語句後面,再拋出錯誤,不會被捕獲,等於沒有拋出。因為 Promise 的狀態一旦改變,就永久保持該狀態,不會再變了。
promise對象的錯誤會一直向後傳遞,直到被捕獲,即錯誤總會被下一個catch
所捕獲。then
方法指定的回調函數,若拋出錯誤,也會被下一個catch
捕獲。catch
中也能拋錯,則需要後面的catch
來捕獲。
因此一般來說,不要在then
方法裏面定義 Reject 狀態的回調函數(即then
的第二個參數),總是使用catch
方法。
這樣就能夠在下一個catch()中統一處理這些錯誤。同時catch()也能夠捕獲then()中拋出的錯誤,所以建議不使用then()的rejected回調,而是統一使用catch()來處理錯誤。
跟傳統的try/catch
代碼塊不同的是,如果沒有使用catch
方法指定錯誤處理的回調函數,Promise 對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。Promise 內部的錯誤不會影響到 Promise 外部的代碼。
11、Module(項目中常用)
ES6實現了模塊功能,可以取代CommonJS和AMD規範,稱為瀏覽器和服務器通用的模塊解決方案。
模塊功能主要由兩個命令構成:export和import。
Export用於規定模塊的對外接口,import用於輸入其他模塊提供的功能。
一個模塊即一個獨立文件。該文件內部的所有變量,在外部是無法獲取的。如果需要讀取模塊內的某個變量,就必須使用export輸出該變量。
(1)export
export可以輸出變量:
// profile.js export var firstName = ‘Michael‘; export var lastName = ‘Jackson‘; export var year = 1958;
或者用大括號指定要輸出的一組變量:
// profile.js var firstName = ‘Michael‘; var lastName = ‘Jackson‘; var year = 1958; export { firstName, lastName, year };
除了輸出變量,還可以輸出函數或class類
export function multiply(x, y) { return x * y; };
(2)import
使用export定義了,模塊對外的幾口以後,其他js文件就可以通過import加載這個模塊。
// main.js import { firstName, lastName, year } from ‘./profile.js‘; function setName(element) { element.textContent = firstName + ‘ ‘ + lastName; }
Import接收一堆大括號,裏面指定要從其他模塊導入的變量名,變量名必須與被導入模塊(profile.js)對外接口的名稱相同。
Import輸入的變量都是只讀的,不允許在加載模塊的腳本裏改寫接口。
From指定模塊文件的位置,.js後綴可以省略。
Import具有提升效果,會提升到整個模塊的頭部首先執行。
(3)export default
使用export default為模塊指定默認輸出。
// export-default.js export default function () { console.log(‘foo‘); }
默認輸出一個匿名函數
// import-default.js import customName from ‘./export-default‘; customName(); // ‘foo‘
加載該模塊時,import為函數指定名字。
需要註意的是export default對應的import不需要使用大括號{}。而export對應的import需要使用大括號。
es6 學習心得