面向對象是軟件開發方法。面向對象的概念和應用已超越了程序設計和軟件開發,擴展到如數據庫系統、交互式界面、應用結構、應用平臺、分佈式系統、網絡管理結構、CAD技術、人工智能等領域。面向對象是一種對現實世界理解和抽象的方法,是計算機編程技術發展到必定階段後的產物。
JavaScript的面向對象主要包含了兩塊:1)建立對象 2)繼承。接下來,咱們將走進JS對象的世界,將依次帶你深刻了解函數、閉包、原型、原型鏈,並經過它們,最終實現建立對象和繼承。數據庫
若是如今有一個純牛奶,那麼咱們建立對象能夠這樣操做:編程
var milk ={ name:'純牛奶', taste:'pure', price:4 }
那麼若是如今有4種不一樣口味的牛奶呢?也建立四個不一樣的對象嗎?milk一、milk二、milk三、milk4?如有一萬種呢,是否也建立一萬個對象?
顯然,這是不合理的。這裏,咱們就要引入一個概念——工廠模式。segmentfault
function createMilk(name,taste,price){ return { name:name, taste:taste, price:price } } var milk1 = createMilk('純牛奶','pure',4); var milk2 = createMilk('有機奶','organic',4); var milk3 = createMilk('低脂奶','low-fat',4);
在這裏,咱們實用一個函數,傳入產品名、口味、價格3個參數,返回一個對象。這樣,咱們只要調用這個函數,並傳入不一樣的參數,便可構建不一樣的對象。這就是工廠模式。網絡
工廠模式有優勢也有缺點:
1)優勢:簡單易懂、常見且實用。
2)缺點:對於如何證實我是一個牛奶這個問題上,則沒法證實。//這句如若沒法理解的話,能夠暫時忽略,繼續往下看哦!閉包
爲了更好的講解構造函數、原型、原型鏈等,建議你複習一下函數的一些基礎知識,若是你已經對函數有深刻的瞭解,能夠選擇跳過。戳這裏:JS函數的一些基礎知識分佈式
還記得咱們以前在講述工廠模式的缺點時,所說的那句「對於如何證實我是一個牛奶這個問題上,則沒法證實。」嗎?接下來,就是見證奇蹟的時刻!函數
var obj = new Object(); var add = new Function('a','b','return a+b'); console.log(obj instanceof Object);//true console.log(add instanceof Function);//true
Object和Function都是原生的構造函數,在這裏咱們就可使用instanceof來判斷是否爲它的一個實例——即:證實了我就是一個牛奶哦!!學習
既然有原生的構造函數,那麼咱們能夠不能夠也本身定義構造函數呢?答案是能夠的。this
通常來講,咱們能夠這樣定義構造函數:人工智能
//構造函數的函數名常大寫 //在這裏,咱們沒有顯示的建立對象,沒有return語句,卻將屬性和方法賦值給了this。 function Milk(name,taste,price){ this.name = name; this.taste = taste; this.price = price; } //new操做符會默認的建立一個新對象,將function的this指向對象,而後將該對象賦值,對象就有了三個屬性。 var milk1 = new Milk('純牛奶','pure',4); console.log(milk1 instanceof Milk);//true
function Milk(name,taste,price){ this.name = name; this.taste = taste; this.price = price; this.say = function(){ console.log('Hello World'); }; } var milk1 = new Milk('純牛奶','pure',4); var milk2 = new Milk('純牛奶','pure',4);
假設咱們建立了一個Milk的構造函數,裏面除了屬性還帶有一個say的方法,當咱們new了兩個對象以後,兩個對象milk1和milk2是否都包含了功能相同的say方法呢?
這就是構造函數的不足之處:功能相同的函數,重複聲明消耗空間!看來,咱們的路尚未走到終點。
原型是函數的一個屬性,是一個對象。若是函數做爲構造函數使用,那麼這個構造函數的全部實例,都共享這個原型對象。
「注」以前咱們回憶函數時,回憶到,函數有三個常見屬性:name,length和prototype喔!若是遺忘,能夠戳這裏:JS函數的一些基礎知識!
1)constructor
原型的constructor是一個對象,咱們能夠這樣簡單的驗證一下:
Object.prototype.constructor === Object //true
2)讀寫
function Milk() {} Milk.prototype.name = '純牛奶'; Milk.prototype.taste = 'pure'; Milk.prototype.price = 4; Milk.prototype.say = function(){ console.log('Hello World'); }; var milk1 = new Milk();
運行的結果以下:
經過這種方式,能夠解決內存問題。但也會所以而共享name,taste,price和say(),尤爲是共享name,taste和price,會產生問題。
3)isPrototypeOf
咱們能夠經過isPrototypeOf來進行原型的斷定,以下:
function Milk() {} Milk.prototype.name = '純牛奶'; Milk.prototype.taste = 'pure'; Milk.prototype.price = 4; Milk.prototype.say = function(){ console.log('Hello World'); }; var milk1 = new Milk(); console.log(Milk.prototype.isPrototypeOf(milk1));//true
原型是函數的一個屬性,是一個對象。若是函數做爲構造函數使用,那麼這個構造函數的全部實例,都共享這個原型對象。
原型的不足,本質上是共享的缺陷。咱們能夠看以下一段代碼:
var price = 10; var priceCopy = price; priceCopy = 20; console.log(price,priceCopy);//10,20
咱們再看以下一段代碼:
var taste = ['pure','organic']; var tasteCopy = taste; tasteCopy.push('low fat'); console.log(taste,tasteCopy);//["pure", "organic", "low fat"],["pure", "organic", "low fat"]
由此咱們可見:
共享會污染數據類型,所以原型建立對象也會污染數據類型。咱們看下面一段代碼:
function Milk(){} Milk.prototype.taste = ['pure','organic']; var m1 = new Milk(); var m2 = new Milk(); m2.taste.push('low fat'); console.log('m1',m1.taste);//["pure", "organic", "low fat"] console.log('m2',m2.taste);//["pure", "organic", "low fat"]
經過這段代碼,咱們能夠清楚的瞭解到原型建立對象主要的不足具體表如今:
構造函數有必定的優缺點,原型也有必定的優缺點,若是咱們把二者優勢結合,將會是一種不錯的建立對象的方式。咱們看以下的代碼:
function Milk(name,taste,price){//構造函數獨享屬性 this.name = name; this.taste = taste; this.price = price; } Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); m1.say();//純牛奶
在這段代碼中,咱們使用構造函數來獨享屬性,以免原型建立對象會產生的共享問題,固然,咱們也使用原型共享方法,從而達到拒絕功能相同的函數致使的重複聲明消耗空間問題。
在學習來構造函數結合原型建立對象的基礎之上,咱們來關心一些細節性的問題,以便於咱們深刻了解構造函數結合原型。如,構造函數和原型上的屬性是否會覆蓋,優先順序又是什麼?再如,如何判斷屬性是在原型上仍是在構造函數之上呢?
1)屬性的覆蓋
咱們經過以下兩段代碼,總結關於構造函數結合原型的屬性覆蓋:
//1 function Milk(name,taste,price){//構造函數獨享屬性 this.name = name; this.taste = taste; this.price = price; } Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log(m1.name);//純牛奶
//2 function Milk(name,taste,price){//構造函數獨享屬性 //this.name = name; this.taste = taste; this.price = price; } Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log(m1.name);//牛奶
從兩端代碼中,咱們對比得知,實例上的屬性會覆蓋原型上的屬性。即:會先在實例中查找,如沒有,則再在原型上查找。
2)屬性的判斷
(1)in操做符
咱們能夠經過以下三段代碼,總結關於in操做符的知識,即:只要對象裏有值,即不管是在構造函數之上仍是在原型之上均返回true,若都不在,則返回false。
//1 function Milk(name,taste,price){//構造函數獨享屬性 this.name = name; this.taste = taste; this.price = price; } Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log('name' in m1);//ture
//2 function Milk(name,taste,price){//構造函數獨享屬性 //this.name = name; this.taste = taste; this.price = price; } Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log('name' in m1);//ture
//3 function Milk(name,taste,price){//構造函數獨享屬性 //this.name = name; this.taste = taste; this.price = price; } //Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log('name' in m1);//false
(2)hasOwnProperty
咱們能夠經過以下兩段代碼,總結關於in操做符的知識,即:判斷是在實例上仍是原型上,掛在實例上返回true,反之false。
//1 function Milk(name,taste,price){//構造函數獨享屬性 this.name = name; this.taste = taste; this.price = price; } //Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log(m1.hasOwnProperty('name'));//true
//2 function Milk(name,taste,price){//構造函數獨享屬性 //this.name = name; this.taste = taste; this.price = price; } Milk.prototype.name = '牛奶'; Milk.prototype.say = function(){//原型共享方法 console.log(this.name); } var m1 = new Milk('純牛奶','pure','4'); console.log(m1.hasOwnProperty('name'));//false
在建立對象這個板塊中,咱們從工廠模式開始講起,再到構造函數,接着到原型,最後到比較完善的構造函數結合原型,在接下來的繼承板塊中,咱們將講述原型鏈、繼承以及最佳方式的相關知識,好好複習!
固然,最最最最最後,若是您喜歡這片文章,能夠瘋狂點贊或者收藏喔!!?