一、理解對象
??? 1.創建
??????? ①構造函數?? new Object
??????? ②對象字面量? var o = {};
??? 2.屬性類型
??????? ①數據屬性,對象屬性有4個屬性特征,默認都為true,可以通過Object.defineProperty()來修改屬性特征
??????????? a.[[Configurable]]? 表示能否通過delete刪除重新定義,能否修改屬性的特征,能否修改為訪問權屬性
??????????? b.[[Enumerable]]??? 表示能否通過for-in枚舉
??????????? c.[[Writable]]????? 表示能否修改屬性的值
??????????? d.[[Value]]???????? 表示屬性值
??????????? eg:
??????????????? var o = {
??????????????????? name : [1, 2, 3]
??????????????? }
??????????????? Object.defineProperty(o, "name", {
??????????????????? configurable : false,?????? // 不能delete,不能修改,不能設置為訪問器屬性
??????????????????? enumerable : false,???????? // 不能枚舉
??????????????????? writable :? false,????????? // 不能修改
??????????????????? value :???? [100, 200]????? // 把值變成[100, 200]
??????????????? });
??????????????? // for(var v in o.name) {
??????????????????? // alert(o.name[v]); // 100, 200, 能枚舉
??????????????? // }
??????????????? alert(o.propertyIsEnumerable("name"));????? // false
??????????????? // o.name = "li";
??????????????? // alert(o.name); // 100, 200 不能修改
??????????????? // delete o.name;
??????????????? // alert(o.name); // 100, 200 不能刪除
??????? ②訪問器屬性,4個訪問器屬性特征,可以通過Object.defineProperty()來修改屬性特征
??????????? a.[[Configurable]]? 表示能否通過delete刪除重新定義,能否修改屬性的特征,能否修改為訪問權屬性
??????????? b.[[Enumerable]]??? 表示能否通過for-in枚舉
??????????? c.[[Get]]?????????? 表示在讀取屬性時調用的函數,默認為undefined
??????????? d.[[Set]]?????????? 表示在設置屬性時調用的函數,默認為undefined
??????????? eg:
??????????????? var o = {
??????????????????? name : [1, 2, 3]
??????????????? }
??????????????? Object.defineProperty(o, "name", {
??????????????????? get : function () {
??????????????????????? alert("get");
??????????????????? },
??????????????????? set : function() {
??????????????????????? alert("set");
??????????????????? }
??????????????? });
??????????????? o.name = "li";????? // set,設置name值時,自動調用o.set()
??????????????? o.name;???????????? // get,讀取name時,自動調用o.get()
??????? ③定義多個屬性 Object.defineProperties()來同時定義多個屬性
??????????? eg:
??????????????? var o = {}
??????????????? Object.defineProperties(o, {
??????????????????? name : {
??????????????????????? configurable : false,
??????????????????????? value : "zhang"
??????????????????? },
??????????????????? age : {
??????????????????????? get : function () {
??????????????????????????? alert("get");
??????????????????????? },
??????????????????????? set : function() {
??????????????????????????? alert("set");
??????????????????????? }
??????????????????? }
??????????????? });
??????????????? alert(o.name);????????? // zhang
??????????????? o.age;????????????????? // get
??????????????? o.age = "li";?????????? // set
??????? ④讀取屬性的特征??? Object.getOwnPropertyDescriptor(objectName, propertyName)
??????????? eg:
??????????????? var o = {}
??????????????? Object.defineProperties(o, {
??????????????????? age : {
??????????????????????? get : function () {
??????????????????????????? alert("get");
??????????????????????? },
??????????????????????? set : function() {
??????????????????????????? alert("set");
??????????????????????? }
??????????????????? }
??????????????? });
??????????????? var descriptor = Object.getOwnPropertyDescriptor(o, "age");
??????????????? for(var v in descriptor) {
??????????????????? alert(v + " = " + descriptor[v]);?????? // 彈出訪問器屬性的4個屬性特征
??????????????? }
二、創建對象
??? 1.工廠模式?????????
??????? ①抽象了創建對象的具體過程
??????????? eg:
??????????????? function createObject (name, age) {
??????????????? var object = new Object();
??????????????? object.name = name;
??????????????? object.age = age;
??????????????? object.sayName = function () {
??????????????????? return object.name;
??????????????? }
??????????????? return object;
??????????? }
??????????? var p1 = createObject("zhang", 23);
??????????? var p2 = createObject("li", 33);
??????????? alert(p1.sayName());??????? // zhang
??????????? alert(p2.sayName());??????? // li
??????????? // 無法識別p1和p2
??????????? alert(p1);????????????????? // [object Object]
??????????? alert(p2);????????????????? // [object Object]
??????? ②弊端???? 沒有解決對象識別的問題
??????? ③解決方法?? 構造函數模型
??? 2.構造函數模式
??????? ①創建模式
??????????? eg:
??????????????? function Person(name, age) {
??????????????????? this.name = name;
??????????????????? this.age = age;
??????????????????? this.getName = function () {
??????????????????????? return this.name;
??????????????????? }
??????????????? }
??????????????? var p1 = new Person("zhang", 34);
??????????????? var p2 = new Person("li", 23);
??????????????? alert(p1.getName());??????? // zhang
??????????????? alert(p2.getName());??????? // li
??????????????? alert(p1 instanceof Person);??????? // true
??????????????? alert(p2 instanceof Person);??????? // true, 解決了工廠模式的對象識別問題
??????? ②問題 每個方法都要在每個實例上創建一遍,從而形成不同的作用域鏈,從而導致不相同
??????????? eg: alert(p1.getName == p2.getName);??????? // false
??????????? 我們也可以將方法部分提取到構造函數之外,但這樣就沒有什么封裝性可言了。
??????????? eg:
??????????????? function Person(name, age) {
??????????????????? this.name = name;
??????????????????? this.age = age;
??????????????????? this.getName = getName;
??????????????? }
??????????????? function getName () {
??????????????????? return this.name;
??????????????? }
??????? ③解決方法?? 原型模型
??? 3.原型模式
??????? ①創建模式?? 原型對象(構造函數的prototype屬性指向它)的好處:可以讓所有對象實例共享它包含屬性和方法
??????????? eg:
??????????????? function Person(name, age) {
??????????????????? this.name = name;
??????????????????? this.age = age;
??????????????? }
??????????????? Person.prototype.getName = function () {
??????????????????? return this.name;
??????????????? }
??????????????? var p1 = new Person("zhang", 34);
??????????????? var p2 = new Person("li", 23);
??????????????? alert(p1.getName == p2.getName);??? // true,解決了方法共享的問題
??????? ②理解原型??
??????????????? a.函數Person.prototype指向原型
??????????????? b.Person.prototype.constructor指回構造函數
??????????????? c.p1、p2的prototype指向原型,且可調用原型中的方法,用Person.prototype.isPrototypeOf(p1)判斷,也可以用Object.getPrototypeOf(p1)來獲取原型
??????????????? d.我們可以用原型訪問屬性的值,但是不能通過實例重寫原型的值,因為對象實例的值會屏蔽原型屬性的值。當我們用實例對象重寫了原型中的值,只有刪除實例對象的值,才能訪問原型屬性的值。
??????????????? e.同樣我們可以通過[實例.hasOwnProperty(propertyName)]來檢測實例是否定義了自己的屬性值
??????????????????? eg:
??????????????????????? function Person() {}
??????????????????????? Person.prototype.name = "zhang";
??????????????????????? Person.prototype.getName = function () {
??????????????????????????? return this.name;
??????????????????????? }
??????????????????????? var p1 = new Person();
??????????????????????? alert(p1.name);???? // zhang
??????????????????????? p1.name = "li";
??????????????????????? alert(p1.name);???? // li,實例中的值覆蓋了原型中的值
??????????????????????? alert(p1.hasOwnProperty("name"));?? // 判斷實例p1是否定義了自己的屬性name的值,true
??????????????????????? delete p1.name;???? // 刪除實例對象中的屬性值
??????????????????????? alert(p1.name);???? // zhang
??????? ③原型與in操作符??????
??????????? a.無論是屬性值存在于原型中,還是實例對象中都返回true
??????????????? eg:
??????????????????? function Person() {}
??????????????????? Person.prototype.name = "zhang";
??????????????????? Person.prototype.getName = function () {
??????????????????????? return this.name;
??????????????????? }
??????????????????? // 判斷是否為原型中的屬性
??????????????????? function hasPrototypeProperty(object, propertyName) {
??????????????????????? return propertyName in object && !object.hasOwnProperty(propertyName);
??????????????????? }
??????????????????? var p1 = new Person();
??????????????????? p1.name = "li";
??????????????????? alert(hasPrototypeProperty(p1, "name"));??? // false
??????????????????? delete p1.name;
??????????????????? alert(hasPrototypeProperty(p1, "name"));??? // true
??????????? b.枚舉所有可枚舉的屬性和方法,用Object.key(原型/實例)
??????????????? eg:
??????????????????? function Person() {}
??????????????????? Person.prototype.name = "zhang";
??????????????????? Person.prototype.age = 11;
??????????????????? Person.prototype.getName = function () {
??????????????????????? return this.name;
??????????????????? }
??????????????????? alert(Object.keys(Person.prototype));?? // 枚舉原型中的屬性和方法
??????????????????? var p1 = new Person();
??????????????????? p1.name = "li";
??????????????????? p1.getName = function () {}???????????? // 枚舉實例對象中的屬性和方法
??????????????????? alert(Object.keys(p1));
??????????? c.枚舉所有的屬性和方法,無論是否隱藏,用hasOwnPropertyNames(原型);
??????????????? eg: alert(Object.getOwnPropertyNames(Person));? // prototype,length,name
??????? ④更簡單的原型方法
??????????? a.源碼
??????????? eg: function Person() {}
??????????????? Person.prototype = {
??????????????????? constructor : Person,
??????????????????? name : "zhang",
??????????????????? getName : function () {}
??????????????? }
??????????? b.問題??? 這樣做可能會導致原型中的constructor屬性的[Enumerable]為true,默認為false
??????????? c.解決方法? 用Object.defineProperty()方法重新定義
??????????????? eg: Object.defineProperty(Person.prototype, constructor, { enumerable : false});
??????????? e.實例化對象一定要后于對象的定義完畢
??????? ⑤原型對象的問題??????? 共享性,針對方法很好,針對屬性也說的過去,但是針對那些包含了引用類型則不可
??????????? eg:
??????????????? function Person() {}
??????????????? Person.prototype = {
??????????????????? constructor : Person,
??????????????????? friends : [1, 2]??????? // 引用類型
??????????????? }
??????????????? var p1 = new Person();
??????????????? var p2 = new Person();
??????????????? p1.friends.push(3);
??????????????? alert(p1.friends);
??????????????? alert(p2.friends);????? // 同時返回1,2,3
??????? ⑥解決方法?? 取長補短,用構造函數模式定義屬性,用原型模式定義方法
??? 3.組合構造模式和原型模式
??????? ①模式 取長補短,用構造函數模式定義屬性,用原型模式定義方法
??????? eg:
??????????? function Person(name) {
??????????????? this.name = name;
??????????????? this.friends = [1, 2]?????? // 引用類型
??????????? }
??????????? Person.prototype = {
??????????????? constructor : Person,
??????????????? name : "zhang",
??????????? }
??????????? var p1 = new Person("li");
??????????? var p2 = new Person("wang");
??????????? p1.friends.push(3);
??????????? alert(p1.friends);????? // 1,2,3
??????????? alert(p2.friends);????? // 1,2
??????? ②小問題??????? 感覺構造函數和原型分離,破壞了封裝性
??????? ③解決方法?? 使用動態原型模式
??? 4.動態原型模式(基本完美)????? 將原型中方法封裝到構造函數中去
??????? eg:
??????????? function Person(name) {
??????????????? this.name = name;
??????????????? this.friends = [1, 2];????? // 引用類型
??????????????? if (typeof this.getName != "function") {
??????????????????? Person.prototype.getName = {
??????????????????????? return this.name;
??????????????????? }
??????????????? }
??????????? }
??? 5.寄生構造模式
??????? ①基本思想:創建一個函數(對象),該函數用來封裝代碼,然后返回函數(對象)
??????? ②模式
??????????? eg:
??????????????? function Person(name, age) {
??????????????????? var o = new Object();
??????????????????? o.name = name;
??????????????????? o.age = age;
??????????????????? o.getName = function () {
??????????????????????? return o.name;
??????????????????? };
??????????????????? return o;
??????????????? }
??????????????? var p1 = new Person("zhang", 34);
??????????????? alert(p1.getName());??????? // zhang
??????????????? alert(p1 instanceof Person);// false
??????? ③問題:由于實例對象和構造函數完全分離,因此無法識別對象
??????? ④案例:對于Array類型,我們可能在特殊情況在,對它進行添加屬性和方法
??????????? eg:
??????????????? function NewArray() {
??????????????????? var array = new Array();
??????????????????? array.push.apply(array, arguments);
??????????????????? array.addFun = function () {
??????????????????????? return this.join("|");
??????????????????? }
??????????????????? return array;
??????????????? }
??????????????? var a1 = new NewArray("zhang", 22);
??????????????? alert(a1.addFun());???? // zhang|22
??? 6.穩妥構造函數模型????? 沒有公共屬性,不使用this和new,只能定義獲取值的方法
??????? ①用途:安全性
??????? ②源碼
??????????? eg:
??????????????? function Person(name, age) {
??????????????????? var o = new Object();
??????????????????? o.getName = function () {
??????????????????????? return name;
??????????????????? }
??????????????????? return o;
??????????????? }
??????????????? var p = Person("zhang", 3);
??????????????? p.name = 'li';????????? // 無效
??????????????? alert(p.getName());???? // zhang
??????? ③特點 函數名首字母大寫、對象里只定義方法且不用this、實例化時不用new
??????? ④問題:由于實例對象和構造函數完全分離,因此無法識別對象
三、繼承
??? 1.原型鏈
??????? ①將父類的實例賦值給子類的原型。因為父類的實例指向父類的原型,因此子類的原型也指向父類的原型。
??????? ②基本源碼:
??????????? eg:
??????????????? function SuperType(){
??????????????????? this.property = true;
??????????????? }
??????????????? SuperType.prototype.getSuperValue = function(){
??????????????????? return this.property;
??????????????? };
??????????????? function SubType(){
??????????????????? this.subproperty = false;
??????????????? }
??????????????? //繼承了SuperType
??????????????? SubType.prototype = new SuperType();??? // 將父類的實例賦值給子類的原型
??????????????? SubType.prototype.getSubValue = function (){
??????????????????? return this.subproperty;
??????????????? };
??????????????? var instance = new SubType();
??????????????? alert(instance.getSuperValue()); //true,調用父類SuperType的方法getSuperValue()
??????? ③別忘記了父類同樣基礎了祖類Object
??????? ③確定原型和實例的關系 用instanceof和對象.isPrototypeOf(實例)
??????? ④在子類重新或者添加父類的方法時,必須要在父類定義之后
??????? ⑤原型鏈的問題 原型鏈中不能存在引用類型
??????????? eg:
??????????????? function SuperType(){
??????????????????? this.friends = [1,2];
??????????????? }
??????????????? function SubType(){}
??????????????? //繼承了SuperType
??????????????? SubType.prototype = new SuperType();
??????????????? var s1 = new SubType();
??????????????? var s2 = new SubType();
??????????????? s1.friends.push(3);
??????????????? alert(s1.friends);????? // 1, 2, 3
??????????????? alert(s2.friends);????? // 同上
??????? ⑥解決方法?? 借用構造函數
??? 2.借用構造函數??? 對于原型鏈中包含引用類型,我們可以在子類的構造函中調用父類的構造函數
??????? ①源碼案例, 即可以使用引用類型,還可以傳遞參數
??????? eg:
??????????? function SuperType(name){
??????????????? this.name = name;
??????????????? this.friends = [1,2];
??????????? }
??????????? function SubType(){
??????????????? SuperType.call(this, "abc");??????? // 傳遞參數
??????????? }
??????????? //繼承了SuperType
??????????? SubType.prototype = new SuperType();
??????????? var s1 = new SubType();
??????????? var s2 = new SubType();
??????????? s1.friends.push(3);
??????????? alert(s1.friends);????? // 1, 2, 3
??????????? alert(s2.friends);????? // 1, 2
??????????? alert(s1.name);???????? // abc
??????? ③問題 由于是在構造函數中定義,所以方法不能夠共享
??????? ④解決方法?? 組合繼承
??? 3.組合繼承(雖然兩次調用了父類,但是基本ok)
??????? ①基本思想?? 將借用構造和原型鏈結合起來,借用構造定義屬性,原型鏈定義方法
??????????? eg:
??????????????? function SuperType(name){
??????????????????? this.name = name;
??????????????????? this.friends = [1,2];
??????????????????? if (typeof this.getName != "function") {
??????????????????????? SuperType.prototype.getName = function () {
??????????????????????????? return this.name;
??????????????????????? }
??????????????????? }
??????????????? }
??????????????? function SubType(name, age){
??????????????????? SuperType.call(this, name);???????????? // 第二次調用父類
??????????????????? this.age = age;
??????????????????? if (typeof this.getAge != "function") {
??????????????????????? SuperType.prototype.getAge = function () {
??????????????????????????? return this.age;
??????????????????????? }
??????????????????? }??
??????????????? }
??????????????? //繼承了SuperType
??????????????? SubType.prototype = new SuperType();??????? // 第一次調用父類
??????????????? var s1 = new SubType("zhang", 23);
??????????????? var s2 = new SubType("li", 24);
??????????????? s1.friends.push(3);
??????????????? alert(s1.friends);????? // 1, 2, 3
??????????????? alert(s2.friends);????? // 1, 2
??????????????? alert(s1.getName());??? // zhang
??????????????? alert(s2.getAge());???? // 24
??? 4.原型式繼承
??????? ①基本思想?? 借助原型可以基于已有的對象創建新對象,從而不必自定義對象
??????????? eg:
??????????????? function object(o) {
??????????????????? function F() {};
??????????????????? F.prototype = o;
??????????????????? return new F();
??????????????? }
??????????????? var person = {
??????????????????? name : "zhang",
??????????????????? friends : [1, 2]
??????????????? }
??????????????? var p1 = object(person);
??????????????? p1.name = "li";
??????????????? p1.friends.push(3);
??????????????? alert(p1.name);???? // li
??????????????? alert(p1.friends);? // 1,2,3
??????????????? var p2 = object(person);
??????????????? p1.name = "wang";
??????????????? p1.friends.push(4);
??????????????? alert(p2.name);???? // wang
??????????????? alert(p2.friends);? // 1,2,3,4
??????? ②ECMAScript 5發展了道格拉斯·克羅克福德的原型鏈繼承,用Object.create()方法
??????????? eg: 其中第二個參數和defineProperty()方法一致
??????????????? var person = {
??????????????????? name : "zhang",
??????????????????? friends : [1, 2]
??????????????? }
??????????????? var p1 = Object.create(person, {
??????????????????? name : {
??????????????????????? value : "zhang"
??????????????????? }
??????????????? });
??????????????? p1.friends.push(3);
??????????????? alert(p1.name);???? // li
??????????????? alert(p1.friends);? // 1,2,3
??????????????? var p2 = Object.create(person, {
??????????????????? name : {
??????????????????????? value : "wang"
??????????????????? }
??????????????? });
??????????????? p1.friends.push(4);
??????????????? alert(p2.name);???? // wang
??????????????? alert(p2.friends);? // 1,2,3,4
??????? ③問題:??? 原型鏈共享問題,引用類型
??? 5.寄生式繼承
??????? ①思想 基于原型式繼承,創建一個新函數對象,添加新方法
??????? eg:
??????????? function object(o) {
??????????????? function F() {};
??????????????? F.prototype = o;
??????????????? return new F();
??????????? }
??????????? function createAnother(original) {
??????????????? // 繼承原來的對象原型
??????????????? var clone = object(original);
??????????????? // 添加新方法
??????????????? clone.newFun = function () {
??????????????????? return "new function";
??????????????? }
??????????????? return clone;
??????????? }
??????????? var person = {
??????????????? name : "zhang",
??????????????? friends : [1, 2]
??????????? }
??????????? var p = createAnother(person);
??????????? alert(p.name);????? // zhang
??????????? alert(p.newFun());? // new function
??????? ②問題 原型鏈共享問題,引用類型
??? 6.寄生組合式繼承
??????? ①思想 在組合繼承和原型式繼承的基礎上,不在子類的內部調用父類的構造函數,而是創建父類原型的副本
??????? eg:
??????????? function object(o) {
??????????????? function F() {};
??????????????? F.prototype = o;
??????????????? return new F();
??????????? }
??????????? function inheritPrototype(subType, superType) {
??????????????? // 賦值proto為superType的原型
??????????????? var proto = object(superType.prototype);
??????????????? // 原型的contructor屬性指向構造函數
??????????????? proto.contructor = subType;
??????????????? // superType的構造函數指向原型
??????????????? subType.prototype = proto;
??????????? }
??????????? function SuperType(name){
??????????????? this.name = name;
??????????????? this.friends = [1,2];
??????????????? if (typeof this.getName != "function") {
??????????????????? SuperType.prototype.getName = function () {
??????????????????????? return this.name;
??????????????????? }
??????????????? }
??????????? }
??????????? inheritPrototype(SubType, SuperType);
??????????? function SubType(name, age){
??????????????? SuperType.call(this, name);
??????????????? this.age = age;
??????????????? if (typeof this.getAge != "function") {
??????????????????? SuperType.prototype.getAge = function () {
??????????????????????? return this.age;
??????????????????? }
??????????????? }??
??????????? }
??????????? var s1 = new SubType("zhang", 23);
??????????? var s2 = new SubType("li", 24);
??????????? s1.friends.push(3);
??????????? alert(s1.friends);????? // 1, 2, 3
??????????? alert(s2.friends);????? // 1, 2
??????????? alert(s1.getName());??? // zhang
??????????? alert(s2.getAge());???? // 24
JavaScript面向對象設計
最后編輯于 :
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
推薦閱讀更多精彩內容
- Chapter 6 面向對象的程序設計 理解對象 使用對象字面量語法創建對象var person = { n...
- 1、構造函數模式 [url=]file:///C:/Users/i037145/AppData/Local/Tem...