js設計模式--面向對象與面向過程


在不會面向對象編程之前,我們都是采用面向過程編程的。按照傳統流程編寫一個個的函數來解決需求的這種方式就是過程編程。

面向對象編程就是將你的需求抽象成一個對象,然后針對這個對象分析其特征(屬性)與動作(方法)。而這個對象我們就稱之為

封裝

在javascript中創建一個類很容易,首先按聲明一個函數,保存在一個變量中,按照編程的習慣,我們一般將類的名字的首字母大寫。然后在這個函數(類)的內部通過this(函數內部自帶的一個變量,用於指向當前這個對象)變量添加屬性或者方法來實現,對類添加屬性和方法。例如:

var Book = function(id, bookname, price) {
    this.id = id;
    this.bookname = bookname;
    this.price = price;
}

也可以通過類的原型(類也是對象,所i也有原型prototype)上田間屬性都和方法。添加屬性和方法的方式有兩種

  • 一種是意義為原型對象屬性賦值。
  • 另一種是將一個對象賦值給類的原型對象。
Book.prototype.display = function() {
        // 展示這本書
    };
    或者
    Book.prototype = {
        display: function() {
            
        }
    }

注意:

這兩種方式不能混用。

我們將所需要的方法和屬性都封裝在我們抽象的Book類里面,當使用功能方法的時候,就不能直接使用這個Book類,需要使用 new關鍵字,來實例化(創建)新的對象。實例化后便可通過點語法來訪問實例化對象的屬性和方法。

var book = new Book(1, 'xxx', 50);
    console.log(book.bookname);

問題:通過this添加的屬性和方法,和在prototype中添加的屬性和方法有什么區別那?

通過this添加的屬性和方法是在當前對象上添加的。然后js是一種基於原型prototype的語言,所以創建一個對象的時候,它都有一個原型對象prototype用於指向其繼承的屬性、方法。這樣通過prtotype繼承的方法並不是對象自身的。所以使用這些方法的時候,需要通過prototype一級一級查找來得到。當我們創建新的對象的時候,這些方法是不會再創建的。

而this創建是屬於對象自身的。我們創建對象的時候,相當於執行了一個類,因此類里面的方法肯定會復制一份。


我的理解:

prototye是每創建一個對象,這個對象都有一個prototype執行對象的原型,也就是實例化這個對象的那個類。因此所有通過prototype創建的屬性或者方法,都是綁定在類上的。

this是對象內部的,指向對象自己。因此通過this創建的方法,都是綁定在對象上的,都在對象內部,加之我們創建對象的時候。new xxx();相當於執行了這個類,創建一個新的對象,那對象的屬性和方法,也會被重新復制一份。


所以每實例化一個對象,都相當於創造出了一個新的對象(類也屬於對象),屬於自身的東西肯定會帶走,雖然實例化了類,但是類本身還存在的,通過這個類實例化的對象的原型都是指向這個類的。原型上屬於類的方法是實例化不走的。因此實例化的時候,原型上的方法是不會被復制的。

但是,因為他們的原型對象都執行同一個類,因此通過this是可以直接調到這些通過prototype創建的屬性和方法的。這里通過this調用prototype綁定的方式的流程是一級一級的查找得到的,怎么說那,對象要調用,手的的找到它原型的類吧,然后再調類上的方法吧,至少的這樣一級級的找吧。

屬性與方法的封裝

這里可以以一個例子來深入理解:

比如一個明星,為了再社會中保持一個良好的形象。它就會將一些隱私藏在心里。然后談的家人人事它,所以會了解一些關於她的事情。外界人不認識她,即使外界人想通過某種途徑認識她,也僅僅裂解她暴露出來的事情,不回來接他的隱私。

如果想了解更多關於他的事情怎么辦?

我們可以通過她的家人了解她。但是在明星深處自己內心深處的隱私永遠不會被別人知道。

在javascript中的實現

聲明在函數內部的變量和方法,函數外是訪問不到的。通過這個特性我們可以創建私有變量和私有方法。

然后通過this創建的屬性和方法,在類創建對象的時候,每個對象自身都會擁有一份,並且這些可以在外部訪問到的。因此通過this創建的屬性和方法便是共有屬性和共有方法。

注意:

1、通過this創建的方法,不但可以訪問這些對象的共有方法和共有屬性,而且還能訪問類或對象的私有屬性和私有方法,因此我們也就這種方法為特權方法。

2、我們可以通過特權方法初始化實例對象的一些屬性,因此這些在創建對象時調用的特權方法還可以看作是類的 構造器

var Book = function(id, bookname, price) {
        // 私有屬性
        var num = 1;
        // 私有方法
        function checkId() {
            
        };
        // 特權方法
        this.getName = function() {};
        this.getPrice = function() {};
        this.setName = function() {};
        this.setPrice = function() {};
        // 共有屬性
        this.id = id;
        // 共有方法
        this.copy = function() {};
        
        // 構造器
        this.setName(name);
        this.setPrice(price);
    }


創建對象的安全模式

剛學習對象編程的時候,經常在創建對象的時候忘記使用關關鍵字 new。如果忘記寫了,那有沒辦法處理這種情況,做到即使內使用new也能正確實例化對象?

有找個檢察長

var Book = function(id, bookname, price) {
        this.id = id;
        this.bookname = bookname;
        this.price = price;
    }
    
    // 實例化一本書
    var book = Book(1, "xxx", 50);
    
    console.log(book);


這段代碼很容易讓人混淆,認為會打印出Book實例化的對象,但是結果卻是:

undefined


仔細看看發現少了一個 new


看看大神們的測試代碼:

console.log(window.id);
console.log(window.bookname);
console.log(window.price);


結果:

1
xxx
50


我們實例化對象的時候,new可以看作當前對象的this不停的賦值,然后例子中沒有new;所以就會直接執行這個函數,而這個函數是在全局作用域中執行的。所以在全局作用域中執行,那this肯定是指向當前對象。自然就是全局變量。而此時的全局變量就是window,所以添加的屬性,自然會被添加到window上。而代碼中的book變量將是獲取Book這個類執行的結果,由於Book類中么有return返回值。自然book就每東西獲取,所以結果是undefined(未定義)。

問題:那該怎么避免那?

開啟安全模式。

var Book = function(id, bookname, price) {
        // 判斷執行過程中 this 是否是當前這個對象,如果是說用使用了 new
        if(this instanceof Book) {
            this.id = id;
            this.bookname = bookname;
            this.price = price;
        }else {
            // 否則創建這個對象
            return new Book(1, "xxx", 50);
        }
        
        
    }


測試:

// 實例化一本書
var book = Book(1, "xxx", 50);
console.log(book.id);
console.log(book.bookname);
console.log(book.price);

console.log(window.id);
console.log(window.bookname);
console.log(window.price);


結果:

1
xxx
50
undefined
undefined
undefined


這樣就不擔心少些 new,導致出錯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM