JS面向對象

一. JavaScript面向對象前言

1.1 什麼是對象?

Everything is object (萬物皆對象)。
對象究竟是什麼,咱們能夠從兩個層次來理解。javascript

  1. 對象是單個事物的抽象前端

    一本書、一輛汽車、一我的均可以是對象,一個數據庫、一張網頁、一個與遠程服務器的鏈接也能夠是對象。當實物被抽象成對象,實物之間的關係就變成了對象之間的關係,從而就能夠模擬現實狀況,針對對象進行編程。
  2. 對象是一個容器,封裝了屬性(property)和方法(method)java

    屬性是對象的狀態,方法是對象的行爲(完成某種任務)。好比,咱們能夠把動物抽象爲animal對象,使用「屬性」記錄具體是那一種動物,使用「方法」表示動物的某種行爲(奔跑、捕獵、休息等等)
       在實際開發中,對象是一個抽象的概念,能夠將其簡單理解爲 : 數據集或功能集。

1.2 什麼是面向對象?

面向對象只是過程式代碼的一種高度封裝,目的在於提升代碼的開發效率和可維護性

小編的理解:面向對象就是說,使用對象的時候,你能夠直接使用它所提供的功能而忽略其內部組成狀況。面對對象不必定只有在編程界裏纔有,咱們生活中無處不在;好比說,你家裏的電視機,你使用了遙控,就能操做電視機,可是你實際上不知道這臺電視機裏面是什麼零件組成的,你只要知道,我拿到遙控就能夠操做電視機就行了。這就是一種面向對象的思想。數據庫

1.2.1 什麼是面向對象編程?

面向對象編程 —— Object Oriented Programming,簡稱 OOP ,是一種編程開發思想。
它將真實世界各類複雜的關係,抽象爲一個個對象,而後由對象之間的分工與合做,完成對真實世界的模擬。
在面向對象程序開發思想中,每個對象都是功能中心,具備明確分工,能夠完成接受信息、處理數據、發出信息等任務。
所以,面向對象編程具備靈活、代碼可複用、高度模塊化等特色,容易維護和開發,比起由一系列函數或指令組成的傳統的過程式編程(procedural programming),更適合多人合做的大型軟件項目。編程

1.2.2 面向對象與面向過程

  • 面向過程就是親力親爲,事無鉅細,面面俱到,步步緊跟,有條不紊
  • 面向對象就是找一個對象,指揮得結果
  • 面向對象將執行者轉變成指揮者
  • 面向對象不是面向過程的替代,而是面向過程的封裝

二. 對象定義的兩種方式

2.1 字面量的方式進行定義

var  obj = {
                    name: "Tom ",
                    sex: " man",
                    age:19,
                    run:function(){
                        console.log("一天跑一千米");
                    }
          }

2.2 使用 new Object() 進行定義

var   obj = new  Object();
         obj.name = "Tom ";
         obj.sex = " man";
         obj.age = 19;
         obj.run = function(){
                     console.log("一天跑一千米");
         }

三. 類和對象

3.1 什麼是類(Class)?

具備相同特性(數據元素)和行爲(功能)的對象的抽象就是類。所以,對象的抽象是類,類的具體化就是對象,也能夠說類的實例是對象,類實際上就是一種數據類型。類具備屬性,它是對象狀態的抽象,用數據結構來描述類的屬性。類具備操做,它是對象行爲的抽象,用操做名和實現該操做的方法來描述。服務器

3.2 類和對象的區別

做爲初學者,容易混淆類和對象的概念。類(Class)是一個抽象的概念,對象則是類的具體實例。好比:人是一個類,司馬遷,李白,杜甫都是對象;首都是一個類,則北京,倫敦,華盛頓,莫斯科都是對象;動物貓是一個類,則Kitty、Grafield 和 Doraemon 都是對象。
咱們能夠說 Kitty 貓的體重是 1.5kg,而不能說貓類的體重是 1.5kg;能夠說李白是詩人,而不能說人類是詩人。狀態是描述具體對象而非描述類的,行爲是由具體對象發出的而非類發出的。數據結構

3.3 類和對象的關係

類與對象的關係就如模具和鑄件的關係,類實例化的結果就是對象,而對象的抽象就是類,類描述了一組有相同特性(屬性)和相同行爲的對象。模塊化

class person{ }//這個是類
    $obj = new person();//類的實例化就是對象

四.建立對象的三種方式

4.1 工廠模式,使用簡單的函數建立對象,爲對象添加屬性和方法,而後返回對象

// Class 模板
    function  Person(name,sex,age){
        var  obj = {};
        obj.name = name;
        obj.sex = sex;
        obj.age = age;
        obj.run = function(){
            console.log("天天堅持跑步");
        }
        return obj;
    }
    // 實例化
    var  person1 = Person("Tom","sex",19);
    //操做
    person1.run();  //  輸出結果:天天堅持跑步

4.1.1 工廠模式的優缺點

優勢:
一、 在工廠模式中,用戶只須要知道所要生產的具體東西,無須關心具體的建立過程,甚至不須要具體產品類的類名。
二、 在系統增長新的產品時,咱們只須要添加一個具體產品類和對應的實現工廠,無需對原工廠進行任何修改,很好地符合了「開閉原則」。
缺點:
一、 每次增長一個產品時,都須要增長一個具體類和對象實現工廠,使得系統中類的個數成倍增長,在必定程度上增長了系統的複雜度,同時也增長了系統具體類的依賴。這並非什麼好事。函數

4.2 構造函數模式。建立自定義引用類型,能夠像建立內置對象實例同樣使用new操做符,這種方法的缺點是,構造函數的每一個成員都沒法複用,每次建立出的對象都只有私有變量和私有方法,不能實現共用

//構造函數(這裏就建立了一個Class模板)
    function Person(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.run = function(){
            console.log("天天堅持跑步");
        }
    }
 // 實例化 ( new Object())
    var person1 = new Person("Tom","man",19);
 //操做
    person1.run();// 天天堅持跑步

4.2.1 構造函數的改進

// 構造全局的對象
    var  action = {
        run:function(){
            console.log("天天堅持跑步");
        }
    }
    //構造函數
    funcction(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.run = action.run;
    }
    //實例化
    var person1 = new Person("Tom","man",19);
    person1.run();

分析: 爲何要改進構造函數?
咱們都知道當實例化一個對象後,那麼這個對象就擁有了模板的屬性和方法,
當咱們使用方法時首先會在內存中開闢一份空間,而後在執行相應的操做。假設咱們實例化一萬個對象,那麼這一萬個對象在執行方法時都要在內存中開闢空間,這樣只會浪費內存的空間,這時若是能用一個操做代替一萬個操做那樣豈不是美哉,因此小編這裏用了一個全局的對象,即便是一萬個對象使用這個方法只會在內存中開闢一份空間。
可是這也有缺點,咱們都知道全局變量和局部變量,全局變量易形成污染而且聲明週期比較長,那麼全局對象也是同樣的,有沒有一種方式能夠不用所有對象呢?固然有,見下面的第三種建立模式學習

4.3 原型模式,使用構造函數的prototype屬性來指定共享的屬性和方法,即便用構造函數定義實例屬性,使用原型定義共享的屬性和方法

//構造函數
    function Person(name,sex,age){
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
    //使用原型對象   Object.prototype
    Person.prototype.run = function() {
        console.log("天天堅持跑步");
    }
    //實例化
    var person1 = new  Person("Tom","man",19);
    person1.run();//  天天堅持跑步

五.構造函數、原型對象、實例化對象三則的關係

首先先明白幾個屬性:
__proto__: 對象的原型。全部對象都有(包括函數)

prototype:函數的原型對象。只有函數(準確來講是構造函數)纔有

constructor:對象上的一個屬性,默認指向這個原型的構造函數
圖片描述

六.完全理解js中this的指向

首先必需要說的是,this的指向在函數定義的時候是肯定不了的,只有函數執行的時候才能肯定this到底指向誰,實際上this的最終指向的是那個調用它的對象(這句話有些問題,後面會解釋爲何會有問題,雖然網上大部分的文章都是這樣說的,雖然在不少狀況下那樣去理解不會出什麼問題,可是實際上那樣理解是不許確的,因此在你理解this的時候會有種琢磨不透的感受),那麼接下來我會深刻的探討這個問題。

eg1:

function  show(){
            var user = "Tom";
            console.log(this.user);//undefined
            console.log(this);//window
        }
        show();
按照咱們上面說的this最終指向的是調用它的對象,這裏的函數show()實際是被Window對象所調用出來的,下面的代碼就能夠證實。
function  show(){
            var user = "Tom";
            console.log(this.user);//undefined
            console.log(this);//window
        }
        window.show();
和上面代碼結果同樣,因此此時this是window調用出來的

eg2:

var show = {
            user:"Tom",
            fn:function(){
                console.log(this.user);//Tom
            }
        }
        show.fn();
這裏的this指向的是對象show,由於你調用這個fn是經過show.fn()執行的,那天然指向就是對象show,這裏再次強調一點,this的指向在函數建立的時候是決定不了的,在調用的時候才能決定,誰調用的就指向誰,必定要搞清楚這個。

要想完全搞懂this的指向請看下面的例子

eg3:

var show = {
            user:"Tom",
            fn:function(){
                console.log(this.user);//Tom
            }
        }
        window.show.fn();
  這段代碼和上面的那段代碼幾乎是同樣的,可是這裏的this爲何不是指向window,若是按照上面的理論,最終this指向的是調用它的對象,這裏先說個而外話,window是js中的全局對象,咱們建立的變量其實是給window添加屬性,因此這裏能夠用window點show對象。

這裏先不解釋爲何上面的那段代碼this爲何沒有指向window,咱們再來看一段代碼

var show = {
            a:20,
            b:{
                a:22,
                fn:function(){
                    console.log(this.a);// 22
                }
            }
        }
        show.b.fn();

  這裏一樣也是對象show點出來的,可是一樣this並無執行它,那你確定會說我一開始說的那些不就都是錯誤的嗎?其實也不是,只是一開始說的不許確,接下來我將補充一句話,我相信你就能夠完全的理解this的指向的問題。

  狀況1:若是一個函數中有this,可是它沒有被上一級的對象所調用,那麼this指向的就是window,這裏須要說明的是在js的嚴格版中this指向的不是window,可是咱們這裏不探討嚴格版的問題,你想了解能夠自行上網查找。

  狀況2:若是一個函數中有this,這個函數有被上一級的對象所調用,那麼this指向的就是上一級的對象。

  狀況3:若是一個函數中有this,這個函數中包含多個對象,儘管這個函數是被最外層的對象所調用,this指向的也只是它上一級的對象,例子3能夠證實,若是不相信,那麼接下來咱們繼續看幾個例子。

var show = {
           a:20,
           b:{
               fn:function(){
                   console.log(this.a);// undefined
               }
           }
       }
       show.b.fn();

儘管對象b中沒有屬性a,這個this指向的也是對象b,由於this只會指向它的上一級對象,無論這個對象中有沒有this要的東西。

還有一種比較特殊的狀況,eg4:

var show = {
           a:20,
           b:{
               a:22,
               fn:function(){
                   console.log(this.a);// undefined
                   console.log(this);//window
               }
           }
       }
       var d = show.b.fn;
       d();

這裏this指向的是window,是否是有些蒙了?實際上是由於你沒有理解一句話,這句話一樣相當重要。

 this永遠指向的是最後調用它的對象,也就是看它執行的時候是誰調用的,例子4中雖然函數fn是被對象b所引用,可是在將fn賦值給變量d的時候並無執行因此最終指向的是window,這和例子3是不同的,例子3是直接執行了fn。

this講來說去其實就是那麼一回事,只不過在不一樣的狀況下指向的會有些不一樣,上面的總結每一個地方都有些小錯誤,也不能說是錯誤,而是在不一樣環境下狀況就會有不一樣,因此我也沒有辦法一次解釋清楚,只能你慢慢地的去體會。

構造函數版this:

function Fn(){
                this.user = "Tom";
            }
        var a = new Fn();
        console.log(a.user); //Tom

這裏之因此對象a能夠點出函數Fn裏面的user是由於new關鍵字能夠改變this的指向,將這個this指向對象a,爲何我說a是對象,由於用了new關鍵字就是建立一個對象實例,理解這句話能夠想一想咱們的例子3,咱們這裏用變量a建立了一個Fn的實例(至關於複製了一份Fn到對象a裏面),此時僅僅只是建立,並無執行,而調用這個函數Fn的是對象a,那麼this指向的天然是對象a,那麼爲何對象a中會有user,由於你已經複製了一份Fn函數到對象a中,用了new關鍵字就等同於複製了一份。

當this碰到return:

function Fn(){
            this.user = "Tom";
            return {};
        }
        var a = new Fn();
        console.log(a.user);//undefined

繼續:

function Fn(){
            this.user = "Tom";
            return  funciton(){};
        }
        var a = new Fn();
        console.log(a.user);//undefined

goon:

function Fn(){
            this.user = "Tom";
            return  1;
        }
        var a = new Fn();
        console.log(a.user);// Tom

再繼續:

function Fn(){
            this.user = "Tom";
            return undefined;
        }
        var a = new Fn();
        console.log(a.user);//Tom
若是返回值是一個對象,那麼this指向的就是那個返回的對象,若是返回值不是一個對象那麼this仍是指向函數的實例
function Fn(){
            this.user = "Tom";
            return null;
        }
        var a = new Fn();
        console.log(a.user);//Tom
雖然null也是對象,可是在這裏this仍是指向那個函數的實例,由於null比較特殊

七.總結

這是今天學的看的全部內容,但願對正在學習前端的朋友有所幫助,有什麼問題能夠留言,咱們一塊兒進步!

相關文章
相關標籤/搜索