天天看點

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

文章目錄

  • 一、原型繼承
  • 二、Class關鍵字
  • 1.ES6之前
  • 2.ES6後
  • 3.補充
  • 三、Map和Set
  • 四、Iterator(疊代器)
  • 1.周遊數組
  • 2.周遊Map
  • 3.周遊Set
  • 五、JS中不完善的報錯+手動改進(throw+【argument】+補充:【...rest】)
  • 1.函數參數中報錯不完善
  • 2.var局部作用域中的bug
  • 六、使JS的原生方法失效+恢複
  • 七、多個js檔案全局周遊沖突問題
  • 八、方法與函數

一、原型繼承

執行個體中,tom本身沒有run方法,無法調用run

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

但如果想調用,則可讓tom的原型對象指向Student,這樣,tom對象在調用run方法時,在本對象中查不到run方法時,則會去tom對象的__proto__屬性中去查找run方法,也就是先在tom對象的原型鍊上查找緊鄰上一個原型對象中的方法

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

當然,要注意的是,将tom的原型指向Student時,Student的原型也會連接配接過來

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

每個對象和原型都有原型,對象的原型指向原型對象,而父的原型又指向父的父,這種原型層層連接配接起來的就構成了原型鍊。

作為一個對象,當你通路其中的一個屬性或方法的時候,如果這個對象中沒有這個方法或屬性,那麼JavaScript引擎将會通路這個對象的__proto__屬性所指向的上一個對象,并在那個對象中查找指定的方法或屬性,如果不能找到,那就會繼續通過那個對象 的__proto__屬性指向的對象進行向上查找,直到這個連結清單結束

二、Class關鍵字

1.ES6之前

在ES6之前,隻能這樣定義類

<script>
    "use strict";

    function Student(name) {
        this.name = name;
    }

    //給Student類新增一個方法,上面的Student(name)為構造函數
    //給類增加方法,是以需指向Student(name)函數的原型對象
    Student.prototype.hello = function () {
        console.log('Hello ' + this.name);
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

引入一張圖

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

2.ES6後

在ES6時,引入了Class關鍵字,使得此操作更加友善、合理和規範

<script>
    "use strict";

    class Student {
        constructor(name) {
            this.name = name;
        }
        
        hello() {
            console.log('Hello ' + this.name)
        }
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

繼承用關鍵字extends

<script>
    "use strict";

    class Student {
        constructor(name) {
            this.name = name;
        }

        hello() {
            console.log('Hello ' + this.name)
        }
    }

    class PrimaryStudent extends Student {
        constructor(name, grade) {
            super(name);
            this.grade = grade;
        }

        say() {
            console.log('I‘m a primary student');
        }
    }
</script>      

如圖,extends本質也是原型鍊的思想

(注:下圖Object原型後面還有連接配接的原型)

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

3.補充

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

(1)得到原型類:

方法一:對象執行個體名._proto_

方法二:類名.prototype

三、Map和Set

二者為ES6的新增資料類型。

Map:(鍵值對)

常用方法:

  • set(‘key’, value):添加某個值。
  • delete(value):删除某個值。
  • get(‘key’):得到此鍵的某個值
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

Set:(去重的無序集合)

常用方法:

  • add(value):添加某個值。
  • delete(value):删除某個值。
  • has(value):某值是否在集合内。
  • clear():清除集合中所有元素。

四、Iterator(疊代器)

為ES6新特性。

1.周遊數組

普通的周遊方法如下:

for in:周遊下标

for of:周遊值

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

2.周遊Map

for of:周遊鍵+值

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

3.周遊Set

for of:周遊值

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

五、JS中不完善的報錯+手動改進(throw+【argument】+補充:【…rest】)

1.函數參數中報錯不完善

例子:

<script>
    "use strict";

    function abs(x) {
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }
</script>      

函數傳遞多個參數,或不傳遞參數,或是傳遞另一種類型的參數,都不會報錯,最多是NaN值,進而可能導緻間接報錯,但不會出現直接報錯

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

加一段判斷參數類型的語句,來手動抛出異常(但也隻能解決隻傳一個參數時的類型問題)

<script>
    "use strict";

    function abs(x) {
        if (typeof x !== 'number') {
            throw 'Not a Number~';
        }
        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

由于可利用JS的關鍵字arguments來接收多個函數參數,否則,若函數隻定義了一個參數,則其它傳入的參數(從第二個參數往後的所有參數),都不會參與到函數中,但卻保留在arguments中

<script>
    "use strict";

    function abs(x) {
        if (typeof x !== 'number') {
            throw 'Not a Number~';
        }

        console.log('x=>' + x);
        console.log('argument周遊');
        for (let i = 0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }

        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

是以,再次改進代碼,即可寫出一個報錯完整的函數

<script>
    "use strict";

    function abs(x) {
        if (typeof x !== 'number') {
            throw 'Not a Number~';
        }

        if (arguments.length > 1) {
            throw 'Please Input one arg~'
        }

        if (x >= 0) {
            return x;
        } else {
            return -x;
        }
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

補充:另外,還有一個…rest(ES6新增),寫在函數定義的參數清單最後面,用于接收除已定義參數外的額外傳入的參數

<script>
    "use strict";

    function talk(x, ...rest) {
        let i;

        for (i = 0; i < arguments.length; i++) {
            console.log(arguments[i]);
        }
        console.log('-----------------------')
        console.log(rest);
    }
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

2.var局部作用域中的bug

<script>
    "use strict";

    for (var i = 0; i < 2; i++) {
        console.log('in: ' + i);
    }
    //仍然可以輸出i
    console.log('out: ' + i);
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

改進:将var改為let

<script>
    "use strict";

    for (let i = 0; i < 2; i++) {
        console.log('in: ' + i);
    }
    //不可以輸出i
    console.log('out: ' + i);
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

六、使JS的原生方法失效+恢複

預先記錄原方法引用,随後消除原方法:

<script>
    "use strict";

    let x = 'xxx';

    var old_alert = window.alert;

    window.alert = function (){

    }

    window.alert(123);
    window.old_alert('old: ' + x);
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

當然,也可以設定恢複

<script>
    "use strict";

    let x = 'xxx';

    var old_alert = window.alert;

    window.alert = function (){

    }

    window.alert(123);
    // window.old_alert('old: ' + x);

    //恢複
    window.alert = old_alert;
    window.old_alert('re-old: ' + x);
</script>      
【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

七、多個js檔案全局周遊沖突問題

問題:由于我們所有的全局變量都會綁定到window對象上,是以,如果使用不同的js檔案,遇到相同名字的全局變量時,就會産生沖突。

解決方法:在每個js中都自定義一個唯一的全局變量對象,将這個腳本檔案中的所有全局變量都賦予該全局變量對象,進而降低全局命名沖突的問題。(JQuery也參考了這個思想)

例如:

<script>
    "use strict";

    //唯一全局變量
    var appT = {};

    appT.name = 'zlc';
    appT.add = function(x, y) {
        return x + y;
    }

    //使用時
    console.log(window.appT.add(1, 2));
</script>      

八、方法與函數

(在講述的時候需格外注意,不要将方法說成函數)

方法:

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

或是這樣的形式

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

方法調用:obj.method(),需要加括号

函數:

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

用函數的apply方法調用函數:格式:函數名.apply(對象, 參數清單);

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

普通函數調用和apply函數調用,結果相同

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

直接調用getAge()函數将會報錯

【JavaScript精華荟萃】精華彙總+易混淆知識(中篇)

繼續閱讀