//如果有 animalfunction Person() {}Person.prototype = animal;var p = new Person();//原型鏈(相當于在原來的鏈中增加了一節):p -> Person.prototype(其實是animal) -> Animal.prototype -> Object.prototype(2)函數的原型鏈繪制原型鏈的結構(3)完整原型鏈結合對象的原型鏈和函數的原型鏈,將其繪制到一起2. Function
Function 是函數的構造函數(函數的constructor屬性就等于Function)借助這個理論可以繪制函數的對象原型鏈(三角形)3. 利用 Function 構建函數
定義一個函數需要有:① 參數② 函數體③ 返回值 這三個東西本質上是代碼,js允許將這些代碼以字符串的形式放到 Function 中,來構建函數。語法:var func = new Function( 參數1, 參數2, ..., 函數體 )例:設計一個函數,求兩個數字的和var sum = new Function( 'a', 'b', 'return a+b;' );函數體太多內容時,一般來說使用字符串拼接 + 折行顯示。為了解決麻煩,引入ES6中的可換行字符串,數字鍵左邊的左撇號。第三種方法,在頁面添加一個標簽<script type="text/template" id="code"> 函數體</script>document.createElementFragment應用:所見即所得的編輯器
4. 繪制函數的原型鏈結構
函數的構造函數是 FunctionFunction 是什么數據類型?函數結論:Function 是 Function 的構造函數① Function.prototype 是原型對象,Function 就繼承自該原型對象② Function 是 Function 的實例Function instanceof Function 為 true推論:Function instanceof Object 為 trueObject instanceof Function 為 trueFunction 也是函數,因此 Function 是 Function 的實例這是原型鏈中唯一的特例(兩個對象構成三角形關系)因此,Function 的 .prototype 與 .__proto__ 指向同一個對象
一般的函數不是這樣function Person() {}1) Person.prototype 是用于描述實例對象的, 表示 new Person() 所繼承的對象. 2) Person.__proto__ 是用于描述 Person 這個函數作為對象來說是 Function 的實例. 是 Function.prototype. 因此一般的函數, 這兩個屬性不是同一個對象.Function -> Function.prototype -> Object.prototype -> null例如:希望讓js中的所有函數都有 inherit 方法,來實現派生Function.prototype.inherit = function() {}Object.prototype.inherit = function() {}
5. __proto__
作用:讓實例對象可以訪問到該原型對象早期是無法直接訪問的,如果早期需要訪問,用 obj.constructor.prototype這樣不方便調試,很麻煩,因此在火狐中率先引入 __proto__ 屬性,用于讓對象直接訪問其原型。由于當時是非標準屬性,因此使用__作為前后綴。但是由于非常好用,今天的瀏覽器基本都實現了該屬性,但依舊沒有標準化(IE8不支持)。因此在開發時,不建議用,也不可以使用該屬性。調試原型鏈結構:obj.__protp__.__proto__.__proto__.__proto__因此在實際開發中,使用 __proto__ 只是用于調試查看,即只用其讀的特性。以前的結論:① 只有函數有 prototype 屬性② 只有實例對象有 __proto__ 屬性今天的結論:函數也是對象,函數也有 __proto__ 屬性① 函數有 prototype 屬性,該屬性指向原型,該原型被函數的實例對象所繼承② 函數有 __proto__ 屬性,該屬性指向原型,該函數繼承自該原型③ 函數的 __proto__ 就是 Function.prototype,Function.__proto__ 就是 Function.prototype6. Object 本身就是一個構造函數
function Person() { }// Object 與 Person 是等同地位的就像人是由基因決定的,無論是父親還是兒子都有基因基因就好比構造函數,決定對象有什么成員,也就是對象長什么樣子結論:① 對象應該都有原型② 實例對象繼承自 構造函數.prototype③ 原型對象也有繼承的關系④ 只有原型中有 constructor,constructor 決定了原型的名字如果 constructor 是 AAA, 那么 這個原型就是 AAA.prototype到此我們得到對象的原型鏈結構1) [ ] [ ] -> Array.prototype -> Object.prototype -> null2) p: Person p -> Person.prototype -> Object.prototype -> null3) { } { } -> Object.prototype -> null結合原型式繼承. 什么是原型式繼承? 怎么操作原型式繼承?1) 原型式繼承就是 原型中提供的成員, 我們的實例對象可以直接使用, 好像是自己的一樣.2) 所謂的操作原型式繼承就是在 對原型鏈做增加, 刪除, 修改的操作.//如果有 animalfunction Person () {}Person.prototype = animal;var p = new Person();...//原型鏈://p -> Person.prototype( 其實是 animal ) -> Animal.prototype -> Object.prototype -> null7. 字面量的原型鏈
所謂的字面量就是在代碼中的寫出來以后有數據、有大小、有類型等具體的數據。常見的字面量有:數字 1,2,123, ...布爾值 true,false字符串 'xxxxxx'對象 { },注意有時需要使用( { } )數組 [ ]函數 function() { }正則表達式 /.+/字面量中,凡是引用類型的都有對應的構造函數,因此原型鏈的繪制就簡單了。8. 屬性搜索原則錯誤的結論:如果一個對象中沒有對應的方法,但是其原型中提供了該方法,該對象可以直接使用原型中的方法,就好像是自己的方法一樣。所謂的屬性搜索原則是說,對象在訪問某一個成員的時候,采用的訪問規則① 首先在當前對象中查找是否有對應的成員(在自己的代碼結構中找)② 如果有,則使用該成員,并停止查找,如果沒有,則到其原型對象中查找對應的成員③ 如果其原型中有該成員,則使用,并停止查找,否則繼續往原型的原型中查找④ 如此往復⑤ 直到 Object.prototype 中,如果還沒有對應的成員,則返回 undefined訪問依照就近原則9. 原型成員的讀寫
在讀取數據的時候,如果當前對象沒有該數據,原型中提供了該數據,那么可以直接訪問該數據。但是,如果是修改屬性,不會對原型中的數據造成任何影響,只會在當前對象中新創建一個該成員,再次讀取該成員時,就不再走原型上的數據了。10. instanceof 運算符
語法:object(要檢測的對象) instanceof constructor(某個構造函數) -> boolean含義:檢測 constructor.prototype 是否存在于 object 的原型鏈上,即一個對象在其原型鏈中是否存在一個構造函數的 prototype 屬性案例1:function Person() {}var p = new Person();p instanceof Person // true//p 的原型鏈://p -> Person.prototype -> Object.prototype -> null案例2:function Person() {}var p1 = new Person();Person.prototype = {};var p2 = new Person();console.log( p1 instanceof Person );//falseconsole.log( p2 instanceof Person );//true//分析原型鏈://p1 -> Person.prototype(原始的類型) -> Object.prototype -> null//p2 -> Person.prototype( { } ) -> Object.prototype -> null//現在 Person.prototype 是 { }//p1 instanceof Person 表示檢測 { } 是否在 p1 的原型鏈中 -> false//p2 instanceof Person 表示檢測 { } 是否在 p2 的原型鏈中 -> true案例3:
console.log(Function instanceof Object);//true//Object.prototype 是否在 Function 的原型鏈中console.log(Function instanceof Function);//true//Function.prototype 是否在 Function 的原型鏈中console.log(Object instanceof Object);//true//Object.prototype 是否在 Object 的原型鏈中console.log(Object instanceof Function);//true//Function.prototype 是否在 Object 的原型鏈中//Object -> Function.prototype -> Object.prototype -> null Object、Function、Array 等等都是構造函數,都是函數 => 而所有函數都是構造函數 Function 的實例 => 從原型鏈機制來說,所有函數都能通過原型鏈找到創建他們的構造函數 Function 的構造原型 Function.prototype 對象=> Object instanceof Function 的結果為 true 又因為 Function.prototype 是一個對象=> Function.prototype 的構造函數是 Object=> 從原型鏈機制來說,所有對象都能通過原型鏈找到創建它們的構造函數 Object 的構造原型 Object.prototype 對象=> Function instanceof Object 的結果為 true Function 是構造函數=> Function 是函數對象=> 函數對象都是由 Function 構造函數創建而來的,從原型鏈機制來說,函數對象的原型鏈中存在 Function.prototype => Function.prototype 在構造函數 Function 的原型鏈中被查到=> Function instanceof Function 的結果為 true結論:在 js 中,一切皆對象,它們全部繼承自 Object,或者說所有對象的原型鏈的根節點都是 Object.prototype11. Object.prototype 的常用成員
(1)hasOwnProperty
語法:對象.hasOwnProperty( '屬性名稱' ) -> boolean含義:判斷某個屬性是否是當前對象提供,而不是原型提供的作用:一般在寫混入的時候會使用for(var k in obj){
//只混入當前對象的屬性
if(obj.hasOwnProperty(k)){
dist[k] = obj[k];
}
}
(2)isPrototypeOf
語法:對象A.isPrototypeOf( 對象B ) -> boolean含義:判斷 對象A 是不是 對象B 的原型(實質上是判斷對象A是否在對象B的原型鏈中)(3)prototypeIsEnumerable
語法:對象A.prototypeIsEnumerable( '屬性名稱' ) -> boolean含義:判斷當前對象是否提供對應的屬性,同時該屬性可枚舉在 js 中一般添加的成員都是可枚舉的(所謂的可枚舉就是利用 for in 可以遍歷出來)在 ES5 之前,所有的自定義屬性都是可枚舉的,是無法控制的。因此該方法很少使用。在 ES5 之后,引入了 Object.definedPrototype 等方法,允許用戶定義不可枚舉的屬性。(4)valueOf
將對象轉換成基本類型(實現的不好,平時不會用,都是自己實現該方法去轉換)內部的實現就是 return this,把自己返回了,并沒有實現功能,沒什么用處(5)toString
將對象轉換成字符串(實現的不好,平時不會用,都是自己實現該方法去轉換)console.log(s.toString());//[object Object](假設s是個對象)console.log([].toString());//默認將數組元素用逗號連接,因此會打印空//數組自己有 toString 方法(6)toLocaleString
將對象轉換成本地字符串(實現的不好,平時不會用,都是自己實現該方法去轉換)例:計算機毫秒數從1970年開始算
新聞熱點
疑難解答