<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

        javascript面向對象全新理練之繼承與多態_js面向對象

        來源:懂視網 責編:小采 時間:2020-11-27 20:45:57
        文檔

        javascript面向對象全新理練之繼承與多態_js面向對象

        javascript面向對象全新理練之繼承與多態_js面向對象:1 又是幾個基本概念 為什么要說又呢? 在討論繼承時,我們已經列出了一些基本概念了,那些概念是跟封裝密切相關的概念,今天我們要討論的基本概念,主要是跟繼承與多態相關的,但是它們跟封裝也有一些聯系。 1.1 定義和賦值 變量定義是指用 var a; 這種形
        推薦度:
        導讀javascript面向對象全新理練之繼承與多態_js面向對象:1 又是幾個基本概念 為什么要說又呢? 在討論繼承時,我們已經列出了一些基本概念了,那些概念是跟封裝密切相關的概念,今天我們要討論的基本概念,主要是跟繼承與多態相關的,但是它們跟封裝也有一些聯系。 1.1 定義和賦值 變量定義是指用 var a; 這種形

        1 又是幾個基本概念
        為什么要說又呢?
        在討論繼承時,我們已經列出了一些基本概念了,那些概念是跟封裝密切相關的概念,今天我們要討論的基本概念,主要是跟繼承與多態相關的,但是它們跟封裝也有一些聯系。
        1.1 定義和賦值
        變量定義是指用
        var a;
        這種形式來聲明變量。
        函數定義是指用
        function a(...) {...}
        這種形式來聲明函數。
        var a = 1;
        是兩個過程。第一個過程是定義變量 a,第二個過程是給變量 a 賦值。
        同樣
        var a = function(...) {};
        也是兩個過程,第一個過程是定義變量 a 和一個匿名函數,第二個過程是把匿名函數賦值給變量 a。
        變量定義和函數定義是在整個腳本執行之前完成的,而變量賦值是在執行階段完成的。
        變量定義的作用僅僅是給所聲明的變量指明它的作用域,變量定義并不給變量初始值,任何沒有定義的而直接使用的變量,或者定義但沒有賦值的變量,他們的值都是 undefined。
        函數定義除了聲明函數所在的作用域外,同時還定義函數體結構。這個過程是遞歸的,也就是說,對函數體的定義包括了對函數體內的變量定義和函數定義。
        通過下面這個例子我們可以更明確的理解這一點:
        代碼如下:
        alert(a);
        alert(b);
        alert(c);
        var a = "a";
        function a() {}
        function b() {}
        var b = "b";
        var c = "c";
        var c = function() {}
        alert(a);
        alert(b);
        alert(c);

        猜猜這個程序執行的結果是什么?然后執行一下看看是不是跟你想的一樣,如果跟你想的一樣的話,那說明你已經理解上面所說的了。
        這段程序的結果很有意思,雖然第一個 alert(a) 在最前面,但是你會發現它輸出的值竟然是 function a() {},這說明,函數定義確實在整個程序執行之前就已經完成了。
        再來看 b,函數 b 定義在變量 b 之前,但是第一個 alert(b) 輸出的仍然是 function b() {},這說明,變量定義確實不對變量做什么,僅僅是聲明它的作用域而已,它不會覆蓋函數定義。
        最后看 c,第一個 alert(c) 輸出的是 undefined,這說明 var c = function() {} 不是對函數 c 定義,僅僅是定義一個變量 c 和一個匿名函數。
        再來看第二個 alert(a),你會發現輸出的竟然是 a,這說明賦值語句確實是在執行過程中完成的,因此,它覆蓋了函數 a 的定義。
        第二個 alert(b) 當然也一樣,輸出的是 b,這說明不管賦值語句寫在函數定義之前還是函數定義之后,對一個跟函數同名的變量賦值總會覆蓋函數定義。
        第二個 alert(c) 輸出的是 function() {},這說明,賦值語句是順序執行的,后面的賦值覆蓋了前面的賦值,不管賦的值是函數還是其它對象。
        理解了上面所說的內容,我想你應該知道什么時候該用 function x(..) {…},什么時候該用 var x = function (…) {…} 了吧?
        最后還要提醒一點,eval 中的如果出現變量定義和函數定義,則它們是在執行階段完成的。所以,不到萬不得已,不要用 eval!另外,即使要用 eval,也不要在里面用局部變量和局部方法!
        1.2 this 和執行上下文
        在前面討論封裝時,我們已經接觸過 this 了。在對封裝的討論中,我們看到的 this 都是表示 this 所在的類的實例化對象本身。真的是這樣嗎?
        先看一下下面的例子吧:
        代碼如下:
        var x = "I'm a global variable!";
        function method() {
        alert(x);
        alert(this.x);
        }
        function class1() {
        // private field
        var x = "I'm a private variable!";
        // private method
        function method1() {
        alert(x);
        alert(this.x);
        }
        var method2 = method;
        // public field
        this.x = "I'm a object variable!";
        // public method
        this.method1 = function() {
        alert(x);
        alert(this.x);
        }
        this.method2 = method;
        // constructor
        {
        this.method1(); // I'm a private variable!
        // I'm a object variable!
        this.method2(); // I'm a global variable!
        // I'm a object variable!
        method1(); // I'm a private variable!
        // I'm a global variable!
        method2(); // I'm a global variable!
        // I'm a global variable!
        method1.call(this); // I'm a private variable!
        // I'm a object variable!
        method2.call(this); // I'm a global variable!
        // I'm a object variable!
        }
        }
        var o = new class1();
        method(); // I'm a global variable!
        // I'm a global variable!
        o.method1(); // I'm a private variable!
        // I'm a object variable!
        o.method2(); // I'm a global variable!
        // I'm a object variable!

        為什么是這樣的結果呢?
        那就先來看看什么是執行上下文吧。那什么是執行上下文呢?
        如果當前正在執行的是一個方法,則執行上下文就是該方法所附屬的對象,如果當前正在執行的是一個創建對象(就是通過 new 來創建)的過程,則創建的對象就是執行上下文。
        如果一個方法在執行時沒有明確的附屬于一個對象,則它的執行上下文是全局對象(頂級對象),但它不一定附屬于全局對象。全局對象由當前環境來決定。在瀏覽器環境下,全局對象就是 window 對象。
        定義在所有函數之外的全局變量和全局函數附屬于全局對象,定義在函數內的局部變量和局部函數不附屬于任何對象。
        那執行上下文跟變量作用域有沒有關系呢?
        執行上下文與變量作用域是不同的。
        一個函數賦值給另一個變量時,這個函數的內部所使用的變量的作用域不會改變,但它的執行上下文會變為這個變量所附屬的對象(如果這個變量有附屬對象的話)。
        Function 原型上的 call 和 apply 方法可以改變執行上下文,但是同樣不會改變變量作用域。
        要理解上面這些話,其實只需要記住一點:
        變量作用域是在定義時就確定的,它永遠不會變;而執行上下文是在執行時才確定的,它隨時可以變。
        這樣我們就不難理解上面那個例子了。this.method1() 這條語句(注意,這里說的還沒有進入這個函數體)執行時,正在創建對象,那當前的執行上下文就是這個正在創建的對象,所以 this 指向的也是當前正在創建的對象,在 this.method1() 這個方法執行時(這里是指進入函數體),這個正在執行的方法所附屬的對象也是這個正在創建的對象,所以,它里面 this.x 的 this 也是同一個對象,所以你看的輸出就是 I'm a object variable! 了。
        而在執行 method1() 這個函數時(是指進入函數體后),method1() 沒有明確的附屬于一個對象,雖然它是定義在 class1 中的,但是他并沒有不是附屬于 class1 的,也不是附屬于 class1 實例化后的對象的,只是它的作用域被限制在了 class1 當中。因此,它的附屬對象實際上是全局對象,因此,當在它當中執行到 alert(this.x) 時,this.x 就成了我們在全局環境下定義的那個值為 “I'm a global variable!” 的 x 了。
        method2() 雖然是在 class1 中定義的,但是 method() 是在 class1 之外定義的,method 被賦值給 method2 時,并沒有改變 method 的作用域,所以,在 method2 執行時,仍然是在 method 被定義的作用域內執行的,因此,你看到的就是兩個 I'm a global variable! 輸出了。同樣,this.method2() 調用時,alert(x) 輸出 I'm a global variable! 也是這個原因。
        因為 call 會改變執行上下文,所以通過 method1.call(this) 和 method2.call(this) 時,this.x 都變成了 I'm a object variable!。但是它不能改變作用域,所以 x 仍然跟不使用 call 方法調用時的結果是一樣的。
        而我們后面執行 o.method1() 時,alert(x) 沒有用 this 指出 x 的執行上下文,則 x 表示當前執行的函數所在的作用域中最近定義的變量,因此,這時輸出的就是 I'm a private variable!。最后輸出 I'm a object variable! 我想不用我說大家也知道為什么了吧?
        2 繼承和多態
        2.1 從封裝開始
        前面我們說了,封裝的目的是實現數據隱藏。
        但是更深一層來說,在 javascript 中進行封裝還有以下幾個好處:
        1、隱身實現細節,當私有部分的實現完全重寫時,并不需要改變調用者的行為。這也是其它面向對象語言要實現封裝的主要目的。
        2、javascript 中,局部變量和局部函數訪問速度更快,因此把私有字段以局部變量來封裝,把私有方法以局部方法來封裝可以提高腳本的執行效率。
        3、對于 javascript 壓縮混淆器(據我所知,目前最好的 javascript 分析、壓縮、混淆器就是 JSA)來說,局部變量和局部函數名都是可以被替換的,而全局變量和全局函數名是不可以被替換的(實際上,對于 javascript 腳本解析器工作時也是這樣的)。因此,不論對于開源還是非開源的 javascript 程序,當私有字段和私有方法使用封裝技術后,編寫代碼時就可以給它們定義足夠長的表意名稱,增加代碼的可讀性,而發布時,它們可以被替換為一些很短的名稱(一般是單字符名稱),這樣就可以得到充分的壓縮和混淆。及減少了帶寬占用,又可以真正實現細節的隱藏。
        所以,封裝對于 javascript 來說,是非常有用的!
        那么在 javascript 實現繼承是為了什么呢?
        2.2 為什么要繼承
        在其它面向對象程序設計語言中,繼承除了可以減少重復代碼的編寫外,最大的用處就是為了實現多態。尤其是在強類型語言中,尤為如此:
        1、在強類型語言中,一個變量不能夠被賦予不同類型的兩個值,除非這兩種類型與這個變量的類型是相容的,而這個相容的關系就是由繼承來實現的。
        2、在強類型語言中,對一個已有的類型無法直接進行方法的擴充和改寫,要擴充一個類型,唯一的方法就是繼承它,在它的子類中進行擴充和改寫。
        因此,對于強類型的面向對象語言,多態的實現是依賴于繼承的實現的。
        而對于 javascript 語言來說,繼承對于實現多態則顯得不那么重要:
        1、在 javascript 語言中,一個變量可以被賦予任何類型的值,且可以用同樣的方式調用任何類型的對象上的同名方法。
        2、在 javascript 語言中,可以對已有的類型通過原型直接進行方法的擴充和改寫。
        所以,在 javascript 中,繼承的主要作用就是為了減少重復代碼的編寫。
        接下來我們要談的兩種實現繼承的方法可能大家已經都很熟悉了,一種是原型繼承法,一種是調用繼承法,這兩種方法都不會產生副作用。我們主要討論的是這兩種方法的本質和需要注意的地方。
        2.3 原型繼承法
        在 javascript 中,每一個類(函數)都有一個原型,該原型上的成員在該類實例化時,會傳給該類的實例化對象。實例化的對象上沒有原型,但是它可以作為另一個類(函數)的原型,當以該對象為原型的類實例化時,該對象上的成員就會傳給以它為原型的類的實例化對象上。這就是原型繼承的本質。
        原型繼承也是 javascript 中許多原生對象所使用的繼承方法。
        代碼如下:
        function parentClass() {
        // private field
        var x = "I'm a parentClass field!";
        // private method
        function method1() {
        alert(x);
        alert("I'm a parentClass method!");
        }
        // public field
        this.x = "I'm a parentClass object field!";
        // public method
        this.method1 = function() {
        alert(x);
        alert(this.x);
        method1();
        }
        }
        parentClass.prototype.method = function () {
        alert("I'm a parentClass prototype method!");
        }
        parentClass.staticMethod = function () {
        alert("I'm a parentClass static method!");
        }
        function subClass() {
        // private field
        var x = "I'm a subClass field!";
        // private method
        function method2() {
        alert(x);
        alert("I'm a subClass method!");
        }
        // public field
        this.x = "I'm a subClass object field!";
        // public method
        this.method2 = function() {
        alert(x);
        alert(this.x);
        method2();
        }
        this.method3 = function() {
        method1();
        }
        }
        // inherit
        subClass.prototype = new parentClass();
        subClass.prototype.constructor = subClass;
        // test
        var o = new subClass();
        alert(o instanceof parentClass); // true
        alert(o instanceof subClass); // true
        alert(o.constructor); // function subClass() {...}
        o.method1(); // I'm a parentClass field!
        // I'm a subClass object field!
        // I'm a parentClass field!
        // I'm a parentClass method!
        o.method2(); // I'm a subClass field!
        // I'm a subClass object field!
        // I'm a subClass field!
        // I'm a subClass method!
        o.method(); // I'm a parentClass prototype method!
        o.method3(); // Error!!!
        subClass.staticMethod(); // Error!!!

        上面這個例子很好的反映出了如何利用原型繼承法來實現繼承。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        javascript面向對象全新理練之繼承與多態_js面向對象

        javascript面向對象全新理練之繼承與多態_js面向對象:1 又是幾個基本概念 為什么要說又呢? 在討論繼承時,我們已經列出了一些基本概念了,那些概念是跟封裝密切相關的概念,今天我們要討論的基本概念,主要是跟繼承與多態相關的,但是它們跟封裝也有一些聯系。 1.1 定義和賦值 變量定義是指用 var a; 這種形
        推薦度:
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲最大福利视频网站| 国产成人精品久久亚洲| 亚洲短视频在线观看| 久久国产精品成人片免费| 亚洲伊人久久大香线蕉苏妲己| 久久国产精品免费| 亚洲线精品一区二区三区影音先锋 | 日韩a级毛片免费视频| 国产成+人+综合+亚洲专| 久久午夜免费视频| 亚洲精品456人成在线| 永久久久免费浮力影院| 亚洲av无码av在线播放| 亚洲国产成人久久综合区| 一个人看的在线免费视频| 亚洲AV无码日韩AV无码导航| 免费h片在线观看网址最新| 在线观看日本亚洲一区| 男人的天堂亚洲一区二区三区 | 亚洲欧洲日产v特级毛片| 亚洲人成免费电影| 伊人久久五月丁香综合中文亚洲 | 亚洲色欲色欲www在线丝| 中文字幕无码日韩专区免费| 亚洲国产美国国产综合一区二区| 中文字幕免费观看| 亚洲日韩国产欧美一区二区三区| 亚洲AV无码乱码在线观看牲色| 黄色短视频免费看| 亚洲无圣光一区二区| 国产男女猛烈无遮挡免费视频网站 | 亚洲av日韩精品久久久久久a| 亚洲 国产 图片| 秋霞人成在线观看免费视频| 亚洲中文字幕乱码熟女在线| 亚洲人成人网站在线观看| 24小时日本电影免费看| 美女被爆羞羞网站在免费观看| 亚洲天堂男人天堂| 免费a级毛片无码a∨性按摩| 91福利免费视频|