面向對象(OOP)和NEW的實現原理

面向對象編程(OOP):
OOP-Object Oriented Programring:面向對象程序設計
POP-Procedure Oriented:面向過程程序設計

面向過程:C語言
面向對象:JS JAVA PHP C# (.net)Python Ruby go …

什麼是面向對象,要正確區分對象,類和實例:
對象: 萬物皆對象
類:對象的細分
實例:類中具體的事物

JS也是面向對象編程:類、實例
1 => Number
‘A’=> Srting
true => Boolean -都屬於大類Object
null => Null
undefined => Undefined
[] => Array
/^$/ => RegExp
function(){} => Function
{} => Object

每一個實例可以調用所屬類(整條鏈)中的屬性和方法。
所以學習JS時,按照面向對象的思維去考慮事情。
在開發中,遇到實例,要可以研究它的子類,父類,基類。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>面向對象</title>
</head>

<body>
    <!-- 
        每一個元素標籤(元素對象)都有一個自己所屬的大類。
        div -> HTMLDivElement -> HTMLElement -> Element -> Node -> EventTarget -> Object
        每一個實例可以調用所屬類(整條鏈)中的屬性和方法
        子類不屬於父類的實例,實例是具體的東西,所以在學習JS時,要按照面向對象的思維去考慮事情
    -->
    <!-- 打開頁面,在控制檯輸入dir(box) => 可以看到它的類__proto__: HTMLDivElement -> __proto__: HTMLElement -> __proto__: Element -> __proto__: Node(元素節點) -> __proto__: EventTarget(事件目標類)-> __proto__: Object  -->

    <div id="box"></div>

    <script>

        /*
        *   JS中已經有一些內置的類,但在開發中,只有這一些是不夠的,所以會需要自定義類。
        *       => 創建一個函數(Function類的實例),直接執行就是普通函數,但是“new執行”,它則被稱爲一個自定義的類
        *       NEW函數執行:
        *           形成一個全新的執行上下文EC
        *           形成一個變量對象AO
        *               ARGUMENTS
        *               形參賦值
        *          // 聲明其THIS指向(普通函數執行,new出來的實例指向不同)
        *           初始化作用域鏈
        *           【新】默認創建一個對象,而這個對象就是當前類的實例
        *           【新】聲明其THIS指向,讓其指向這個新創建的實例
        *           代碼執行
        *           【新】不論其是否寫RETURN,都會把新創建的實例返回(特殊點)
        *
        */
        //  new函數執行,既包含了普通函數應該辦的事,也包含了new時所有的特殊的處理
        /*
        function func() {
            // let obj = {}; //=> 這個對象就是實例對象
            //this -> obj
            let x = 100;
            this.num = x + 100; //=> 相當於給創建的實例對象新增一個num的屬性
            //obj.num = 200; (因爲具備普通函數執行的一面,所以只有this.XXX=xxx才和創建的實例有關係,此案例中的x只是AO中的私有變量)
            //return obj; 用戶自己返回內容,如果返回的是一個引用類型值,則會把默認返回的實例給覆蓋掉(此時返回的值就不再是類的實例了)。比如return {x:3000},輸出的就是x:3000,基本類型的值沒有影響。
        }
        let f = new func();
        console.log(f); //=> f是func這個類的實例
        // let f2 = new func();
        // console.log(f2);
        // console.log(f === f2); //false =>因爲每一次new出來的都是一個新的實例對象,(一個新的堆內存),所以是不相等的
        // func(); //=> this:window 變量對象AO(FUNC): {x:100} ...普通函數執行
        console.log(f instanceof func);//TRUE ;instanceof 用來檢測某一個實例是否屬於這個類 在此即代表f是否是func的實例
        */
    </script>

    <script>
        function Dog(name) {
            this.name = name;
        }
        Dog.prototype.bark = function () {
            console.log('wangwang');
        }
        Dog.prototype.sayName = function () {
            console.log('my name is' + this.name);
        }
        /*
        使用new可以實現
        let sanmao = new Dog('三毛');
        sanmao.sayName();
        sanmao.bark();
        */
        /*
        *內置NEW的實現原理
        *   @params:
        *       Func:操作的那個類
        *       ARGS:NEW類的時候傳遞的實參集合
        *   @return:
        *       實例或者自己返回的對象
        */
        function _new(Func, ...args) {
            // =>在此是執行的過程
            // 默認創建一個實例對象(而且是屬於當前這個類的一個實例)
            // let obj = {};
            // 若想要obj指向Dog的原型,需要以下代碼
            // obj.__proto__ = Func.prototype; //=> IE大部分瀏覽器中不允許我們直接操作__proto__,所以可以直接將lei obj = {}和obj.__proto__ = Func.prorotype合併爲下邊的一步:
            let obj = Object.create(Func.prototype);


            // 也會把類當做普通函數執行
            // 執行的時候要保證函數中的THIS指向創建的實例
            let result = Func.call(obj, ...args);//當做普通函數執行,傳參數...args,要把this指向當前的實例,使用call轉換this
            // 若客戶自己返回引用值,則以自己返回的爲主,否則返回創建的實例
            if ((result != null && typeof result === "object") || (typeof result === "function")) {
                return result
            }
            return obj;
        }
        let sanmao = _new(Dog, '三毛');
        console.log(sanmao); //name: "三毛" 原型指向object __proto__: Object ,是沒有指向Dog.protoType的,sanmao.bark()會報錯,Uncaught TypeError: sanmao.bark is not a function,因爲原型沒有指對
        /*
        若使用new,在控制檯中輸入 sanmao = new Dog();原型指向Dog.prototype,結果是這樣的:sanmao= new Dog('三毛');
        Dog {name: "三毛"}
            name: "三毛"
            __proto__: Object
                bark: ƒ ()
                sayName: ƒ ()
                constructor: ƒ Dog(name)
                __proto__: Object
        */
        sanmao.bark(); //=>'wangwang' 
        sanmao.sayName();//=>"my name is 三毛"l
        console.log(sanmao instanceof Dog); //=>true
    </script>
</body>

</html>

內置NEW的實現原理
@params:
Func:操作的那個類
ARGS:NEW類的時候傳遞的實參集合
@return:
實例或者自己返回的對象
function new(Func, …args) {
// =>在此是執行的過程
// 默認創建一個實例對象(而且是屬於當前這個類的一個實例)
// let obj = {};
// 若想要obj指向Dog的原型,需要以下代碼
// obj.proto = Func.prototype; //=> IE大部分瀏覽器中不允許我們直接操作__proto
_,所以可以直接將lei obj = {}和obj.proto = Func.prorotype合併爲下邊的一步:
//create方法,可見https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create
let obj = Object.create(Func.prototype);

        // 也會把類當做普通函數執行
        // 執行的時候要保證函數中的THIS指向創建的實例
        let result = Func.call(obj, ...args);//當做普通函數執行,傳參數...args,要把this指向當前的實例,使用call轉換this
        // 若客戶自己返回引用值,則以自己返回的爲主,否則返回創建的實例
        if ((result != null && typeof result === "object") || (typeof result === "function")) {
            return result
        }
        return obj;
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章