国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

ES6新特性

這篇具有很好參考價值的文章主要介紹了ES6新特性。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

1、初識ES6

ECMAScript 6.0(簡稱ES6)是JavaScript語言的下一代標準,已經(jīng)在2015年6月正式發(fā)布了。它的目標,是使得JavaScript語言可以用來編寫復雜的大型應用程序,成為企業(yè)級開發(fā)語言;
?
ECMAScript是JavaScript的規(guī)范,而JavaScript是ECMAScript的實現(xiàn);
?
ES6是一個歷史名詞,泛指 5.1 版本后的JavaScript 標準,而ECMAScript 2015則是正式名稱。


2、let與const聲明變量

2.1、let聲明變量

ES6新增了let,用來聲明變量,用法類似于var,但是let有塊級作用域,且在相同作用域中,只能重復聲明同一個變量,因此不能在函數(shù)內部重新聲明參數(shù)。
?
在for循環(huán)中,設置循環(huán)變量的部分是一個父作用域,循環(huán)體內部是一個子作用域。
?
let不會發(fā)生變量提升,在使用let聲明變量之前使用該變量會拋出錯誤。
?
let聲明的變量會綁定當前的作用域,不受外部影響,所以使用let聲明變量之前,該變量都是不能用的,這就稱為 暫時性死區(qū) (temporal dead zone,簡稱 TDZ)
?
因為有了暫時性死區(qū),所以typeof也不再是百分百安全的操作了,因為如果typeof在變量聲明前的死區(qū)運行,就會報錯 ReferenceError,如果一個變量根本沒有聲明,使用typeof反而不會報錯。

比較隱蔽的死區(qū):

function bar(x = y, y = 2) {
  return [x, y];
}
bar(); // 報錯
//因為參數(shù)y還沒有聲明,屬于“死區(qū)”。如果y的默認值是x,就不會報錯,因為此時x已經(jīng)聲明了
function bar(x = 2, y = x) {
  return [x, y];
}
bar(); // [2, 2]

// 不報錯
var x = x;
// 報錯
let x = x; // ReferenceError: x is not defined
//在x的聲明語句執(zhí)行完成之前就去取x的值,所以才會報錯

為什么需要塊級作用域:

因為內層變量可能會覆蓋外層變量;用來計數(shù)的循環(huán)變量會泄露為全局變量。
?
塊級作用域的出現(xiàn),實際上使得獲得廣泛應用的匿名立即執(zhí)行函數(shù)表達式(匿名 IIFE)不再必要了。
?

// IIFE 寫法
(function () {
	var tmp = ...;
	...
}());

// 塊級作用域寫法
{
	let tmp = ...;
	...
}

塊級作用域與函數(shù)聲明:

ES6引入了塊級作用域,明確允許可以在塊級作用域中聲明函數(shù),但是在塊級作用域外不能引用域內的函數(shù),這點與let類似。
?
ES6的塊級作用域必須有大括號,這樣JS引擎才會認為存在塊級作用域:
?

// 第一種寫法,報錯
if (true) let x = 1;

// 第二種寫法,不報錯
if (true) {
	let x = 1;
}
//函數(shù)聲明也是如此!
2.2、const聲明常量

const 聲明一個只讀的常量。一旦聲明,常量的值就不能改變,并必須立即初始化;只聲明不賦值,就會報錯,其作用域與let相同;聲明的常量也不會提升,同樣存在暫時性死區(qū),且不可重復聲明。
?
如果聲明的是對象類型,那么該對象中的數(shù)據(jù)是可以改變的,因為它只保證該對象的地址不能變。
?
可以使用 Object.freeze() 方法凍結對象,這樣就不能修改對象中的數(shù)據(jù)了(只能凍結一級屬性與方法),如下是一個實現(xiàn)徹底凍結的函數(shù):
?

var constantize = (obj) => {
	Object.freeze(obj);
	Object.keys(obj).forEach( (key, i) => {
		if ( typeof obj[key] === 'object' ) {
  			constantize( obj[key] );
		}
	});
};

ES6聲明變量的六種方法:

ES5:var和function、ES6:let和const,還有import和class。


3、變量的解構賦值

解構(Destructuring)賦值就是按照一定的模式從數(shù)組或對象中提取值,然后對變量進行賦值,這是ES6新增的。

3.1、數(shù)組解構賦值

如果解構不成功,變量的值就等于undefined;等號左邊的模式可以只匹配一部分右邊的數(shù)組,這叫做不完全解構。
?
只要某種數(shù)據(jù)結構具有 Iterator 接口,都可以采用數(shù)組形式的解構賦值。
?
解構賦值允許指定默認值,ES6內部會使用 === 來判斷一個位置是否有值,只有數(shù)組成員為undefined時,默認值才會生效,為null不會生效;如果默認值是一個表達式,那么只有在用到時才會求值;默認值可以引用解構賦值的其它變量,但必須是已聲明的。

<script>
    //同時將數(shù)組中多個值分別賦給a,b,c
    let arr = [1, 2, 3];
    let [a, b, c] = arr;

    //交換變量值
    let x = 1, y = 2;
    [y, x] = [x, y];
    console.log(x, y); //2,1

    //將第三個值賦給d
    let [, , d] = arr;
    console.log(d); //3

    //從嵌套數(shù)組中將1賦給e,3賦給f,5賦給g
    let arrs = [1, [2, 3, 4], 5, 6];
    let [e, [, f,], g] = arrs;
    console.log(e, f, g); //1,3,5

    //設置默認值,右邊賦值對象為undefined,默認值生效,否則照常賦值
    let [h = 1] = []; //let [h=1]=[100] //h=100
    console.log(h); //1
</script>
3.2、對象解構賦值

對象的解構賦值的內部機制,是先找到同名屬性,然后再賦給對應的變量。真正被賦值的是后者,而不是前者。
?
對象的解構賦值可以取到繼承的屬性。

<script>
    let obj = {
        name: 'twj',
        age: 600,
        data: {
            list: ['aaa', 'bbb', 'ccc']
        }
    }
    //對象解構不需要按照順序來,是先按照屬性名找有沒有,找到再賦值給相應的變量
    let { age, name } = obj;
    console.log(name, age); // twj 600
    let { data: { list }, name: n, age: a, err = '沒有錯誤' } = obj;
    console.log(list, n, a, err); // [aaa,bbb,ccc] twj 600 沒有錯誤

    function getData() {
        let obj = {
            name: 'twj',
            age: 600,
            data: {
                list: ['aaa', 'bbb', 'ccc']
            }
        }
        test(obj)
    }
    function test({ name, data: { list } }) { //函數(shù)參數(shù)也能使用解構賦值
        console.log(name, list); //twj [aaa,bbb,ccc]
    }
    getData();
</script>
3.3、字符串解構賦值
<script>
    let myname = 'twj';
    let [x, y, z] = myname;
    console.log(x, y, z); // t w j
    let { length } = myname;
    console.log(length); //3
</script>
3.4、注意

如果要將一個已經(jīng)聲明的變量用于解構賦值,必須非常小心:
?

// 錯誤的寫法
let x;
{x} = {x: 1}; // SyntaxError: syntax error
// 正確的寫法
let x;
({x} = {x: 1});
//因為JS引擎會將{x}理解成一個代碼塊,只有不將大括號放在行首才能避免這個問題。

解構賦值允許等號左邊的模式之中,不放置任何變量名:
?

({} = [true, false]);
({} = 'abc');
({} = []);

由于數(shù)組本質是特殊的對象,因此可以對數(shù)組進行對象屬性的解構:
?

let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr;
first // 1
last // 3

解構賦值時,如果等號右邊是數(shù)值和布爾值,則會先轉為對象。由于 undefinednull 無法轉為對象,所以對它們進行解構賦值,都會報錯。

3.5、圓括號的使用

因為對于編譯器來說,一個式子是模式還是表達式,得解析到(或解析不到)等號才能知道,所以只要有導致解構的歧義,就得使用圓括號,但是并不是所有情況都能使用圓括號的。
?
不能使用圓括號的情況:
?

//1、變量聲明語句
let [(a)] = [1];
let {x: (c)} = {};
//2、函數(shù)參數(shù)(也屬于變量聲明)
function f([(z)]) { return z; } // 報錯
function f([z,(x)]) { return x; } // 報錯
//3、賦值語句的模式
({ p: a }) = { p: 42 }; // 報錯
([a]) = [5]; // 報錯

可以使用圓括號的情況:
?

//只有賦值語句的非模式部分,可以使用圓括號。
[(b)] = [3]; // 正確
({ p: (d) } = {}); // 正確
[(parseInt.prop)] = [3]; // 正確

4、模板字符串

模板字符串(template string)是增強版的字符串,用反引號(`)標識。它可以當作普通字符串使用,也可以用來定義多行字符串,或者在字符串中嵌入變量。

?
在反引號中的 ${} 就是用來書寫變量或表達式的位置。

<head>
    <meta charset="UTF-8">
    <style>
        .active {
            color: rgb(188, 7, 22);
        }
    </style>
</head>

<body>
    <h1>演示使用模板字符串</h1>
    <ul>

    </ul>
    <script>
        let name = 'twj'
        //拼接字符串,換行并插入單個值(原始方法)
        let oli = "<li>\
            <b>"+ name + "</b>\
            </li>";
        //使用模板字符串
        let oli2 = `<li>
            <b>${name}</b>
            </li>`;
        console.log(oli2);

        function test() {
            return "函數(shù)返回結果"
        }

        //插入多個值
        let arr = ['twj', 'wbd', 'xjp'];
        let newList = arr.map(function (item, index) {
            //模板字符串的中可以插入變量、表達式、函數(shù)等
            return `<li class="${index === 0 ? 'active' : ''}">
                <b>${item}</b>
                ${test()}
            </li>`
        })
        console.log(newList);

        //將li添加到ul里面
        let oul = document.querySelector("ul");
        oul.innerHTML = newList.join("");
    </script>
</body>

5、常用數(shù)據(jù)類型的擴展

5.1、字符串的擴展

include函數(shù): 判斷字符串中是否存在指定字符。

let text = "Hello world!";
console.log(text.includes("o")); //true ,是否包含該字符
console.log(text.startsWith("Hello")); //true ,是否以該字符開頭
console.log(text.endsWith("!")); //true ,是否以該字符結尾
//這三個方法都支持第二個參數(shù),表示開始搜索的位置。
console.log(text.includes("Hello", 6)); //false
console.log(text.startsWith("world", 6)); //true
console.log(text.endsWith("Hello", 5)); //true
//上面代碼表示,使用第二個參數(shù)n時,endsWith針對前n個字符,而其他兩個方法針對從第n個位置直到字符串結束。

repeat函數(shù): 將原字符串重復n次,并返回重復后的新字符串。

console.log(text.repeat(2)); //Hello world!Hello world!
console.log(text.repeat(0)); //空字符串
console.log(text.repeat(2.7)); //Hello world!Hello world!
console.log(text.repeat("3")); //Hello world!Hello world!Hello world!
5.2、數(shù)值的擴展
//1. 各進制的寫法
let num1 = 100;
let num2 = 0x100;
let num3 = 0b100;
let num4 = 0o100;
console.log(num1, num2, num3, num4); //100 256 4 64

//2. Number.isFinite & Number.isNaN
let num5 = Number.isFinite(100)
let num6 = Number.isFinite(100 / 0)
let num7 = Number.isFinite(Infinity)
let num8 = Number.isFinite("100")
console.log(num5, num6, num7, num8) //true false false false
//Number.isFinite對于非數(shù)值一律返回false,Number.isNaN只有對于NaN才返回true
let num9 = Number.isNaN(100)
let num10 = Number.isNaN(NaN)
let num11 = Number.isNaN("twj")
let num12 = Number.isNaN("100")
console.log(num9, num10, num11, num12) //false true false false

//3. Number.isInteger:用來判斷一個數(shù)組是否為整數(shù)
let num13 = Number.isInteger(100)
let num14 = Number.isInteger(100.0)
let num15 = Number.isInteger("kerwin")
let num16 = Number.isInteger("100")
console.log(num13, num14, num15, num16) //true true false false

//4. Number.EPILON:極小常量 
//它表示1與大于1的最小浮點數(shù)之間的差。2.220446049250313e-16
function isEqual(a, b) {
    return Math.abs(a - b) < Number.EPSILON
}
console.log(isEqua1(0.1 + 0.2, 0.3)) //true
console.log(0.1 + 0.2 === 0.3) //fa1se

//5. Math.trunc:將小數(shù)部分抹掉,返回一個整數(shù)
console.log(Math.trunc(1.2)) //1
console.log(Math.trunc(1.8)) //1
console.log(Math.trunc(-1.8)) //-1
console.log(Math.trunc(-1.2)) //-1

//6. Math.sign:用來判斷一個數(shù)到底是正數(shù)、負數(shù)、還是零。對于非數(shù)值,會先將其轉換為數(shù)值。
Math.sign(-100) // -1
Math.sign(100) // +1
Math.sign(o1) // +0
Math.sign(-0) // -0
Math.sign("kerwin") // NaN
5.3、數(shù)組的擴展
5.3.1、擴展運算符
// ...展開
let arr = [1, 2, 3]
//let arr2 = arr.concat()
// let arr2 = [...arr] //實現(xiàn)淺拷貝
// arr2.pop() //刪除arr2中的元素,arr并不會受影響
// console.log(arr, arr2)
let arr2 = [4, 5, 6]
console.log(...arr, ...arr2) // 1 2 3 4 5 6
let myarr = [1, 2, 3, 4, 5, 6, 7, 8]
let [a, b, ...c] = myarr
console.log(a, b, c) //1 2 [3,4,5,6,7,8]
5.3.2、Array.from()
//Array.from():用于將一個類似數(shù)組的對象轉換成數(shù)組
function test() {
    //console.log(arguments) //[1, 2, 3, 4, callee: ?, Symbol(Symbol.iterator): ?]
    console.log(Array.from(arguments)) //[1,2,3,4]
}
test(1, 2, 3, 4)

let olis = document.querySelectorAll("li")
console.log(Array.from(olis)); //[li,li,li,li]
5.3.3、Array.of()
//Array.of():將一組值轉化為數(shù)組,也就是新建數(shù)組
let arr3 = Array(3)
let arr4 = Array.of(3)
console.log(arr3, arr4) //[empty×3] [3]
5.3.4、find() & findIndex()
//find() findIndex():查找數(shù)組元素/下標
let arr5 = [11, 12, 13, 14, 15]
//找到大于13的元素
let res = arr5.find(function (item) {
    return item > 13
})
console.log(res) //14
//找到大于13的那個元素的下標
let index = arr5.findIndex(function (item) {
    return item > 13
})
console.log(index) //3
5.3.5、findLast() & findLastIndex()
//findLast() findLastIndex():ES2022新增的
//這兩個方法與前面兩個方法類似,不過是從后面開始查找
let index1 = arr5.findLastIndex(function (item) {
    return item > 13
})
console.log(index1) //4
5.3.6、fill()
//fill():填充數(shù)組元素的值
let arr6 = new Array(3).fill("twj")
console.log(arr6) //['twj', 'twj', 'twj']
let arr7 = [11, 22, 33]
console.log(arr7.fill('twj', 1, 2)) //[11, 'twj', 33]
5.3.7、flat() & flatMap()
//flat() flatMap():扁平化處理,將嵌套數(shù)組拉伸成一維數(shù)組
let arr8 = [1, 2, 3, [4, 5, 6]]
let arr9 = arr8.flat()
console.log(arr9) //[1, 2, 3, 4, 5, 6]

//復雜的多維數(shù)組可通過flatMap來處理
let arr10 = [
    {
        name: "A",
        list: ["安慶", "安陽", "鞍山"]
    },
    {
        name: "B",
        list: ["北京", "保定", "包頭"]
    }
]
let res1 = arr10.flatMap(function (item) {
    return item.list
})
console.log(res1) //['安慶', '安陽', '鞍山', '北京', '保定', '包頭']

5.4、對象的擴展
//1. 對象簡寫
let name = "moduleA"
let obj = {
    name, //name:name
    test1() { //方法可以簡寫為這樣

    },
    [name + "test2"]() { //方法名也可以為表達式形式

    }
}

//2. 對象屬性使用表達式
let name1 = "a"
let obj1 = {
    [name1 + "bc"]: "twj"
}
console.log(obj1) //{abc:'twj'}

//3. 擴展運算符... ES2018支持
let obj2 = {
    name: "twj"
}
let obj3 = {
    ...obj2
}
let obj4 = {
    age: 100
}
obj2.name = "whh"
console.log(obj2) //{name: 'whh'}
//console.log(...obj2, ...obj4) //報錯

//4. Object.assign:合并多個對象
let obj5 = {
    name: "twj"
}
let obj6 = {
    age: 100
}
//影響的是obj5,可以用個空對象來接收返回的新對象
console.log(Object.assign(obj5, obj6)) //{name: 'twj', age: 100}

//5. Object.is:判斷兩個對象是否相等
//因為 === 無法判斷兩個NaN是否相等,以及+0和-0是否相等
console.log(Object.is(5, 5)) //true
console.log(Object.is({}, {})) //false
console.log(Object.is(NaN, NaN)) //true

console.log(Object.is(+0, -0)) //false
console.log(+0 === -0) //true
5.4、函數(shù)的擴展
//1. 箭頭函數(shù),寫法簡潔
let test = () => "666"
console.log(test()) //666
let arr = ["aaa", "bbb", "ccc"]
let newarr = arr.map(item => `<li>${item}</li>`)
console.log(newarr) //['<li>aaa</li>', '<li>bbb</li>', '<li>ccc</li>']
//2. 只有return可以省略,如果返回對象則需要加圓括號(因為大括號會被解釋為代碼塊)
let test2 = () => ({
    name: "twj",
    age: 100
})
console.log(test2()) //{name: 'twj', age: 100}
//3. 如果只有一個參數(shù),可以省略()
let newarr2 = arr.map(item => `<li>${item}</li>`)
console.log(newarr2) //['<li>aaa</li>', '<li>bbb</li>', '<li>ccc</li>']
//4. 無法訪問arguments,無法new
let test3 = () => {
    console.log(arguments) //無法訪問的哦!
}
//test3(1, 2, 3, 4) //ReferenceError: arguments is not defined
//new test3() //TypeError: test3 is not a constructor

箭頭函數(shù)沒有this:

<body>
    模糊搜索: <input type="text" id="mysearch">
    <script>
        let osearch = document.querySelector("#mysearch")
        //原始方式this指向window,需要用個臨時變量來改變指向
        osearch.oninput = function () {
            let _this = this
            setTimeout(function () {
                console.log(_this.value)
                console.log(`發(fā)送${_this.value}到后端,獲取列表數(shù)據(jù)`)
            }, 1000)
        }

        //而箭頭函數(shù)就沒這個問題,誰調用就指向誰,箭頭函數(shù)沒有this,this指向父作用域
        osearch.oninput = function () {
            setTimeout(() => {
                console.log(this.value)
                console.log(`發(fā)送${this.value}到后端,獲取列表數(shù)據(jù)`)
            }, 1000)
        }
    </script>
</body>

6、Symbol

ES6 引入了一種新的原始數(shù)據(jù)類型 Symbol,表示獨一無二的值。它屬于 JavaScript 語言的原生數(shù)據(jù)類型之一,其他數(shù)據(jù)類型是:undefined、null、布爾值(Boolean)、字符串(String)、數(shù)值(Number)、大整數(shù)(BigInt)、對象(Object)。

let s1 = Symbol() //生成了Symbol類型的數(shù)據(jù)
let s2 = Symbol()
console.log(s1) //Symbol()
console.log(s1 === s2) //false

//1. 不能進行運算
//console.log(s1 + "abc") //報錯

//2. 顯式調用toString()
console.log(s1.toString() + "abc") //Symbol()abc 沒啥用!

//2. 隱式轉換toString()
if (s1) {
    console.log("執(zhí)行")
}

// let obj = {
//     name: "twj",
//     age: 100
// }
// let name = Symbol()
// obj[name] = "hhh"
// console.log(obj[name]) //hhh

//避免后期添加新屬性時,屬性名的沖突
let keys = {
    name: Symbol(),
    age: Symbol(),
    location: Symbol(),
    test: Symbol()
}
let obj = {
    [keys.name]: "twj",
    [keys.age]: 100,
    [keys.location]: "beijing",
    [keys.test]() {
        console.log("test")
    }
}
obj.name = "aaaaaa"
console.log(obj) //{name: 'aaaaaa', Symbol(): 'twj', Symbol(): 100, Symbol(): 'beijing', Symbol(): ?}
obj[keys.test]() //test

遍歷Symbol:

//Symbol可接受一個參數(shù)用作Symbol的描述,方便我們區(qū)分
let keys = {
    name: Symbol("name"),
    age: Symbol("age"),
    location: Symbol("location"),
    test: Symbol("test")
}
let obj = {
    [keys.name]: "twj",
    [keys.age]: 100,
    [keys.location]: "beijing",
    [keys.test]() {
        console.log("test")
    }
}
obj.name = "aaaaaa"
console.log(obj) //{name: 'aaaaaa', Symbol(name): 'twj', Symbol(age): 100, Symbol(location): 'beijing', Symbol(test): ?}

//for..in 只能遍歷出普通的屬性
for (let i in obj) {
    console.log(i) //name
}
//遍歷得到Symbol的屬性
console.log(Object.getOwnPropertySymbols(obj)) //[Symbol(name), Symbol(age), Symbol(location), Symbol(test)]

console.log(Reflect.ownKeys(obj)) //['name', Symbol(name), Symbol(age), Symbol(location), Symbol(test)]
//遍歷得到所有屬性
Reflect.ownKeys(obj).forEach(item => {
    console.log(item, obj[item])
})

//還能使用Symbol.for()重新使用同一個Symbol的值,略...

Symbol作為常量:

//作為常量
const VIDEO = Symbol();
const AUDIO = Symbol();
const IMAGE = Symbol();

function play(type) {
    switch (type) {
        case VIDEO:
            console.log("視頻播放")
            break;
        case AUDIO:
            console.log("音頻播放")
            break;
        case IMAGE:
            console.log("圖片播放")
            break;
    }
}
//這樣就能統(tǒng)一代碼的一致性,只能使用這三個常量
play(VIDEO)

7、Iterator

7.1、Iterator的作用
  1. 為各種數(shù)據(jù)結構,提供一個統(tǒng)一的、簡便的訪問接口;
  2. 使得數(shù)據(jù)結構的成員能夠按某種次序排列;
  3. ES6創(chuàng)造了一種新的遍歷命令for…of循環(huán),Iterator接口主要供for…of循環(huán)。
7.2、Iterator的遍歷過程
  1. 創(chuàng)建一個指針對象,指向當前數(shù)據(jù)結構的起始位置。也就是說,遍歷器對象本質上,就是一個指針對象。
  2. 第一次調用指針對象的next方法,可以將指針指向數(shù)據(jù)結構的第一個成員。
  3. 第二次調用指針對象的next方法,指針就指向數(shù)據(jù)結構的第二個成員。
  4. 不斷調用指針對象的next方法,直到它指向數(shù)據(jù)結構的結束位置。
let arr = ["twj", "wdf", "jjb"]
for (const a of arr) {
    console.log(a)
}
//arr數(shù)組原型中封裝了Symbol(Symbol.iterator)屬性
let iter = arr[Symbol.iterator]() //得到遍歷器對象
console.log(iter)
console.log(iter.next()) //{value: 'twj', done: false}
console.log(iter.next()) //{value: 'wdf', done: false}
console.log(iter.next()) //{value: 'jjb', done: false}
console.log(iter.next()) //{value: 'undefined', done: none}

ES6規(guī)定,默認的Iterator接口部署在數(shù)據(jù)結構的Symbol.iterator屬性,或者說,一個數(shù)據(jù)結構只要具有Symbol.iterator屬性,就可以認為是"可遍歷的”(iterable)。Symbol.iterator屬性本身是一個函數(shù),就是當前數(shù)據(jù)結構默認的遍歷器生成函數(shù)。執(zhí)行這個函數(shù),就會返回一個遍歷器。

7.2、默認具備Iterator接口的數(shù)據(jù)結構

Array、Map、Set、String、TypedArray、arguments 對象、NodeList 對象。

常規(guī)遍歷:

let arr = ["twj", "wdf", "jjb"]
for (const a of arr) {
    console.log(a)
}
console.log(arr)
//arr數(shù)組原型中封裝了Symbol.iterator屬性,也稱遍歷器接口,用于返回一個遍歷器
let iter = arr[Symbol.iterator]() //得到遍歷器對象
console.log(iter)
console.log(iter.next()) //{value: 'twj', done: false}
console.log(iter.next()) //{value: 'wdf', done: false}
console.log(iter.next()) //{value: 'jjb', done: false}
console.log(iter.next()) //{value: 'undefined', done: none}

//字符串也能使用for..of進行遍歷,因為它也封裝了遍歷器接口
let str = "twjnbnb"
for (const s of str) {
    console.log(s)
}

//arguments也封裝了遍歷器接口
function test() {
    for (let arg of arguments) {
        console.log(arg)
    }
}
test(1, 2, 3, 4)

手動封裝Interator接口:

<body>
    <ul>
        <li>111</li>
        <li>222</li>
        <li>333</li>
    </ul>
    <script>
        //對象是非線性的,所以沒有封裝遍歷器接口,但是可以借助Array類原型的遍歷器接口!
        let obj = {
            0: "twj",
            1: "wdf",
            2: "jjb",
            length: 3,
            [Symbol.iterator]: Array.prototype[Symbol.iterator]
        }
        for (let i of obj) {
            console.log(i)
        }

        //手動埋一個遍歷器接口
        let obj2 = {
            code: 200,
            name: "obj2",
            list: ["jjb", "twj", "wdf"],
            [Symbol.iterator]() {
                let index = 0
                return {
                    next: () => {
                        return {
                            value: this.list[index++],
                            done: index === (this.list.length + 1) ? true : false
                        }
                    }
                }
            }
        }
        //for..of成功!
        for (let i of obj2) {
            console.log(i)
        }
        //沒毛病!
        let iter = obj2[Symbol.iterator]()
        console.log(iter)
        console.log(iter.next())
        console.log(iter.next())
        console.log(iter.next())
        console.log(iter.next())

        //展開運算符會默認調用對象中的遍歷器,配合解構賦值就能自動轉換成數(shù)組!
        console.log([...obj2]) //['jjb', 'twj', 'wdf']

        let oli = document.querySelectorAll("li");
        console.log([...oli]) //[li, li, li]
        console.log(Array.from(oli)) //[li, li, li]
    </script>
</body>

8、Set數(shù)據(jù)接口

8.1、Set簡介

Set 類似于數(shù)組,但是成員的值都是唯一的,沒有重復的值。Set 本身是一個構造函數(shù),用來生成 Set 數(shù)據(jù)結構。

基本用法:

let s1 = new Set([1, 2, 3, 4, 2, 1])
console.log(s1) //{1,2,3,4}
console.log([...s1]) //[1,2,3,4]
console.log(Array.from(s1)) //[1,2,3,4]

let s2 = new Set()
s2.add(11)
s2.add(22)
s2.add(22)
s2.add(33)
console.log(s2) //{11,22,33}
8.2、Set實例的屬性和方法

Set實例的屬性:

  • Set.prototype.constructor:構造函數(shù),默認就是Set函數(shù)。
  • Set.prototype.size:返回Set實例的成員總數(shù)。

Set 實例的方法分為兩大類:操作方法和遍歷方法,如下為操作方法:

  • Set.prototype.add(value):添加某個值,返回 Set 結構本身。
  • Set.prototype.delete(value):刪除某個值,返回一個布爾值,表示刪除是否成功。
  • Set.prototype.has(value):返回一個布爾值,表示該值是否為Set的成員。
  • Set.prototype.clear():清除所有成員,沒有返回值。

如下為遍歷方法:

  • Set.prototype.keys():返回鍵名的遍歷器
  • Set.prototype.values():返回鍵值的遍歷器
  • Set.prototype.entries():返回鍵值對的遍歷器
  • Set.prototype.forEach():使用回調函數(shù)遍歷每個成員

使用示例:

//size:返回Set實例的成員總數(shù)
console.log(s1.size) //4
//add():添加成員
s1.add(5).add(6)
//has():判斷是否存在指定成員
console.log(s1.has(5)) //true
//delete():刪除指定成員
s1.delete(5)
console.log(s1.has(5)) //false
//clear():清除set中所有成員
s1.clear()

//keys():返回鍵名的遍歷器
for (let i of s2.keys()) {
    console.log(i)
}
//values():返回鍵值的遍歷器
for (let i of s2.values()) {
    console.log(i)
}
//entries():返回鍵值對的遍歷器
for (let i of s2.entries()) {
    console.log(i)
}
//使用解構賦值
let arr = ["aa", "bb", "cc"]
for (let [index, item] of arr.entries()) {
    console.log(index, item)
}

//forEach():使用回調函數(shù)遍歷每個成員
s2.forEach((item, index) => {
    console.log(item, index)
})

對復雜數(shù)組去重:

let arr2 = [1, 2, 2, "twj", "twj", [1, 2], [3, 4], [1, 2], { name: "twj" }
    , { age: 100 }, { name: "twj" }, undefined, undefined, NaN, NaN]
function uni(arr2) {
    let res = new Set()
    return arr2.filter((item) => {
        //判斷有沒有重復的,沒有添加到set中并返回true
        let id = JSON.stringify(item)
        if (res.has(id)) {
            return false
        } else {
            res.add(id)
            return true
        }
    })
}
console.log(uni(arr2))

9、Map數(shù)據(jù)接口

9.1、Map簡介

Map類似于數(shù)組,也是鍵值對的集合,但是"鍵"的范圍不限于字符串,各種類型的值(包括對象)都可以當作鍵。

基本用法:

let m1 = new Map([
    ["name", "twj"],
    ["age", 100],
    [{ a: 1 }, "北京"]
])
console.log(m1) //{'name' => 'twj', 'age' => 100, {Object} => '北京'}

let o = { a: 1 }
let m2 = new Map()
m2.set("name", "twj")
m2.set("age", 100)
m2.set(o, "北京")
console.log(m2) //{'name' => 'twj', 'age' => 100, {Object} => '北京'}

//使用for..of
for (let i of m2) {
    console.log(i)
}
//使用擴展運算符+解構賦值
console.log([...m2])
9.2、Map實例的屬性和方法

size: 返回Map結構的成員總數(shù)。
Map.prototype.set(key , value): 添加key對應得value,返回Map結構本身。
Map.prototype.get (key): 獲取key對應的value
Map.prototype.delete(key): 刪除某個鍵(鍵名+鍵值)
Map.prototype.has(key): 某個鍵是否在當前Map對象之中。

Map的遍歷方法與Set一樣。

使用示例:

//map實例的屬性和方法
console.log(m2.get(o)) //北京
console.log(m2.has("age")) //true
m2.delete("age")
console.log(m2.has("age")) //false
console.log(m2.size) //2
//m2.clear() //清空map
//console.log(m2)

//map的遍歷
for (let i of m2.keys()) {
    console.log(i)
}
for (let i of m2.values()) {
    console.log(i)
}
for (let [index, item] of m2.entries()) {
    console.log(index, item)
}
//與entries()作用一樣
for (let [index, item] of m2) {
    console.log(index, item)
}
m1.forEach((item, index) => {
    console.log(item, index)
})

10、Proxy

Proxy如其名,它的作用是在對象和和對象的屬性值之間設置一個代理,獲取該對象的值或者設置該對象的值,以及實例化等等多種操作,都會被攔截住,經(jīng)過這一層我們可以統(tǒng)一處理,我們可以認為它就是“代理器

攔截對象屬性:

<div id="box"></div>
<script>
    //常規(guī)方式實現(xiàn)攔截對象屬性
    let obj = {}
    //obj為要攔截的對象,data為攔截的屬性,一旦訪問了data屬性,就會調用get方法,
    //一旦修改了data屬性,就會調用set方法,攔截后我們就可以做一些響應式的操作,比如更新DOM節(jié)點的內容....
    Object.defineProperty(obj, "data", {
        get() {
            console.log("get")
        },
        set(value) {
            console.log("set", value)
            //設置DOM
            box.innerHTML = value
        }
    })
	//defineProperty的缺點:每一次只能攔截一個屬性,也只能攔截對象,所以就引出了Proxy
</script>

使用Proxy攔截對象屬性:

<div id="box"></div>
<script>
    //Proxy不僅能攔截對象還能攔截數(shù)組、Set、Map等,其實就是給原對象加一個代理,這個代理可以比作是一個中介,
    //通過這個中介來幫我們攔截對象,攔截到對象屬性后我們就可以進行相應的操作了
    //Proxy代理攔截幾乎所有數(shù)據(jù)類型,并且能攔截多個屬性
    let obj = {}
    let proxy = new Proxy(obj, {
        get(target, key) {
            console.log("get", target[key])
            return target[key]
        },
        //target為原對象,key為屬性名,value為屬性值
        set(target, key, value) {
            console.log("set", target, key, value)
            if (key === "data") {
                box.innerHTML = value
            }
            target[key] = value
        },
        has() { //has()只能控制判斷代理中是否存在某個屬性,原對象它并不會做處理
            return false
        }
    })
</script>

代理set/map需注意:

//如果是代理的set和map,就要注意其方法的this指向,如果不改變this的指向,就無法操作其方法
let s = new Set()
let proxy = new Proxy(s, {
    get(target, key) {
        //判斷如果是方法,就要修正this指向
        let value = target[key]
        if (value instanceof Function) {
            return value.bind(target) //將this指向target,target也就是s
        }
        return value
    },
    set() {
        console.log("set")
    }
})

Proxy本質上屬于元編程而非破壞性數(shù)據(jù)劫持,在原對象的基礎上進行了功能的衍生而又不影響原對象,符合松耦合高內聚的設計理念。


11、Reflect

Reflect(反射)可以用于獲取目標對象的行為,它與Object類似,但是更易讀,為操作對象提供了一種更優(yōu)雅的方式。它的方法與Proxy是對應的,作用如下:

代替Object的某些方法:

let obj = {}
Reflect.defineProperty(obj, "name", {
    value: "twj",
    writable: false, //設置屬性值不可改
    enumerable: false //設置name屬性不可刪
})
console.log(obj)

修改某些Object方法返回結果:

//好處就是在處理異常代碼時不用再try..catch了,因為它返回的是布爾值,所以程序也不會因為異常中斷了
//,而Object會直接拋出異常中斷程序
let obj = {}
Reflect.defineProperty(obj, "name", {
    value: "twj",
    writable: false, //設置屬性值不可改
    enumerable: false //設置name屬性不可刪
})
let res = Reflect.defineProperty(obj, "name", {
    value: "whh" //再次修改了屬性值,就會返回false
})
console.log(res) //false

命令式變?yōu)楹瘮?shù)行為:

let obj = {
    name: "twj"
}
//查詢對象中是否存在某個屬性:老寫法
console.log("name" in obj) //true
//新寫法
console.log(Reflect.has(obj, "name")) //true
//刪除屬性:老寫法
//delete obj.name
//新寫法
Reflect.deleteProperty(obj, "name")
console.log(Reflect.has(obj, "name")) //false
//修改和獲取對象屬性值:新寫法
Reflect.set(obj, "age", 100) //在obj上添加一個屬性age,賦值為100
console.log(Reflect.get(obj, "age")) //獲取obj上的age屬性值

配合Proxy實現(xiàn)更好的攔截:

let s = new Set()
let proxy = new Proxy(s, {
    get(target, key) {
        //判斷如果是方法,就要修正this指向
        let value = Reflect.get(target, key)
        if (value instanceof Function) {
            return value.bind(target) //將this指向target,target也就是s
        }
        return value
    },
    set(target, key, value) {
        //走原對象的默認行為即可
        Reflect.set(...arguments)
    }
})
//攔截數(shù)組,動態(tài)監(jiān)測長度,非常方便!
let arr = [1, 2, 3]
let proxy2 = new Proxy(arr, {
    get(target, key) {
        console.log("get", key)
        return Reflect.get(...arguments)
    },
    set(target, key, value) {
        console.log("set", key, value)
        return Reflect.set(...arguments)
    }
})
proxy2.push(4) //會觸發(fā)兩次get,兩次set

12、Promise對象

promise是異步編程的一種解決方案,比傳統(tǒng)的解決方案回調函數(shù),更合理和更強大。ES6將其寫進了語言標準。統(tǒng)一了用法,原生提供了Promise對象。
?
promise指定回調函數(shù)方式更靈活易懂。解決了異步回調地獄的問題。

12.1、回調地獄

當一個回調函數(shù)嵌套一個回調函數(shù)的時候就會出現(xiàn)一個嵌套結構;
?
當嵌套的多了就會出現(xiàn)回調地獄的情況;比如我們發(fā)送三個ajax請求:

  • 第一個正常發(fā)送;
  • 第二個請求需要第一個請求的結果中的某一個值作為參數(shù);
  • 第三個請求需要第二個請求的結果中的某一個值作為參數(shù)。
function ajax(url, successcb, failcb) {
    setTimeout(() => successcb("111"))
}
//回調地獄!
ajax("/aaa", function (data) {
    console.log(data)
    ajax("/bbb", function (data) {
        console.log(data)
        ajax("/ccc", function (data) {
            console.log(data)
        }, function () {
        })
    }, function () {
    })
}, function () {
})
12.2、基本使用
let pro = new Promise(function (resolve, reject) {
    //執(zhí)行器函數(shù)
    setTimeout(() => {
        //resolve(1000)
        reject("天天遲到,沒有獎金!")
    }, 1000)
})
// pro.then(() => {
//     console.log("獎金")
// }, () => {
//     console.log("啥也沒有")
// })
//catch()用于注冊一個在 promise 被拒絕時調用的函數(shù)。 它會立即返回一個等價的 Promise 對象,
//這可以允許你 鏈式 調用其他 promise 的方法
pro.then((res) => {
    console.log("獎金", res)
}).catch((err) => {
    console.log("啥也沒有", err)
})
12.3、Promise對象的狀態(tài)

Promise對象通過自身的狀態(tài),來控制異步操作,Promise實例具有三種狀態(tài):
?

異步操作未完成(pending)
異步操作成功(fulfilled)
異步操作失?。╮ejected)

|這三種狀態(tài)的變化途徑只有兩種:從未完成到成功、從未完成到失敗。

一旦狀態(tài)發(fā)生變化,就凝固了,不會再有新的狀態(tài)變化。這也是Promise這個名字的由來,它的英語意思是"承諾",一旦承諾成效,就不得再改變了。這也意味著,Promise實例的狀態(tài)變化只可能發(fā)生一次。
?
因此,Promise的最終結果只有兩種:
?

異步操作成功,Promise實例傳回一個值(value),狀態(tài)變?yōu)閒ulfilled。
異步操作失敗,Promise實例拋出一個錯誤(error),狀態(tài)變?yōu)閞ejected。

ES6新特性

手動封裝一個Ajax:

function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open("get", url, true)
        xhr.send()
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText)
                } else {
                    reject(xhr.responseText)
                }
            }
        }
    })
}
ajax("1.json").then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

.then鏈式調用:

let pro = new Promise(function (resolve, reject) {
    //執(zhí)行器函數(shù)
    setTimeout(() => {
        resolve(1000)
        //reject("天天遲到,沒有獎金!")
    }, 1000)
})
pro.then((res) => {
    console.log("獎金1", res)
    //如果return 非promise類型,pending->fulfilled
    //如果return promise類型,那就根據(jù)這個新的promise對象的結果,
    //來決定pending->fulfilled 還是 pending->rejected
    return res
}).then((res) => {
    console.log("獎金2", res)
}).catch((err) => {
    console.log("啥也沒有", res)
})

解決回調地獄:

function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open("get", url, true)
        xhr.send()
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText)
                } else {
                    reject(xhr.responseText)
                }
            }
        }
    })
}
ajax("1.json").then(res => {
    console.log(res)
    //一旦請求成功,就進入下一個then,否則就進入catch
    return ajax("2.json", res)
}).then(res => {
    console.log(res)
}).catch(err => {
    console.log(err)
})

all和race函數(shù):

let pro1 = new Promise(function (resolve, reject) {
    //執(zhí)行器函數(shù)
    setTimeout(() => {
        resolve(1000)
    }, 1000)
})
let pro2 = new Promise(function (resolve, reject) {
    //執(zhí)行器函數(shù)
    setTimeout(() => {
        resolve(2000)
    }, 2000)
})
let pro3 = new Promise(function (resolve, reject) {
    //執(zhí)行器函數(shù)
    setTimeout(() => {
        resolve(3000)
    }, 3000)
})
/*Promise.all:
參數(shù)為多個promise對象,只有這三個promise狀態(tài)都變成fulfilled,才會進入then
,并且將返回值封裝成一個數(shù)組傳入;這樣就可以實現(xiàn)loading加載效果只有在多個任務執(zhí)行完才消失。
*/
Promise.all([pro1, pro2, pro3]).then(res => {
    console.log(res) //[1000, 2000, 3000]
}).catch(err => {
    console.log(err)
})
/*Promise.race:
參數(shù)為多個promise對象,這三個promise誰最先變更狀態(tài),誰就進入then,并把數(shù)據(jù)傳入;
這樣可以實現(xiàn)請求多個服務器資源,誰最快就請求那個服務器,還有如果請求超時了,可以在指定時間內進入catch,不占用資源
*/
Promise.race([pro1, pro2, pro3]).then(res => {
    console.log(res) //1000
}).catch(err => {
    console.log(err)
})

13、Generator

Generator函數(shù)是ES6提供的一種異步編程解決方案,它是一個狀態(tài)機,封裝了多個內部狀態(tài)。
?
執(zhí)行Generator函數(shù)會返回一個遍歷器對象,也就是說,Generator函數(shù)除了狀態(tài)機,還是一個遍歷器對象生成函數(shù)。返回的遍歷器對象,可以依次遍歷Generator函數(shù)內部的每一個狀態(tài)。

基本用法:

//可以讓函數(shù)暫停執(zhí)行,yield(產出)相當于一個暫停的標記
//,遇到這個標記就暫停不往下執(zhí)行了,除非通過next()才能往下執(zhí)行
function* gen() {
    console.log(11)
    yield //產出
    console.log(22)
    yield
    console.log(33)
}
let g = gen()
g.next()
g.next()
g.next()
/
function* gen2() {
    console.log(11)
    yield "aaa" //可以產出一個結果
    console.log(22)
    yield "bbb"
    console.log(33)
}
let g2 = gen2()
let res1 = g2.next()
console.log(res1)
let res2 = g2.next()
console.log(res2)
let res3 = g2.next()
console.log(res3)
//可以直接使用for..of遍歷g

基本原理:

//yield可以產出一個值,不過在第一次調用next()的時候,在yield這里會暫停,所以“傳入-111”不會輸出,
//并且也不會將產出的結果返回給res1,第二次執(zhí)行next(),就可以將產出值返回給函數(shù)外的res1,然后輸出第一條語句,
//接著再輸入函數(shù)內部的第一條語句,以此類推...
function* gen() {
    let res1 = yield "aaa"
    console.log("gen內部", res1)
    let res2 = yield "bbb"
    console.log("gen內部", res2)
}
let g = gen()
let res1 = g.next("傳入-111")
console.log(res1)
let res2 = g.next("傳入-222")
console.log(res2)
let res3 = g.next("傳入-333")
console.log(res3)

結合異步操作:

function ajax(url) {
    return new Promise((resolve, reject) => {
        let xhr = new XMLHttpRequest()
        xhr.open("get", url, true)
        xhr.send()
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.responseText)
                } else {
                    reject(xhr.responseText)
                }
            }
        }
    })
}
function* gen() {
    let res = yield ajax("1.json")
    console.log("第一個請求的結果", res)
    let res2 = yield ajax("2.json")
    console.log("第二個請求的結果", res2)
}
//自動版本,遞歸實現(xiàn)
function AutoRun(gen) {
    let g = gen();
    function next(data) {
        let res = g.next(data);
        if (res.done) return
        res.value.then(function (data) {
            next(data);
        });
    }
    next();
}
AutoRun(gen)
//手動版本
//let g = gen()
//console.log(g.next()) //promise
// g.next().value.then(data => {
//     g.next(data).value.then(res => {
//         g.next(res)
//     })
// })
//async await 屬于內置的自動執(zhí)行器!

14、Class語法

基本用法:

//傳統(tǒng)構造函數(shù)寫法
// function Person(name, age) {
//     this.name = name
//     this.age = age
// }
// Person.prototype.say = function () {
//     console.log(this.name, this.age)
// }
// let obj = new Person("twj", 100)
// console.log(obj)
//ES6新寫法
let s = Symbol('say')
class Person {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    hhh() {
        console.log("hhh")
    }
    [s]() {
        console.log(this.name, this.age)
    }
}
let obj = new Person("twj", 100)
console.log(obj.__proto__ === Person.prototype) //true
obj[s]() //twj 100

get/set:

<body>
    <ul id="list">

    </ul>
    <script>
        class Person {
            constructor(name, age, location, id) {
                this.name = name
                this.age = age
                this.location = location
                this.ele = document.querySelector(`#${id}`)
            }
            get location() {
                console.log("get")
                //return this.location //死循環(huán)
            }
            set location(data) {
                console.log("set", data)
                //this.location = data //棧溢出
            }
            get html() {
                return this.ele.innerHTML
            }
            set html(data) {
                this.ele.innerHTML = data.map(item => `<li>${item}</li>`).join("")
            }
        }
        let obj = new Person("twj", 100, "長沙", "list")
        obj.html = ["111", "222", "333"]
    </script>
</body>

靜態(tài)屬性和方法:

class Person {
    static myname = "person類的名字"
    static mymethod = function () {
        console.log("mymethod")
    }
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    say() {
        console.log(this.name, this.age)
    }
}
//等價于static寫法,不用new,直接通過類名.來訪問
// Person.myname = "person類的名字"
// Person.mymethod = function () {
//     console.log("mymethod")
// }
let obj = new Person("twj", 100)
console.log(Person.myname)
Person.mymethod()

15、Class繼承

基本用法:

class Person {
    static myname = "person類的名字"
    static mymethod = function () {
        console.log("mymethod")
    }
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    say() {
        console.log(this.name, this.age)
    }
}
//可以繼承屬性和方法(靜態(tài)的也可以),可以重寫父類方法等,使用super調用父類構造器,這些特點都與Java類似
class Student extends Person {
    constructor(name, age, score) {
        super(name, age)
        this.score = score
    }
    getScore() {
        console.log(this.score)
    }
    say() {
        super.say()
        console.log(this.score)
    }
}
let obj = new Student("twj", 100, 149)

渲染DOM元素:

<body>
    <div class="box1">
        <h2></h2>
        <ul></ul>
    </div>
    <div class="box2">
        <h2></h2>
        <img src="" alt="" style="width: 100px;" />
        <ul></ul>
    </div>
    <script>
        var data1 = {
            title: "體育",
            list: ["體育-1", "體育-2", "體育-3"]
        }
        var data2 = {
            title: "綜藝",
            url: "https://fanyi-cdn.cdn.bcebos.com/static/translation/img/header/logo_e835568.png",
            list: ["綜藝 - 1", "綜藝 - 2", "綜藝3"]
        }
        class CreatBox {
            constructor(select, data) {
                this.ele = document.querySelector(select)
                this.title = data.title
                this.list = data.list
                this.render()
            }
            render() {
                let oh1 = this.ele.querySelector("h2")
                let oul = this.ele.querySelector("ul")
                oh1.innerHTML = this.title
                oul.innerHTML = this.list.map(item =>
                    `<li>${item}</li>`).join("")
            }
        }

        new CreatBox(".box1", data1)

        //因為只多了個圖片,所以直接繼承CreatBox即可
        class CreatImgBox extends CreatBox {
            constructor(select, data) {
                super(select, data)
                this.imgUrl = data.url
                this.render() //這里需要重新調用一下render(),與this指向有關
            }
            render() {
                super.render()
                let oimg = this.ele.querySelector("img")
                oimg.src = this.imgUrl
            }
        }

        new CreatImgBox(".box2", data2)
    </script>
</body>

16、Module語法

ES Module是ES6中提出的一個新的模塊加載方式,簡稱ES6模塊。ES Module的最大好處就是取代commonJS和AMD兩種模塊加載方式,實現(xiàn)服務端和瀏覽器端模塊加載的大一統(tǒng)。當然,ES Module在資源加載速度和靜態(tài)分析方面也是好處大大的。
?
JavaScript現(xiàn)在有兩種模塊。一種是ES6模塊,簡稱ESM;另一種是CommonJS模塊,簡稱CJS。
?
CommonJS模塊是Node.js專用的,與ES6模塊不兼容。語法上面,兩者最明顯的差異是,CommonJS模塊使用require()module.exports,ES6模塊使用importexport
?
ES6模塊不是對象,而是通過export命令顯式指定輸出的代碼,再通過import命令輸入。
?
模塊化的作用

  • 異步加載:異步加載JS文件,結合了async和defer的好處;
  • 私密不漏:需要哪些組件就導出哪些,不需要導出所有,這樣私密性就好一點;
  • 重名不怕:多個JS文件中函數(shù)或變量重名,通過模塊化可以解決重名沖突的問題;
  • 依賴不亂:比如說有1.js、2.js兩個文件,2.js中需要用到1.js中的函數(shù),那么1.js就需要比2.js先加載完,不然就會找不到這個函數(shù),使用模塊化的方式就能很好的解決這個問題,也就是在2.js中導入1.js中導出的函數(shù)即可。
16.1、export語法
16.1.1、export + 變量聲明

這種方式應該是大家日常開發(fā)中使用頻率最高的的一種接口導出方式,尤其是在封裝公共方法或者抽取業(yè)務模塊的時候。并不支持 export 后面直接使用變量名稱。
?
export命令規(guī)定的是對外的接口,必須與模塊內部的變量建立一一對應關系。

// 正確使用方式
export const moduleName = "es module";
export const moduleType = "js";
export const moduleSize = 200;

// 錯誤使用方式
export moduleName;
const moduleType = "js";
export moduleType;
16.1.2、export+{}

這種方式就是在模塊進行大量的邏輯的鋪排,然后在模塊的底部將需要對外開放的接口一次性導出即可,最大的好處就是可讀性高,可以在模塊的底部快速的找到對外導出的接口,然后按需導入想要使用的接口。

const moduleName = "es module";
const moduleType = "js";
const moduleSize = 200;
export {
  moduleName,
  moduleType,
  moduleSize,
}
16.1.3、export default

這種方式其實就是前面第2個語法的語法糖,相當于進行了 export { * as default },當然,也能單個單個的導出。

const moduleInfo = {
  name: 'es module',
  type: 'js',
  size: 200,
}

export default moduleInfo;
16.2、import語法
16.2.1、import普通接口

針對export中的前兩種接口導出方式,import有與之對應的接口引入方式。這種接口引入的方式的語法是:import { [name] } from '[moduleName]',其中name對應export的接口名稱,moduleName對應模塊名稱或者模塊路徑。
?
通過export { [name] }導出的接口,不支持通過import [name]的方式導入。

// 正確使用方式
import { moduleName, moduleType, moduleSize } from './modules/index';

// 錯誤使用方式
import module from './modules/index';
16.2.2、import default接口

針對export default [name]導出的接口也有一套與之匹配的接口導入方式。比較常規(guī)的導入方式是通過import [name]的方式引入,這也是我們日常開發(fā)中使用最高頻的導入方式。

// 正確使用方式
import module from './modules/index';

// 錯誤使用方式
import { module } from './modules/index';

//export default其實是export { * as default },我們其實也可以通過 import 普通接口的方式將其導入:
import { default as module } from './modules/index';
16.2.3、import *

說實話,在不考慮代碼tree shake的前提條件下,其實是蠻省事情的:
?
import * as module from './modules/index';

16.3、export和import的組合

不僅可以單獨使用export和import,還可以將它們組合起來一起使用,組合起來更加便捷。

//導入index模塊到當前模塊,然后導出,這樣其它導入當前模塊的,就能同時用index模塊和當前模塊的組件了,*后面還能跟as取別名
export * from './modules/index'
//其實就是下面這段代碼的變種:
import * as index from './modules/index';
export { ...index }
16.4、CommonJS的導入和導出

導出: 可以導出任意類型數(shù)據(jù)

// module.js
module.exports = {
    name:'banana',
    age:18,
    eat:function(){
        console.log('I like eating bananas')
    }
}
module.exports.userName = 'admin'

導入:文章來源地址http://www.zghlxwxcb.cn/news/detail-471649.html

// app.js
const obj = require('./module.js')
console.log(obj) // { name: 'banana', age: 18, eat: [Function: eat], userName: 'admin' }

// 如果只想導入某個屬性,可以使用解構賦值
const { name } = require('./module')
console.log(name) // 'banana'

上一篇文章 下一篇文章
ES7新特性

到了這里,關于ES6新特性的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • ES6新特性

    ES6新特性

    1、初識ES6 ECMAScript 6.0(簡稱ES6)是JavaScript語言的下一代標準,已經(jīng)在2015年6月正式發(fā)布了。它的目標,是使得JavaScript語言可以用來編寫復雜的大型應用程序,成為企業(yè)級開發(fā)語言; ? ECMAScript是JavaScript的規(guī)范,而JavaScript是ECMAScript的實現(xiàn); ? ES6是一個歷史名詞,泛指 5.1 版本后

    2024年02月07日
    瀏覽(22)
  • 【ES6 新特性】

    ES6 為字符串擴展了幾個新的 API: includes() :返回布爾值,表示是否找到了參數(shù)字符串。 startsWith() :返回布爾值,表示參數(shù)字符串是否在原字符串的頭部。 endsWith() :返回布爾值,表示參數(shù)字符串是否在原字符串的尾部。 模板字符串相當于加強版的字符串,用反引號 `,除了

    2024年02月11日
    瀏覽(21)
  • ES6 特性

    ES6 特性

    1.1.1 什么是 ES ES 全稱 EcmaScript 是腳本語言的規(guī)范 JavaScript 是 EcmaScript 的一種實現(xiàn) ES 新特性就是指 JavaScript 的新特性 1.1.2 為什么要使用 ES 語法簡單,功能豐富 框架開發(fā)應用 前端開發(fā)職位要求 1.1.3 為什么要學習 ES6 ES6 的版本變動最多,具有里程碑的意義 ES6 加入許多新的語法

    2024年02月07日
    瀏覽(22)
  • ES6的重要特性

    1. 塊級作?域:引? let 和 const ,允許在塊級作?域中聲明變量,解決了變量提升和作?域污染的問題。 2. 箭頭函數(shù):使?箭頭( = )定義函數(shù),簡化了函數(shù)的書寫,并且?動綁定了 this 。 3. 模板字符串:使?反引號(`)包裹字符串,可以在字符串中使?變量和表達式

    2024年02月19日
    瀏覽(31)
  • ES6常用新特性

    ES6改動很大,可以簡單分為四類 1、解決原有語法的缺陷和不足 例如:let,const 2、對原有語法進行增強 解構、擴展、模板字符串 3、新增對象、全新的方法,全新的功能 Object.assign()、Proxy對象代理、Reflect 等等 4、全新的數(shù)據(jù)類型和數(shù)據(jù)結構 set、map、class、迭代器、生成器 等

    2024年02月09日
    瀏覽(18)
  • ES6及以上新特性

    ES6及以上新特性

    ES6(ECMAScript 2015)及以上版本引入了許多新特性,每個版本都有不同的增強和改進。以下是 ES6 及以上版本的新特性的詳細描述: ES6(ECMAScript 2015): let 和 const 聲明:引入塊級作用域的變量聲明,用于替代 var 聲明,解決了變量提升的問題。 箭頭函數(shù):用 “=” 符號定義函

    2024年02月14日
    瀏覽(41)
  • 【ES6】—【新特性】—Symbol詳情

    【ES6】—【新特性】—Symbol詳情

    定義:獨一無二的字符串 PS: Symbol 聲明的值是獨一無二的 PS: 無論Symbol.for()在哪里聲明,都屬于全局環(huán)境聲明 當一個對象的key值有重復時,后面的值會覆蓋前面的值 PS: 使用Symbol的獨一無二的特性來解決

    2024年02月10日
    瀏覽(27)
  • ES新特性系列(一)—— ES的簡介與ES6

    ES新特性系列(一)—— ES的簡介與ES6

    ? ? ? 前幾天在BOSS上了解現(xiàn)在的前端工作的情況和各個公司要求的技術棧情況,看到一條非常有意思的要求:“能夠理解并使用ES6、ES7、ES8、ES9、ES10新特性,都2024年了你總不能只知道ES6吧?” ? ? ? 各位彥祖現(xiàn)在現(xiàn)在就回憶一下,自己是否能把上述的ES系列的常用新特性都

    2024年04月29日
    瀏覽(20)
  • ES6 新特性(詳細復習筆記)--下

    應用實例-聲明對象簡寫 1. 需求: 演示聲明對象簡寫 代碼演示 2-需求: 演示對象方法簡寫 3-應用實例-對象拓展運算符 需求: 演示對象拓展運算符使用 拷貝對象(深拷貝)的用法和理解 對象拓展運算符是比較新的特性,低版本的瀏覽器不支持 火狐/谷歌瀏覽器沒有問題 基本介紹

    2024年02月15日
    瀏覽(23)
  • es6有哪些新特性?用法和案例

    目錄 箭頭函數(shù) 模板字符串 ?解構賦值 Promise ?async/await 箭頭函數(shù)使用 = 符號定義,可以更簡潔地書寫函數(shù)并且自動綁定 this 。比如: 箭頭函數(shù)通常用在回調函數(shù)中,例如: 模板字符串是一種新的字符串格式,可以包含變量、表達式和換行符。通過使用占位符 ${} 可以插入變

    2024年02月06日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包