摘要:構造函數用于檢測給定的屬性在當前對象實例中而不是原型中是否存在。返回對象的字符串表示。實現空函數的原型對象和超類的原型對象轉換原型繼承做善后處理。判斷父類的原型對象的構造器,防止簡單原型中給更改為還原父類原型對象的構造器
類的創建于實例對象 工廠模型創建對象
function CreatePerson ( name,sex,age ) { var obj = new Object(); obj.name = name; obj.sex = sex; obj.age = age; obj.sayName = function () { console.log( this.name ); } return obj; } var p1 = CreatePerson("zf","女",22); p1.sayName(); //zf console.log( p1.name ); //zf構造函數式
//函數的第一個字母大寫(類的模板) function Person ( name,age,sex ) { this.name = name; this.age = age; this.sex =sex; this.sayName = function () { alert(this.name); } } //構造一個對象, 使用new關鍵字, 傳遞參數, 執行模板代碼, 返回對象。 var p1 = new Person("zf",20,"女"); //類的概念:根據模板創建出不同的實例對象 console.log( p1.name ); p1.sayName();
創建類的實例:
當作構造函數去使用
var p1 = new Person("a1",20);
作為普通函數去調用
Person("a2",20); //在全局環境中定義屬性并賦值, 直接定義在window上。
在另個一對象的作用域中調用
var o = new Object();
Person.call(o,"a3",23);
Object每個實例都會具有的屬性和方法:
Constructor: 保存著用于創建當前對象的函數。(構造函數)
hasOwnProperty(propertyName):用于檢測給定的屬性在當前對象實例中(而不是原型中)是否存在。
isPrototypeOf(Object): 用于檢查傳入的對象是否是另外一個對象的原型。
propertyIsEnumerable(propertyName):用于檢查給定的屬性是否能夠使用for-in語句來枚舉。
toLocaleString():返回對象的字符串表示。該字符串與執行環境的地區對應.
toString():返回對象的字符串表示。
valueOf():返回對象的字符串、數值或布爾表示。
判斷一個對象是不是另一個對象的實例,通常使用的是 instanceof. 比較少使用constructor。
原型創建每一個函數的時候,都有一個prototype屬性. 這個是屬性,是一個指針。而這個對象總是指向一個對象。
這個對象 的用途就是將特定的屬性和方法包含在內,是一個實例對象, 起到了一個所有實例所共享的作用。
屏蔽了,構造函數的缺點,new 一個對象,就把構造函數內的方法實例化一次。
function Person () { } var obj = Person.prototype; console.log( obj ); //Person.prototype 就是一個對象 //Person.prototype 內部存在指針,指針指向一個對象。 這個對象稱之為:原型對象。原型對象,被所有的實例對象所共享。 console.log( obj.constructor ); //function Person(){} //obj這個對象的構造器就是 Person
原型圖例:
console.log(Person.prototype) 的結果:
根據實例對象獲得原型對象
每次代碼讀取一個對象的屬性的時候:首先會進行一次搜索,搜索實例對象里,看看是否存在,如果沒有,再去實例所對的原型中尋找屬性.如果有則返回,如果兩次都沒有則返回undefined
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } var p1 = new Person(); console.log( p1.name ); //z1 console.log( Object.getPrototypeOf(p1) ); console.log( Object.getPrototypeOf(p1) == Person.prototype ); //truehasOwnProperty()
判斷是否是 實例對象自己的屬性
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } // 判斷一個對象屬性 是屬于 原型屬性 還是屬性 實例屬性 var p3 = new Person(); console.log( p3.name ); //zf 是原型上的 //hasOwnProperty() 是否是 實例對象自己的屬性 console.log( p3.hasOwnProperty("name") ); //falsein 操作符
無論是 原型的屬性, 還是實例對象的屬性, 都區分不開。 如果存在,返回true
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } //判斷屬性是否存在 實例對象 和 原型對象中. var p1 = new Person(); console.log("name" in p1); //true //表示,name的屬性到底在不在p1的屬性中 true var p2 = new Person(); p1.name = "zzz"; console.log("name" in p1); //true
判斷一個屬性是否在原型中
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } //判斷屬性是否存在 實例對象 和 原型對象中. var p1 = new Person(); p1.name = "123"; //在原型對象中,是否存在這個值 //@obj 當前對象 //@判斷的屬性 function hasPrototypeProtoperty ( obj,attrName ) { return !obj.hasOwnProperty(attrName) && (attrName in obj); } console.log( hasPrototypeProtoperty(p1,"name") ); //falseObject.keys()
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } //ECMA5新特性 Object.keys(); //拿到當前對象中的所有keys, 返回一個數組 var p1 = new Person(); p1.name = "zz"; p1.age = 20; var attr = Object.keys(p1); console.log( attr ); //["name", "age"] var attr2 = Object.keys(p1.__proto__); console.log( attr2 ); //["name", "age", "sayName"] var attr3 = Object.keys(Person.prototype); console.log( attr3 ); //["name", "age", "sayName"]Object.getOwnPropertyNames()
function Person () { } Person.prototype.name = "z1"; Person.prototype.age = 20; Person.prototype.sayName = function () { console.log( "我是原型對象方法" ); } var p1 = new Person(); p1.name = "zz"; p1.age = 20; //ECMA5 //constructor屬性,是無法被枚舉的. 正常的for-in循環是無法枚舉. [eable = false]; //Object.getOwnPropertyNames(); //枚舉對象所有的屬性:不管該內部屬性能夠被枚舉. var attr4 = Object.getOwnPropertyNames(Person.prototype); //["constructor", "name", "age", "sayName"] console.log( attr3 );isPrototypeOf()
判斷原型的方法
原型對象.isPrototypeOf(new instance);
實現each方法原型的另外一個作用就是擴展對象中的屬性和方法
//遍歷多維數組 var arr = [1,2,4,5,[455,[456,[345345]]]]; Array.prototype.each = function ( cb ) { try { //計數器 this.i || (this.i = 0); //核心代碼 if ( this.length > 0 && cb.constructor === Function ) { while ( this.i < this.length ) { //計數器 大于 數組長度跳出 //獲得每一項值 var e = this[this.i]; //判斷是否是 數組 if ( e && e.constructor === Array ) { //遞歸 e.each(cb); } else { cb.call(null,e); } this.i++; } //使用完之后,釋放變量 this.i = null; } } catch (e) { //do someting } return this; }; arr.each(function( val ){ console.log(val); });簡單原型
直接通過對象字面量來重寫整個原型對象(這種方法會改變原型對象的構造器[改變為Object])
//簡單原型 function Person () { } Person.prototype = { constructor: Person, //原型的構造器改變 name: "zz", age: 20, say: function () { console.log( this.age ); } } var p1 = new Person(); console.log( p1.name ); p1.say();
存在的問題,constructor屬性是無法被枚舉的。加在原型對象上,可以被枚舉,被枚舉。不符合要求。
ECMA5中的Object.defineProperty()方法可以為原型對象重新加入構造器。constructor問題可以被避免。
//3個參數, 參數1:重新設置構造的對象 (給什么對象設置) 參數2:設置什么屬性 參數3:options配置項 (要怎么去設置) Object.defineProperty(Person.prototype,"constructor",{ enumerable: false, //是否是 能夠 被枚舉 value: Person //值 構造器的 引用 });
原型的動態特性
注意原型和創建實例的前后順序
function Person () { } var p1 = new Person(); // {} Person.prototype = { constructor: Person, name: "zf", age: 20, say: function () { console.log("原型"); } } //先把原型對象寫好,然后再實例化。 //p1.say(); //error 因為 原型對象里面沒有任何屬性和方法 var p2 = new Person(); p2.say(); //注意 簡單原型使用的順序(實例對象必須在原型對象之后創建)原型對象的常用開發模式 組合構造函數式和原型模式
function Person( name,age,firends ) { this.name = name; this.age = age; this.firends = firends; } Person.prototype = { constructor: Person, sayName: function () { console.log( this.name ); } } var p1 = new Person("zz",20,["zf"]); var p2 = new Person("zx",22,["z1"]); console.log( p1.firends ); //["zf"] console.log( p2.firends ); //["z1"]動態原型模式
就是把信息都封裝到函數中,這樣體現了封裝的概念。
//動態原型模式:(讓你的代碼 都封裝到一起) function Person( name,age,firends ) { this.name = name; this.age = age; this.firends = firends; //動態原型方法 if ( typeof this.sayName !== "function" ) { Person.prototype.sayName = function () { console.log(this.name); } } }穩妥構造函數式
穩妥模式就是沒有公共屬性,而且其他方法也不引用this對象,穩妥模式最適合在安全的環境中使用。如果程序對于安全性要求很高,那么非常適合這種模式。
也不能使用new關鍵字。
//穩妥構造函數式 durable object (穩妥對象) //1,沒有公共的屬性 //2,不能使用this對象 function Person ( name,age ) { //創建一個要返回的對象。 利用工廠模式思維。 var obj = new Object(); //可以定義一下是有的變量和函數 private var name = name || "zf"; // var sex = "女"; // var sayName = function () { // } //添加一個對外的方法 obj.sayName = function () { console.log(name); } return obj; } var p1 = Person("xixi",20); p1.sayName();深入原型繼承的概念
如果讓原型對象等于另一個類型的實例,結果會怎么樣呢?顯然此時的原型對象將包含一個指向另一個原型的指針,相應的另一個原型中也包含著一個指向另一個構造函數的指針。
原型鏈: 利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。
構造函數 原型對象 實例對象
構造函數.prototype = 原型對象
原型對象.constructor = 構造函數
實例對象.__proto__ = 原型對象
原型對象.isPrototypeOf(實例對象)
構造函數 實例對象 (類和實例)
isPrototypeOf(); //判斷是否 一個對象的 原型
//父類的構造函數 Sup function Sup ( name ) { this.name = name; } //父類的原型對象 Sup.prototype = { constructor: Sup, sayName: function () { console.log(this.name); } } //子類的構造函數 Sub function Sub ( age ) { this.age = age; } //如果子類的原型對象 等于 父類的 實例 //1, 顯然此時的原型對象將包含一個指向另一個原型的指針 //2, 相應的另一個原型中也包含著一個指向另一個構造函數的指針。 // 實例對象.__proto__ = 原型對象 // Sup的實例對象 和 Sup的原型對象 有一個關系 Sub.prototype = new Sup("zf"); // console.log( Sub.prototype.constructor ); //function Sup () {} // // console.log( Sub.prototype.__proto__ ); //Sup 的 原型對象 var sub1 = new Sub(20); console.log( sub1.name ); //zf sub1.sayName(); //zf
原型鏈繼承映射圖
繼承的三種方式 原型繼承//原型繼承的特點: //即繼承了父類的模板,又繼承了父類的原型對象。 (全方位的繼承) //父類 function Person ( name,age ) { this.name = name; this.age = age; } Person.prototype.id = 10; //子類 function Boy ( sex ) { this.sex = sex; } //原型繼承 Boy.prototype = new Person("zz"); var b = new Boy(); console.log( b.name ); //zz console.log( b.id ); //10類繼承
類繼承 (只繼承模板) 不繼承原型對象 (借用構造函數的方式繼承)
//父類 function Person ( name,age ) { this.name = name; this.age = age; } Person.prototype.id = 10; //子類 function Boy ( name,age,sex ) { //類繼承 Person.call(this,name,age); this.sex = sex; } var b = new Boy("zf",20,"女"); console.log( b.name ); //zf console.log( b.age ); //20 console.log( b.sex ); //女 console.log( b.id ); //父類的原型對象并沒有繼承過來.混合繼承
原型繼承+類繼承
//父類 (關聯父類和子類的關系) function Person ( name,age ) { this.name = name; this.age = age; } Person.prototype.id = 10; Person.prototype.sayName = function () { console.log( this.name ); } //子類 function Boy ( name,age,sex ) { //1 類繼承 Person.call(this,name,age); //繼承父類的模板 this.sex = sex; } //2 原型繼承 //父類的實例 和 父類的 原型對象的關系. Boy.prototype = new Person(); //繼承父類的原型對象 var b = new Boy("z1",20,"女"); console.log( b.name );//z1 console.log( b.sex ); //女 console.log( b.id ); //10 b.sayName(); //z1ExtJs底層繼承方式
模擬ExtJs底層繼承一部分代碼
//ExtJs 繼承 //2件事: 繼承了1次父類的模板,繼承了一次父類的原型對象 function Person ( name,age ) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, sayHello: function () { console.log("hello world!"); } } function Boy ( name,age,sex ) { //call 綁定父類的模板函數 實現 借用構造函數繼承 只復制了父類的模板 // Person.call(this,name,age); Boy.superClass.constructor.call(this,name,age); this.sex = sex; } //原型繼承的方式: 即繼承了父類的模板,又繼承了父類的原型對象。 // Boy.prototype = new Person(); //只繼承 父類的原型對象 extend(Boy,Person); // 目的 只繼承 父類的原型對象 , 需要那兩個類產生關聯關系. //給子類加了一個原型對象的方法。 Boy.prototype.sayHello = function () { console.log("hi,js"); } var b = new Boy("zf",20,"男"); console.log( b.name ); console.log( b.sex ); b.sayHello(); Boy.superClass.sayHello.call(b); //extend方法 //sub子類, sup 父類 function extend ( sub,sup ) { //目的, 實現只繼承 父類的原型對象。 從原型對象入手 //1,創建一個空函數, 目的:空函數進行中轉 var F = new Function(); // 用一個空函數進行中轉。 // 把父類的模板屏蔽掉, 父類的原型取到。 F.prototype = sup.prototype; //2實現空函數的原型對象 和 超類的原型對象轉換 sub.prototype = new F(); //3原型繼承 //做善后處理。 還原構造器 , sub.prototype.constructor = sub; //4 ,還原子類的構造器 // 保存一下父類的原型對象 // 因為 ①方便解耦, 減低耦合性 ② 可以方便獲得父類的原型對象 sub.superClass = sup.prototype; //5 ,保存父類的原型對象。 //自定義一個子類的靜態屬性 , 接受父類的原型對象。 //判斷父類的原型對象的構造器, (防止簡單原型中給更改為 Object) if ( sup.prototype.constructor == Object.prototype.constructor ) { sup.prototype.constructor = sup; //還原父類原型對象的構造器 } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79713.html
摘要:是完全的面向對象語言,它們通過類的形式組織函數和變量,使之不能脫離對象存在。而在基于原型的面向對象方式中,對象則是依靠構造器利用原型構造出來的。 JavaScript 函數式腳本語言特性以及其看似隨意的編寫風格,導致長期以來人們對這一門語言的誤解,即認為 JavaScript 不是一門面向對象的語言,或者只是部分具備一些面向對象的特征。本文將回歸面向對象本意,從對語言感悟的角度闡述為什...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:很多情況下,通常一個人類,即創建了一個具體的對象。對象就是數據,對象本身不包含方法。類是相似對象的描述,稱為類的定義,是該類對象的藍圖或原型。在中,對象通過對類的實體化形成的對象。一類的對象抽取出來。注意中,對象一定是通過類的實例化來的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 馬上就要到七夕了,離年底老媽老爸...
摘要:在中,并沒有對抽象類和接口的支持。例如,當對象需要對象的能力時,可以有選擇地把對象的構造器的原型指向對象,從而達到繼承的效果。本節內容為設計模式與開發實踐第一章筆記。 動態類型語言 編程語言按數據類型大體可以分為兩類:靜態類型語言與動態類型語言。 靜態類型語言在編譯時已確定變量類型,動態類型語言的變量類型要到程序運行時,待變量被賦值后,才具有某種類型。 而JavaScript是一門典型...
摘要:對象重新認識面向對象面向對象從設計模式上看,對象是計算機抽象現實世界的一種方式。除了字面式聲明方式之外,允許通過構造器創建對象。每個構造器實際上是一個函數對象該函數對象含有一個屬性用于實現基于原型的繼承和共享屬性。 title: JS對象(1)重新認識面向對象 date: 2016-10-05 tags: JavaScript 0x00 面向對象 從設計模式上看,對象是...
閱讀 1518·2023-04-25 17:41
閱讀 3040·2021-11-22 15:08
閱讀 842·2021-09-29 09:35
閱讀 1605·2021-09-27 13:35
閱讀 3323·2021-08-31 09:44
閱讀 2716·2019-08-30 13:20
閱讀 1939·2019-08-30 13:00
閱讀 2558·2019-08-26 12:12