var、let、const
var
在講解 let、const 之前,先來了解下 var,
var 宣告陳述句宣告一個變數,并可選地將其初始化為一個值,
- var 用以宣告變數;
- var 宣告的變數,不存在塊級作用域,在全域范圍內都有效;
- var 存在變數提升現象,因此 var 定義的變數可以先使用,后宣告;
example one:
function fn() {
var a = 1
console.log(a) // 1
}
fn()
example two:
function fn() {
if (true) {
console.log(a) // undefined
} else {
var a = 1
}
}
fn()
上面這段代碼列印出 undefined 是因為 var 變數提升,代碼等價于:
function fn() {
var a
if (true) {
console.log(a)
} else {
a = 1
}
}
fn()
example three:
現在有如下代碼,如何只暴露 fn 一個全域變數呢?
var a = 1
window.fn1 = function() {
console.log(a)
}
因為var a = 1會產生一個全域變數 a
假如我們把代碼包裹在一個函式里,代碼如下:
function fn2() {
var a = 1
window.fn1 = function() {
console.log(a)
}
}
如果像上面這樣,a 雖然是區域變數了,但是呢,這個函式有名字 fn2,也是一個全域變數
所以使用立即執行函式,代碼如下:
(function() {
var a = 1
window.fn1 = function() {
console.log(a)
}
}())
但是這段代碼太麻煩了,在ES6中,使用let就可以很方便解決此問題!
let
let 陳述句宣告一個塊級作用域的本地變數,并且可選的將其初始化為一個值,
- let 關鍵字用來宣告變數;
- let 關鍵字宣告的變數不能重復宣告;
- 存在塊級作用域,只在其宣告的塊或子塊中可用;
- 不存在變數提升,只可以先宣告,后使用;
- let 宣告的變數存在暫時性死區,只要塊級作用域中存在 let,那么它所宣告的變數就系結了這個區域,不再受外部的影響;
example one:
{
let a = 1
console.log(a) // 1
{
let a = 2
console.log(a) // 2
}
}
example two:
{
let a = 1
console.log(a) // 1
{
console.log(a) // 報錯
let a = 2
}
}
example three:
{
let a = 1
console.log(a) // 1
let a = 2 // 報錯,a已經宣告
}
const
const 關鍵字用來宣告常量,常量是塊級作用域,很像使用 let 陳述句定義的變數,常量的值不能通過重新賦值來改變,并且不能重新宣告,
- const 在宣告時必須賦予初始值,一旦宣告,其宣告的值就不允許改變,更不允許重復宣告;
- const 用于宣告只讀的常量;
- 存在塊級作用域,只在其宣告的塊或子塊中可用;
- 識別符號一般為大寫;
- 不存在變數提升,只可以先宣告,后使用;
- const 宣告的變數存在暫時性死區,只要塊級作用域中存在 const,那么它所宣告的變數就系結了這個區域,不再受外部的影響;
example one:
{
const a = 1
console.log(a) // 1
a = 2 // 報錯
}
example two:
const arr = [1, 2, 3]
arr[0] = 2
console.log(arr) // [2, 2, 3]
const obj = {
name: 'zww',
age: 18
}
obj.name = 'lq'
console.log(obj) // {name: "lq", age: 18}
注意:對于陣列和物件的元素修改,不算做對常量的修改,不會報錯,
相關題目
Question One
var a = 1
function fn() {
console.log(a)
}
? ? ? ?
fn()
答:
var a = 1
function fn() {
console.log(a) // 2
}
a = 2
fn()
Question Two
下面代碼將列印什么?
for (var i = 0; i < 5; i++) {}
console.log(i)
答:
以上代碼等價于:
var i
for (i = 0; i < 5; i++) {}
console.log(i) // 5
Question Three
下面代碼將列印什么?
for (var i = 0; i < 5; i++) {
function fn() {
console.log(i)
}
button.onclick = fn
}
console.log(i)
答:都將列印5
Question Four
點擊第三個li將列印什么,如何解決此問題?
var liTags = document.querySelectorAll('li') // 假設只有6個li
for (var i = 0; i < liTags.length; i++) {
liTags[i].onclick = function() {
console.log(i)
}
}
答:不管點擊哪個li都將列印出6!
method one:
var liTags = document.querySelectorAll('li')
for (var i = 0; i < liTags.length; i++) {
let j = i
liTags[j].onclick = function() {
console.log(j)
}
}
method two:
var liTags = document.querySelectorAll('li')
for (var i = 0; i < liTags.length; i++) {
(function(j) {
liTags[j].onclick = function() {
console.log(j)
}
})(i)
}
method three:
var liTags = document.querySelectorAll('li')
for (let i = 0; i < liTags.length; i++) {
liTags[i].onclick = function() {
console.log(i)
}
}
參考資料
阮一峰 - let和const命令
MDN - var
MDN - let
MDN - const
知乎 - 我用了兩個月的時間才理解let
變數的解構賦值
ES6 允許按照一定模式,從陣列和物件中提取值,對變數進行賦值,這被稱為解構賦值,
陣列的解構賦值
let name = ['zww', 'lq', 'lqzww']
let [a, b, c, d] = name
console.log(a, b, c, d); // zww lq lqzww undefined
物件的解構賦值
let info = {
name: 'zww',
age: 18,
like: function() {
console.log("game");
}
}
let { name, age, like } = info
console.log(name, age, like); // zww 18 ? ()
like() // game
字串的解構賦值
字串也可以解構賦值,這是因為此時,字串被轉換成了一個類似陣列的物件,
let str = 'hello'
let [a, b, c, d, e, f] = str
console.log(a, b, c, d, e, f) // h e l l o undefined
let { length: len } = str
console.log(len) // 5
字串的擴展
模板字串
模板字串是字串的增強版寫法,用反引號(`)標識,它可以當作普通字串使用,也可以用來定義多行字串,或者在字串中嵌入變數,
- 模板字串中可以出現換行符;
- 可以使用 ${xxx} 的形式嵌入變數;
- 模板字串中還能呼叫函式;
let str = `我也是字串`
console.log(str, typeof str); // 我也是字串 string
let name = `<ul><li>a</li><li>b</li></ul>`
let like = 'game'
let out = `${like}喜歡`
console.log(out); // game喜歡
function fn() {
console.log("fn")
}
`${fn()}` // fn
trimStart()、trimEnd()
它們的行為與 trim() 一致,trimStart() 消除字串頭部的空格,trimEnd() 消除尾部的空格,它們回傳的都是新字串,不會修改原始字串,
除了空格鍵,這兩個方法對字串頭部(或尾部)的 tab 鍵、換行符等不可見的空白符號也有效,
瀏覽器還部署了額外的兩個方法,trimLeft() 是 trimStart() 的別名,trimRight() 是 trimEnd() 的別名,
let str = ' hello world '
console.log(str) // hello world
console.log(str.trimStart()) // hello world
console.log(str.trimEnd()) // hello world
陣列的擴展
擴展運算子
擴展運算子(spread)是三個點(...),它好比 rest 引數的逆運算,將一個陣列轉為用逗號分隔的引數序列,對陣列進行解包,
let name = ['zww', 'lq', 'lqzww']
function fn() {
console.log(arguments) // Arguments [Array(3), callee: ?, Symbol(Symbol.iterator): ?]
console.log(...arguments) // (3) ["zww", "lq", "lqzww"]
}
fn(name)
// 擴展運算子可用于陣列的合并
let name = ['zww', 'lq', 'lqzww']
let age = [18, 20]
var info = [...name, ...age]
console.log(info) // (5) ["zww", "lq", "lqzww", 18, 20]
// 擴展運算子可用于陣列的克隆 - 淺拷貝
let name = ['zww', 'lq', 'lqzww']
let copyName = [...name]
console.log(copyName) // (3) ["zww", "lq", "lqzww"]
// 擴展運算子可將偽陣列轉為真正的陣列
<div></div>
<div></div>
var div = document.querySelectorAll("div")
var arrDiv = [...div]
console.log(div) // NodeList(2) [div, div]
console.log(arrDiv) // (2) [div, div]
Array.from()
Array.from() 方法用于將兩類物件轉為真正的陣列:類似陣列的物件(array-like object)和可遍歷(iterable)的物件(包括 ES6 新增的資料結構 Set 和 Map),
let arr = {
'0': 'a',
'1': 'b',
'2': 'c',
length: 3
};
console.log(Array.from(arr)) // (3) ["a", "b", "c"]
Array.of()
Array.of() 方法用于將一組值,轉換為陣列,
Array.of() 總是回傳引數值組成的陣列,如果沒有引數,就回傳一個空陣列,
console.log(Array.of(1, 2, 3)) // (3) [1, 2, 3]
console.log(Array.of()) // []
includes()
該方法表示某個陣列是否包含給定的值,回傳一個布林值,
該方法的第二個引數表示搜索的起始位置,默認為 0,如果第二個引數為負數,則表示倒數的位置,
let arr = ['天龍八部', '英雄聯盟', '王者榮耀', '部落沖突']
console.log(arr.includes('天龍八部')) // true
console.log(arr.includes('皇室戰爭')) // false
console.log(arr.includes('天龍八部', 1)) // false
flat()、flatMap()
flat()
flat() 用于將嵌套的陣列“拉平”,變成一維的陣列,該方法回傳一個新陣列,對原資料沒有影響,
flat() 默認只會“拉平”一層,如果想要“拉平”多層的嵌套陣列,可以將 flat() 方法的引數寫成一個整數,表示想要拉平的層數,默認為1,如果引數為 Infinity,表示可展開任意深度的嵌套陣列,
let arr = [1, 2, [3, 4, [5, 6, [7]]]]
console.log(arr.flat()) // (5) [1, 2, 3, 4, Array(3)]
console.log(arr.flat(2)) // (7) [1, 2, 3, 4, 5, 6, Array(1)]
console.log(arr.flat(Infinity)) // (7) [1, 2, 3, 4, 5, 6, 7]
flatMap()
flatMap() 方法對原陣列的每個成員執行一個函式(相當于執行Array.prototype.map()),然后對回傳值組成的陣列執行 flat() 方法,該方法回傳一個新陣列,不改變原陣列,
flatMap() 方法的引數是一個遍歷函式,該函式可以接受三個引數,分別是當前陣列成員、當前陣列成員的位置(從零開始)、原陣列,
let arr = [1, 2, 3]
let res1 = arr.map(item => [item * 2])
console.log(res1) // (3) [Array(1), Array(1), Array(1)]
let res2 = arr.flatMap(item => [item * 2])
console.log(res2) // (3) [2, 4, 6]
函式的擴展
函式引數默認值
ES6 允許為函式的引數設定默認值,即直接寫在引數定義的后面,
function add(a, b) {
return a + b;
}
console.log(add(1, 2)); // 3
console.log(add(1)); // NaN
function add(a, b = 10) {
return a + b;
}
console.log(add(1, 2)); // 3
console.log(add(1)); // 11
rest引數
ES6 引入 rest 引數(形式為...變數名),用于獲取函式的多余引數,用來代替 arguments,rest 引數搭配的變數是一個陣列,該變數將多余的引數放入陣列中,
function fn(...args) {
console.log(args)
}
fn(1, 2) // (2) [1, 2]
function fn(a, b, ...args) {
console.log(args)
}
fn(1, 2, 3, 4, 5) // (3) [3, 4, 5]
注意:rest 引數必須要放到引數最后,
箭頭函式
ES6 允許使用“箭頭”(=>)定義函式,
let fn1 = function() {}
// 等價于
let fn2 = () => {}
// 簡寫形式
var f = x => n * n
var f = (x, y) => x + y
var f = (x, y) => {
return x + y
}
// 箭頭函式 this 指向宣告時所在作用域下 this 的值
let fn1 = function() {
console.log(this.name);
}
let fn2 = () => {
console.log(this.name);
}
var name = 'zww';
const home = {
name: "home"
}
fn1() // zww
fn2() // zww
fn1.call(home) // home
fn2.call(home) // zww
// 箭頭函式不能作為建構式實體化
let Person = name => {
this.name = name;
}
let person = new Person('zww');
console.log(person); // 報錯:Person is not a constructor
// 箭頭函式不能使用 arguments
let fn = () => {
console.log(arguments);
}
fn(1, 2); // 報錯:arguments is not defined
總結:
- 如果形參只有一個,那么小括號可以省略;
- 函式體如果只有一條陳述句,則花括號可以省略,函式的回傳值為該條陳述句的執行結果;
- 箭頭函式 this 指向宣告時所在作用域下 this 的值;
- 箭頭函式不能作為建構式實體化,也就是說,不可以使用new命令,否則會拋出一個錯誤,
- 不能使用 arguments,該物件在函式體內不存在,如果要用,可以用 rest 引數代替,
數值的擴展
二進制和八進制表示法
ES6 提供了二進制和八進制數值的新的寫法,分別用前綴 0b(或0B)和 0o(或0O)表示,
如果要將 0b 和 0o 前綴的字串數值轉為十進制,要使用 Number 方法,
let b = 0b111;
console.log(b) // 7
let o = 0o234;
console.log(o) // 156
let x = 0xabc;
console.log(x) // 2748
console.log(Number('0b111')) // 7
console.log(Number('0o10')) // 8
Number.EPSILON
ES6 在 Number 物件上面,新增一個極小的常量 Number.EPSILON,它表示 1 與大于 1 的最小浮點數之間的差,
Number.EPSILON 實際上是 JavaScript 能夠表示的最小精度,誤差如果小于這個值,就可以認為已經沒有意義了,即不存在誤差了,
Number.EPSILON 的實質是一個可以接受的最小誤差范圍,
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(0.1 + 0.2 === 0.3) // false
console.log(equal(0.1 + 0.2, 0.3)) // true
Number.isFinite() 與 Number.isNaN()
Number.isFinite() 用來檢查一個數值是否為有限的(finite),即不是 Infinity,如果引數型別不是數值,Number.isFinite 一律回傳 false,
Number.isNaN() 用來檢查一個值是否為 NaN,如果引數型別不是 NaN,Number.isNaN 一律回傳 false,
console.log(Number.isFinite(1)) // true
console.log(Number.isFinite(1 / 0)) // false
console.log(Number.isFinite(Infinity)) // false
console.log(Number.isFinite(-Infinity)) // false
console.log(Number.isNaN(1)) // false
console.log(Number.isNaN(NaN)) // true
console.log(Number.isNaN(NaN / 0)) // true
console.log(Number.isNaN('true' / 0)) // true
console.log(Number.isNaN('true' / 'true')) // true
Number.parseInt() 與 Number.parseFloat()
ES6 將全域方法 parseInt() 和 parseFloat(),移植到 Number 物件上面,行為完全保持不變,
console.log(Number.parseInt('1.34abc')) // 1
console.log(Number.parseFloat('1.34abc')) // 1.34
Number.isInteger()
Number.isInteger() 用來判斷一個數值是否為整數,
console.log(Number.isInteger(123)) // true
console.log(Number.isInteger(1.34)) // false
Math.trunc()
Math.trunc 方法用于去除一個數的小數部分,回傳整數部分,
console.log(Math.trunc(123)) // 123
console.log(Math.trunc(1.34)) // 1
Math.sign()
Math.sign 方法用來判斷一個數到底是正數、負數、還是零,對于非數值,會先將其轉換為數值,
它有如下五種回傳值:
- 引數為正數,回傳 +1;
- 引數為負數,回傳 -1;
- 引數為 0,回傳 0;
- 引數為 -0,回傳 -0;
- 其他值,回傳 NaN,
console.log(Math.sign(0)) // 0
console.log(Math.sign(-0)) // -0
console.log(Math.sign(1)) // 1
console.log(Math.sign(-1)) // -1
console.log(Math.sign(NaN)) // NaN
指數運算子
指數運算子(**)用來實作冪運算,功能與 Math.pow 結果相同,
console.log(Math.pow(2, 10)) // 1024
console.log(2 ** 10) // 1024
console.log(2 ** 3 ** 2) // 512
注意:指數運算子的一個特點是右結合,而不是常見的左結合,多個指數運算子連用時,是從最右邊開始計算的,
物件的擴展
簡化物件的寫法
ES6 允許在大括號里面,直接寫入變數和函式,作為物件的屬性和方法,這樣的書寫更加簡潔,
let name = 'zww'
let change = function() {
console.log('change');
}
let info = {
name,
change,
like() {
console.log('game');
}
}
console.log(info); // {name: "zww", change: ?, like: ?}
Object.is()
Object.is() 它是用來比較兩個值是否嚴格相等,回傳true / false,與嚴格比較運算子(===)的行為基本一致,
Object.is() 方法如果滿足以下條件則兩個值相等:
- 都是undefined;
- 都是null;
- 都是true或false;
- 都是相同長度的字串且相同字符按相同順序排列;
- 都是相同物件(意味著每個物件有同一個參考);
- 都是數字且都是+0;都是-0;都是NaN;或都是非零而且非 NaN且為同一個值;
Object.is('hello','hello') // true
Object.is('hello','hi') // false
Object.is([],[]) // false
Object.is(null,null) // true
Object.is(null,undefined) // false
Object.is(0,+0) // true
Object.is(0,-0) // false
Object.is(-0,+0) // false
Object.is(NaN,0/0) // true
Object.assign()
Object.assign() 方法用于物件的合并,將源物件(source)的所有可列舉屬性,復制到目標物件(target),
Object.assign() 方法的第一個引數是目標物件,后面的引數都是源物件,
let obj1 = {
name: 'zww',
age: 18,
like: 'game'
}
let obj2 = {
name: 'lq',
age: 111,
size: 22
}
console.log(Object.assign(obj1, obj2)) // {name: "lq", age: 111, like: "game", size: 22}
注意:
- 如果目標物件與源物件有同名屬性,或多個源物件有同名屬性,則后面的屬性會覆寫前面的屬性;
- 如果只有一個引數,Object.assign() 會直接回傳該引數;
- 如果該引數不是物件,則會先轉成物件,然后回傳;
- 由于 undefined 和 null 無法轉成物件,所以如果它們作為引數,就會報錯;
- Object.assign() 方法實行的是淺拷貝,而不是深拷貝,也就是說,如果源物件某個屬性的值是物件,那么目標物件拷貝得到的是這個物件的參考;
該方法有如下常見用途:
- 為物件添加屬性
- 為物件添加方法
- 克隆物件
- 合并多個物件
- 為屬性指定默認值
Object.setPrototypeOf()、Object.getPrototypeOf()
Object.setPrototypeOf():用來設定一個物件的原型物件(prototype),回傳引數物件本身,
Object.getPrototypeOf():用于讀取一個物件的原型物件,
let a = {
name: 'zww'
}
let b = {
age: 18
}
console.log(Object.setPrototypeOf(a, b)) // {name: "zww"}
console.log(Object.getPrototypeOf(a)) // {age: 18}
Object.keys()、Object.values()、Object.entries()
Object.keys()
ES5 引入了 Object.keys 方法,回傳一個陣列,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名,
ES2017 引入了跟 Object.keys 配套的 Object.values 和 Object.entries,作為遍歷一個物件的補充手段,供 for...of 回圈使用,
var obj = {
name: 'zww',
age: 22
};
console.log(Object.keys(obj)) // (2) ["name", "age"]
Object.values()
Object.values 方法回傳一個陣列,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值,它只回傳物件自身的可遍歷屬性,
var obj = {
name: 'zww',
age: 22
};
console.log(Object.values(obj)) // (2) ["zww", 22]
Object.entries()
Object.entries() 方法回傳一個陣列,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值對陣列,
var obj = {
name: 'zww',
age: 22
};
console.log(Object.entries(obj)) // (2) [Array(2), Array(2)]
Object.entries 方法的另一個用處是,將物件轉為真正的 Map 結構,
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors() 方法,回傳指定物件所有自身屬性(非繼承屬性)的描述物件,
var obj = {
name: 'zww',
age: 22
}
console.log(Object.getOwnPropertyDescriptors(obj)) // {name: {…}, age: {…}}
Object.fromEntries()
Object.fromEntries() 方法是 Object.entries() 的逆操作,用于將一個鍵值對陣列轉為物件,
該方法的主要目的,是將鍵值對的資料結構還原為物件,因此特別適合將 Map 結構轉為物件,
let arr = Object.fromEntries([
['name', 'zww'],
['age', 18]
])
console.log(arr) // {name: "zww", age: 18}
let m = new Map()
m.set('name', 'lq')
let res = Object.fromEntries(m)
console.log(res) // {name: "lq"}
Symbol
ES6 引入了一種新的原始資料型別 Symbol,表示獨一無二的值,它是JavaScript 語言的第七種資料型別,前六種是:undefined、null、布林值(Boolean)、字串(String)、數值(Number)、物件(Object),
// 通過 Symbol() 創建
let s = Symbol()
console.log(s, typeof s) // Symbol() "symbol"
let s1 = Symbol('zww')
let s2 = Symbol('zww')
console.log(s1 == s2) // false
console.log(s1 === s2) // false
// 通過 Symbol.for() 創建
let s = Symbol.for('1')
console.log(s, typeof s) // Symbol(1) "symbol"
let s1 = Symbol.for('zww')
let s2 = Symbol.for('zww')
console.log(s1 == s2) // true
console.log(s1 === s2) // true
// 物件添加 Symbol 型別的兩種方式
// 第一種
let info = {
name: 'zww',
like: function() {}
}
let myInfo = {
like: Symbol()
}
info[myInfo.like] = function() {
console.log('hh')
}
console.log(info) // {name: "zww", like: ?, Symbol(): ?}
// 第二種
let game = {
name: 'tlbb',
[Symbol('ts')]: function() {},
[Symbol('em')]: function() {}
}
console.log(game) // {name: "tlbb", Symbol(ts): ?, Symbol(em): ?}
注意:
- Symbol 的值是唯一的,用來解決命名沖突的問題
- Symbol 值不能與其他資料進行運算
- Symbol 定義的物件屬性不能使用 for…in 回圈遍歷,但是可以使用 Reflect.ownKeys 來獲取物件的所有鍵名
阮一峰 - Symbol
迭代器
遍歷器(Iterator)就是這樣一種機制,它是一種介面,為各種不同的資料結構提供統一的訪問機制,任何資料結構只要部署 Iterator 介面,就可以完成遍歷操作(即依次處理該資料結構的所有成員),
Iterator 的作用有三個:一是為各種資料結構,提供一個統一的、簡便的訪問介面;二是使得資料結構的成員能夠按某種次序排列;三是 ES6 創造了一種新的遍歷命令for...of回圈,Iterator 介面主要供for...of消費,
原生具備 Iterator 介面的資料(可用 for of 遍歷)的有:Array、Arguments、Set、Map、String、TypedArray、NodeList,
let arr = [1, 2, 3]
for (let i of arr) {
console.log(i) // 1 2 3
}
Iterator 的作業原理如下:
- 創建一個指標物件,指向當前資料結構的起始位置;
- 第一次呼叫物件的 next 方法,指標自動指向資料結構的第一個成員;
- 接下來不斷的呼叫 next 方法,指標一直往后移動,直到指向最后一個成員;
- 每呼叫 next 方法回傳一個包含 value 和 done 屬性的物件;
let arr = [1, 2, 3]
let iterator = arr[Symbol.iterator]();
console.log(iterator) // Array Iterator {}
console.log(iterator.next()); // {value: 1, done: false}
console.log(iterator.next()); // {value: 2, done: false}
console.log(iterator.next()); // {value: 3, done: false}
console.log(iterator.next()); // {value: undefined, done: true}
使用迭代器可以自定義遍歷資料,例如:
// 遍歷 info 里的 like 陣列
const info = {
name: "zww",
like: ['tlbb', 'xylm', 'wzry'],
[Symbol.iterator]() {
let index = 0;
let that = this;
return {
next: function() {
if (index < that.like.length) {
const result = {
value: that.like[index],
done: false
};
index++;
return result;
} else {
return {
value: undefined,
done: true
}
}
}
}
}
}
for (let i of info) {
console.log(i); // tlbb xylm wzry
}
阮一峰 - Iterator 和 for...of 回圈
生成器
Generator 函式是 ES6 提供的一種異步編程解決方案,語法行為與傳統函式完全不同,
function* gen() {
yield 'hi'
yield 'generator'
}
let iterator = gen()
console.log(iterator) // gen {<suspended>}
console.log(iterator.next()) // {value: "hi", done: false}
console.log(iterator.next()) // {value: "generator", done: false}
console.log(iterator.next()) // {value: undefined, done: true}
生成器函式可以傳入引數:
function* gen(arg) {
console.log(arg)
let one =
yield 'one'
console.log(one)
let two =
yield 'two'
console.log(two)
}
let iterator = gen('A')
console.log(iterator.next())
console.log(iterator.next('B'))
console.log(iterator.next('CCC'))
使用生成器函式可以避免回呼地獄:
function one() {
setTimeout(() => {
let data = 'https://www.cnblogs.com/LqZww/archive/2020/09/28/tlbb'
iterator.next(data);
}, 1000)
}
function two() {
setTimeout(() => {
let data = 'https://www.cnblogs.com/LqZww/archive/2020/09/28/yxlm'
iterator.next(data);
}, 2000)
}
function* gen() {
let t = yield one();
console.log(t)
let y = yield two();
console.log(y)
}
let iterator = gen();
iterator.next();
注意:
-
- 的位置沒有限制,但必須在 function 與函式名之間;
- 生成器函式回傳的結果是迭代器物件,呼叫迭代器物件的 next 方法可以得到 yield 陳述句后的值;
- yield 相當于函式的暫圖示記,也可認為是函式的分隔符,每呼叫一次 next 方法,執行一段代碼;
- next 方法可以傳遞實參,作為 yield 陳述句的回傳值;
阮一峰 - Generator 函式的語法
Promise
傳送門 - Promise從入門到放棄
async、await - 待完善
Set
ES6 提供了新的資料結構 Set(集合),它類似于陣列,但是成員的值都是唯一的,沒有重復的值(自帶去重),它實作了 iterator 介面,所以可以使用擴展運算子、for...of,
Set 本身是一個建構式,用來生成 Set 資料結構,
let s = new Set()
console.log(s, typeof s) // Set(0) {} "object"
Set 結構的實體具有以下幾個屬性:
- Set.prototype.constructor:建構式,默認就是Set函式;
- Set.prototype.size:回傳 Set 實體的成員總數;
Set 實體的方法分為兩大類,分別為操作方法和遍歷方法,
操作方法如下:
- .add(value):用于添加某個值,回傳 Set 結構本身;
- .delete(value):用于洗掉某個值,回傳的是布林值,表示是否洗掉成功;
- .has(value):用于檢測該值是否為 Set 成員,回傳一個布林值;
- .clear():用于清除 Set 所有成員,沒有回傳值;
let s = new Set([1, 2, 3, 2, 1])
console.log(s) // Set(3) {1, 2, 3}
console.log(s.size) // 3
console.log(s.add(4)) // Set(4) {1, 2, 3, 4}
console.log(s.delete(1)) // true
console.log(s) // Set(3) {2, 3, 4}
console.log(s.has(2)) // true
s.clear()
console.log(s) // Set(0) {}
遍歷方法如下:
- .keys():回傳鍵名的遍歷器;
- .values():回傳鍵值的遍歷器;
- .entries():回傳鍵值對的遍歷器;
- .forEach():使用回呼函式遍歷每個成員;
注意:Set 的遍歷順序就是插入順序,
阮一峰 - ECMAScript6入門 - Set
Map
ES6 提供了 Map 資料結構,它類似于物件,也是鍵值對的集合,但是“鍵”的范圍不限于字串,各種型別的值(包括物件)都可以當作鍵,也就是說,Object 結構提供了“字串—值”的對應,Map 結構提供了“值—值”的對應,是一種更完善的 Hash 結構實作,它也實作了 iterator 介面,所以可以使用擴展運算子、for...of,
let m = new Map()
console.log(m, typeof m) // Map(0) {} "object"
Map 結構的實體具有以下屬性和操作方法:
- .size:回傳 Map 結構的成員總數;
- .set(key, value):設定鍵名 key 對應的鍵值為 value,回傳整個 Map 結構,如果key已經有值,則鍵值會被更新,否則就新生成該鍵,set 方法回傳的是當前的 Map 物件,因此可以采用鏈式寫法;
- .get(key):讀取 key 對應的鍵值,如果找不到 key,回傳 undefined;
- .has(key):表示某個鍵是否在當前 Map 物件之中,回傳一個布林值;
- .delete(key):洗掉某個鍵,回傳 true,如果洗掉失敗,回傳 false;
- .clear():清除所有成員,沒有回傳值;
let m = new Map()
m.set("name", "zww")
m.set("like", function() {
console.log("game")
})
console.log(m) // Map(2) {"name" => "zww", "like" => ?}
console.log(m.size) // 2
console.log(m.get("name")) // zww
console.log(m.get("age")) // undefined
console.log(m.has("name")) // true
console.log(m.delete("like")) // true
console.log(m) // Map(1) {"name" => "zww"}
m.clear()
console.log(m) // Map(0) {}
阮一峰 - ECMAScript6入門 - Map
class
基本用法
在沒有ES6 class之前的常規寫法:
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.sayHi = function(sing) {
console.log(this.name + "唱了" + sing)
}
var zname = new Person('zww', 22)
console.log(zname) // Person {name: "zww", age: 22}
zname.sayHi('啊哈哈') // zww唱了啊哈哈
在 ES6 中新增加了類的概念,可以使用 class 關鍵字宣告一個類,之后以這個類來實體化物件,
類抽象了物件的公共部分,它泛指某一大類,
物件特指某一個,通過類實體化一個具體的物件,
class Star {
constructor(name, age) {
this.name = name
this.age = age
}
sayHi(sing) {
console.log(this.name + "唱了" + sing);
}
}
var zname = new Star("zww", 11)
console.log(zname); // Star {name: "zww", age: 11}
zname.sayHi("我愛你") // zww唱了我愛你
注意:
- 類必須使用new實體化物件
- 通過class關鍵字創建類,類名首字母一般大寫
- 類里面有個constructor函式,可以接收傳遞過來的引數,同時回傳實體物件
- 類里面所有函式都不需要寫function
- 多個函式方法之間不需要用逗號隔開
類的繼承
JavaScript中的類可以繼承某個類,其中被繼承的類稱為父類,而繼承父類的被稱為子類,
子類可以有自己的函式和構造器,當子類中存在父類相同的方法時,則該方法不會從父類繼承,而使用子類的方法,
class Father {
constructor(name, age) {
this.name = name
this.age = age
}
sayHi(sing) {
console.log(this.name + '的年齡是' + this.age + ',并且唱了' + sing)
}
}
class Son extends Father {
}
var father = new Father('zww', 18)
console.log(father) // Father {name: "zww", age: 18}
var son = new Son('lq', 22)
console.log(son) // Son {name: "lq", age: 22}
son.sayHi('呵呵') // lq的年齡是22,并且唱了呵呵
super關鍵字
super關鍵字用于訪問和呼叫物件父類上的函式,可以呼叫父類的建構式,也可以呼叫父類的普通函式,
class Father {
constructor(name, age) {
this.name = name
this.age = age
}
sayHi() {
console.log('父類函式')
}
}
class Son extends Father {
constructor(name, age, sex) {
super(name, age)
this.sex = sex
}
sonfn() {
super.sayHi()
console.log('子類函式')
}
}
var son = new Son('lq', 22, '女')
console.log(son) // Son {name: "lq", age: 22, sex: "女"}
son.sonfn('丫丫') // 父類函式 子類函式
注意:
- 在ES6中類沒有變數提升,所以必須先定義類,才能通過類實體化物件
- 類里面的共有的屬性和方法一定要加this
- this的指向問題;constructor里面的this指向的是創建的實體物件;方法里面的this指向這個方法的呼叫者
模塊化
模塊功能主要由兩個命令構成:export 和 import,export 命令用于規定模塊的對外介面,import 命令用于輸入其他模塊提供的功能,
export 暴露模塊的三種方法:
- 分別暴露;
- 統一暴露;
- 默認暴露;
// 1. 分別暴露
export var name = 'zww';
export function like() {
console.log("like");
}
// 2. 統一暴露
var name = 'zww';
function like() {
console.log("like");
}
export { name, like }
// 3. 默認暴露
export default {
name: 'zww',
like: function() {
console.log("like");
}
}
import 引入模塊的三種方式:
- 通用方式;
- 解構賦值形式;
- 簡便形式,只適用于默認暴露;
// 1. 通用方式
import * as m from './module.js'
// 2. 解構賦值形式
import { name, like } from './module.js'
import { name as myname, like } from './module.js' // 如果重名,可以使用 as 來別名
import { default as m } from './module.js'
// 3. 簡便形式
import m from './module.js'
注意:在引入模塊時,要在 script 標簽寫上 type="module",
參考鏈接
阮一峰 - ECMAScript6入門
尚硅谷 - ES6教程
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/134960.html
標籤:其他
上一篇:Cesium系統學習整理(一)
下一篇:行內CSS樣式
