[TOC]
>[success] # Javascript 面向對象編程(一):封裝
在寫之前先發一下參考大佬阮一峰的文章地址 [Javascript 面向對象編程(一):封裝](http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html) 因為是參考大佬的案例總結知識嘛。
>[success] ## 一、 生成實例對象的原始模式
那么什么是實例對象? 實例和對象的區別,從定義上來講:
* 1、實例是類的具象化產品,(例如貓是一個種類)
* 2、而對象是一個具有多種屬性的內容結構(貓有名字、顏色、大小,這些都是貓的屬性)
~~~
假定我們把貓看成一個對象,它有"名字"和"顏色"兩個屬性。
var Cat = {
name : '',
color : ''
}
但是我現在如果有2個貓就要寫成這樣的:
var cat1 = {}; // 創建一個空對象
cat1.name = "大毛"; // 按照原型對象的屬性賦值
cat1.color = "黃色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
~~~
<br/>
>[success] ## 二、 原始模式的改進
那么如果有100個貓我豈不是累死了,要寫100個對象? 不那樣太傻了于是做了一些改進如下,這種方法的問題依然是,'cat1'和'cat2'之間沒有內在的聯系,不能反映出它們是同一個原型對象的實例。
~~~
// 封裝一個函數這樣就可以有好多貓
function Cat(name,color) {
return {
name:name,
color:color
}
}
調用這樣寫:
var cat1 = Cat("大毛","黃色");
var cat2 = Cat("二毛","黑色");
~~~
<br/>
>[success] ## 三、 構造函數模式
為了解決從原型對象生成實例的問題,Javascript提供了一個構造函數(Constructor)模式。
所謂"構造函數",其實就是一個普通函數,但是內部使用了[`this`變量](http://www.ruanyifeng.com/blog/2010/04/using_this_keyword_in_javascript.html)。對構造函數使用`new`運算符,就能生成實例,并且`this`變量會綁定在實例對象上。
~~~
比如,貓的原型對象現在可以這樣寫:
// 這個就是構造函數
function Cat(name,color){
this.name=name;
this.color=color;
this.age = "1"
}
然后頁面中調用這個實例對象這么寫:
var cat1 = new Cat("大毛","黃色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黃色
這個new Cat()的寫法我的理解,就是深拷貝下來這個Cat構造函數中的屬性值,如果cat1修改了Cat構造函數中的屬性值cat2不會受到
影響例如:
var cat1 = new Cat("大毛","黃色")
var cat2 = new Cat("二毛","黑色");
cat1.age = "2" // "2"
cat2.age // "1"
這時'cat1'和'cat2'會自動含有一個'constructor'屬性,指向它們的構造函數。
alert(cat1.constructor == Cat); // true
alert(cat2.constructor == Cat); // true
alert(cat1.constructor == cat2.constructor) // true
Javascript還提供了一個'instanceof'運算符,驗證原型對象與實例對象之間的關系。
alert(cat1 instanceof Cat); //true
alert(cat2 instanceof Cat); //true
~~~
<br/>
>[success] ## 四、構造函數模式的問題
~~~
構造函數方法很好用,但是存在一個浪費內存的問題。
請看,我們現在為'Cat'對象添加一個不變的屬性'Cat'(種類),再添加一個方法'eat'(吃)。那么,原型對象'Cat'就變成了下面
這樣:
function Cat(name,color){
this.name = name;
this.color = color;
this.type = "貓科動物";
this.eat = function(){alert("吃老鼠");};
}
表面上好像沒什么問題,但是實際上這樣做,有一個很大的弊端。那就是對于每一個實例對象,'type'屬性和'eat()'方法都是一模一樣
的內容,每一次生成一個實例,都必須為重復的內容,多占用一些內存。這樣既不環保,也缺乏效率。
alert(cat1.eat == cat2.eat); // false
能不能讓'type'屬性和'eat()'方法在內存中只生成一次,然后所有實例都指向那個內存地址呢?回答是可以的。
~~~
<br/>
>[success] ## 五、 Prototype模式
~~~
Javascript規定,每一個構造函數都有一個'prototype'屬性,指向另一個對象。這個對象的所有屬性和方法,都會被構造函數的實例
繼承。這意味著,我們可以把那些'不變的屬性和方法',直接定義在'prototype'對象上。
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "貓科動物";
Cat.prototype.eat = function(){alert("吃老鼠")};
然后,生成實例。
var cat1 = new Cat("大毛","黃色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 貓科動物
cat1.eat(); // 吃老鼠
這時所有實例的'type'屬性和'eat()'方法,其實都是同一個內存地址,指向'prototype'對象,因此就提高了運行效率。
alert(cat1.eat == cat2.eat); //true
~~~
<br/>
>[success] ## 六、 Prototype模式的驗證方法
~~~
為了配合'prototype'屬性,Javascript定義了一些輔助方法,幫助我們使用它
6.1 isPrototypeOf()
這個方法用來判斷,某個'proptotype'對象和某個實例之間的關系。
alert(Cat.prototype.isPrototypeOf(cat1)); //true
alert(Cat.prototype.isPrototypeOf(cat2)); //true
6.2 hasOwnProperty()
每個實例對象都有一個'hasOwnProperty()'方法,用來判斷某一個屬性到底是本地屬性,還是繼承自'prototype'對象的屬性。
alert(cat1.hasOwnProperty("name")); // true
alert(cat1.hasOwnProperty("type")); // false
6.3 in運算符
'in'運算符可以用來判斷,某個實例是否含有某個屬性,不管是不是本地屬性。
alert("name" in cat1); // true
alert("type" in cat1); // true
'in'運算符還可以用來遍歷某個對象的所有屬性。
for(var prop in cat1) { alert("cat1\["+prop+"\]="+cat1\[prop\]); }
~~~
- Javascript基礎篇
- Array數組
- 數組插入值
- filter()
- forEach()
- push()
- pop()
- unshift()
- shift()
- valueOf()
- 面向對象思想
- Javascript 面向對象編程(一):封裝
- Javascript面向對象編程(二):構造函數的繼承
- Javascript面向對象編程(三):非構造函數的繼承
- 解構
- 數組的解構賦值
- 對象的解構賦值
- 函數參數解構
- 字符串的解構賦值
- 數值和布爾值的解構賦值
- 圓括號問題
- 字符串.
- split()
- charAt()
- charCodeAt()
- concat()
- indexOf()
- lastIndexOf()
- match()
- replace()
- includes()
- 初識遞歸
- 渲染ul-li樹形結構
- 異步函數解決方案
- 1. callback回調函數
- 2. ES6 - Promise
- JavaScript高級程序設計(書)
- 在html中使用JavaScript
- script標簽的位置
- 延遲腳本
- 異步腳本
- <noscript>元素
- 基本概念
- 嚴格模式
- 變量詳解
- 數據類型
- typeof操作符
- undefined類型
- Null類型
- Boolean類型
- Number類型
- 深入了解ES6(書)
- var 、let 、 const
- 字符串與正則表達式
- 字符串
- 正則表達式
- 函數
- 函數形參默認值
- 使用不具名參數
- 函數構造器的增強能力
- 擴展運算符
- name屬性
- 明確函數的多重用途
- 塊級函數
- 箭頭函數
- 尾調用優化
- 擴展的對象功能
- 對象類別
- 對象字面量語法的擴展
- ES6對象新增方法
- 重復的對象屬性
- 自有屬性的枚舉順序
- 更強大的原型
- 解構:更方便的數據訪問
- 為什么要用解構?
- 對象解構
- 數組解構
- 混合解構
- 參數解構
- Symbol與Symbol屬性
- 創建Symbol
- Symbol的使用方法
- Symbol全局私有屬性
- Symbol與類型強制轉換
- Symbol屬性檢索
- Symbol的一些構造方法
- Set集合與Map集合
- Set集合
- Weak Set集合(弱引用Set集合)
- Map集合
- JS標準內置對象
- Object 構造函數及屬性
- Object 構造方法
- Symbol 內建對象類的函數及屬性
- Set 構造函數及屬性
- Weak Set 構造函數及屬性
- JS雜項
- 類數組對象
- Class類的理解和使用