摘要:但是確是一個特例它的指向的是至于為什么簡單解釋下所有的構造器都來自于,甚至包括根構造器及自身。所有構造器都繼承了的屬性及方法。如知道了所有構造器含內置及自定義的都是,的是誰呢這說明所有的構造器也都是一個普通對象,可以給構造器添加刪除屬性等。
前言
此文章為加深對JS中重要概念進行理解,不建議沒有任何JS基礎的人看,只為加深對概念理解通過實際的例子,而不是看書以為自己讀懂了,可能幾天后就忘了,主要是為了理解核心概念,以及對重難點解釋。
一切都是對象概念“一切都是對象”這句話的重點在于如何去理解“對象”這個概念。
JavaScript 中,萬物皆對象!但對象也是有區別的。分為普通對象和函數對象,Object 、Function 是 JS 自帶的函數對象。
當然,也不是所有的都是對象,值類型就不是對象。
function show(x) { console.log(typeof x); // undefined console.log(typeof 10); // number console.log(typeof "abc"); // string console.log(typeof true); // boolean console.log(typeof function () {}); //function console.log(typeof [1, "a", true]); //object console.log(typeof { a: 10, b: 20 }); //object console.log(typeof null); //object console.log(typeof new Number(10)); //object } show();
以上代碼列出了typeof輸出的集中類型標識,其中上面的四種(undefined, number, string, boolean)屬于簡單的值類型,不是對象。剩下的幾種情況——函數、數組、對象、null、new Number(10)都是對象。他們都是引用類型。
對象——若干屬性的集合 概念數組是對象,函數是對象,對象還是對象。
對象里面的一切都是屬性,只有屬性,沒有方法
那么這樣方法如何表示呢?——方法也是一種屬性。因為它的屬性表示為鍵值對的形式。
而且,javascript中的對象可以任意的擴展屬性,沒有class的約束。這個大家應該都知道,就不再強調了。
先說個最常見的例子:
var obj = { a: 10, b: function(x) { alert(this.a + x) }, c: { name: "yzh", age: 21 } }
以上代碼中,obj是一個自定義的對象,其中a、b、c就是它的屬性,而且在c的屬性值還是一個對象,它又有name、year兩個屬性。
這個可能比較好理解,那么函數和數組也可以這樣定義屬性嗎?——當然不行,但是它可以用另一種形式,總之函數/數組之流,只要是對象,它就是屬性的集合。
var fn = function () { alert(100); }; fn.a = 10; fn.b = function () { alert(123); }; fn.c = { name: "yzh", age: 21 };
上段代碼中,函數就作為對象被賦值了a、b、c三個屬性——很明顯,這就是屬性的集合。
創建對象 前言(引用類型)都是對象,對象是屬性的集合。最需要了解的就是對象的概念。
這塊在《JS高級程序設計》也算是大章節下的一塊大內容,我只把一些重要的概念寫出來讓大家理解,具體的深入要自己去看書中的講解。
函數和對象的關系對象都是通過函數創建的
function Fn() { this.name = "yzh"; this.year = 1996; } var fn1 = new Fn();
有人可能會舉出如下反例
var obj = { a: 10, b: 20 }; var arr = [5, "x", true];
這種做法屬于使用“快捷方式”,在編程語言中,一般叫做“語法糖”。
其實以上代碼的本質是:
//var obj = { a: 10, b: 20 }; //var arr = [5, "x", true]; var obj = new Object(); obj.a = 10; obj.b = 20; var arr = new Array(); arr[0] = 5; arr[1] = "x"; arr[2] = true;
而其中的 Object 和 Array 都是函數:
console.log(typeof (Object)); // function console.log(typeof (Array)); // function
prototype總結:對象都是通過函數來創建的
函數也是一種對象。他也是屬性的集合,你也可以對函數進行自定義屬性
每創建一個函數,就會同時創建函數的prototype對象。
這個prototype的屬性值是一個對象(屬性的集合,再次強調!),默認的只有一個叫做constructor的屬性,指向這個函數本身。
function Fn() { } Fn.prototype.name = "王福朋"; Fn.prototype.getYear = function () { return 1988; }; var fn = new Fn(); console.log(fn.name); console.log(fn.getYear());
Fn是一個函數,fn對象是從Fn函數new出來的,這樣fn對象就可以調用Fn.prototype中的屬性。
因為每個對象都有一個隱藏的屬性——“__proto__”,這個屬性引用了創建這個對象的函數的prototype。
即:fn.__proto__ === Fn.prototype
這里的"__proto__"成為“隱式原型”
每個函數function都有一個prototype,即原型。這里再加一句話——每個對象都有一個__proto__,可成為隱式原型。__proto__用于指向創建它的構造函數的原型對象
對象 person1 有一個 __proto__屬性,創建它的構造函數是 Person,構造函數的原型對象是 Person.prototype ,所以:
person1.__proto__ == Person.prototype
又比如:obj這個對象本質上是被Object函數創建的,因此obj.__proto__=== Object.prototype
在說明“Object.prototype”之前,先說一下自定義函數的prototype。自定義函數的prototype本質上就是和 var obj = {} 是一樣的,都是被Object創建,所以它的__proto__指向的就是Object.prototype。
但是Object.prototype確是一個特例——它的__proto__指向的是null.
至于為什么簡單解釋下:
所有的構造器都來自于 Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了·Function.prototype·的屬性及方法。如length、call、apply、bind
console.log(typeof Function.prototype) // function console.log(typeof Object.prototype) // object console.log(typeof Number.prototype) // object console.log(typeof Boolean.prototype) // object console.log(typeof String.prototype) // object console.log(typeof Array.prototype) // object console.log(typeof RegExp.prototype) // object console.log(typeof Error.prototype) // object console.log(typeof Date.prototype) // object console.log(typeof Object.prototype) // object
知道了所有構造器(含內置及自定義)的__proto__都是Function.prototype,
Function.prototype的__proto__是誰呢?
console.log(Function.prototype.__proto__ === Object.prototype) // true
這說明所有的構造器也都是一個普通 JS 對象,可以給構造器添加/刪除屬性等。同時它也繼承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。
最后Object.prototype的proto是誰?
Object.prototype.__proto__ === null // true
已經到頂了,為null。
訪問一個對象的屬性時,先在基本屬性中查找,如果沒有,再沿著__proto__這條鏈向上找
javascript中的繼承是通過原型鏈來體現的.
傳統原型語法
function Foo() {} Foo.prototype.a = 100; Foo.prototype.b = 200; var f1 = new Foo(); f1.a = 10; alert(f1.a); //10 alert(f1.b); //200
function Foo() {} var f1 = new Foo(); f1.a = 10; Foo.prototype.a = 100; Foo.prototype.b = 200; alert(f1.a); //10 alert(f1.b); //200
對象字面量方法添加屬性和方法的注意事項
function Foo() {} Foo.prototype = { a: 100, b: 200 } var f1 = new Foo(); f1.a = 10; alert(f1.a); //10 alert(f1.b); //200
function Foo() {} var f1 = new Foo(); f1.a = 10; Foo.prototype = { a: 100, b: 200 } alert(f1.a); //10 alert(f1.b); //undefined
原型的屬性和方法賦值要在,新建實例對象之前,不然無法獲得原型的值和屬性,alert返回相應的undefined
重寫原型對象問題接上面的例子講,如果在實例上添加新屬性,這個屬性就會屏蔽原型對象中保存的同名屬性,就是阻止訪問了屬性,而不是修改原型的屬性。
function Foo() {} var f1 = new Foo(); f1.a = 10; Foo.prototype = { a: 100, b: 200 } alert(f1.a); //10 alert(f1.b); //undefined
End總結:重寫原型對象切斷了現有原型與任何之前已經存在的對象實例之間的關系,它們的引用的仍然是最初的原型。
暫時總結到此,有些知識點沒有講到,可能需要大家自己去看書或查閱資料來理解,本人理解也有限,文中若有難以理解的還望大神換個方式來闡述。
未完待續后續還有兩篇講解《執行上下文與作用域》和《閉包》,最后一篇閉包可能會有一些前端面試題來講,并在文章末做個總結。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/83048.html
摘要:不理解沒關系,下面會結合圖例分析上一篇高級程序設計筆記創建對象下一篇高級程序設計筆記繼承參考之原型鏈的解讀三張圖搞懂的原型對象與原型鏈繼承與原型鏈 文章直接從原型圖解開始的,如果對一些概念不太清除,可以結合后面幾節查看 1. 圖解原型鏈 1.1 鐵三角關系(重點) function Person() {}; var p = new Person(); showImg(https://s...
摘要:繼承和前面兩篇文章中的知識非常相關,如果對函數創建原理和原型鏈不熟悉,請猛戳高級程序設計筆記創建對象高級程序設計筆記原型圖解繼承,通俗的說,就是將自身不存在的屬性或方法,通過某種方式為自己所用文章分別介紹原型鏈繼承繼承借用構造函數繼承組合繼 繼承和前面兩篇文章中的知識非常相關,如果對函數創建原理和原型鏈不熟悉,請猛戳:《javascript高級程序設計》筆記:創建對象《javascri...
原型鏈之前一直都不是很理解,這兩天把《你不知道的JavaScript》和《JavaScript高級程序設計》的原型鏈那章看完后有所理解,在這里先記下來,加深印象。 什么是原型對象 要講清楚什么是原型鏈需要從原型對象開始談,那么什么是原型對象呢?《JavaScript高級程序設計》中是這樣講的: 無論什么時候,只要創建了一個新函數,就會根據一組特定的規則為該函數創建一個prototype屬性,這個屬...
摘要:探索是如何判斷的表達式如果函數的顯式原型對象在對象的隱式原型鏈上,返回,否則返回是通過自己產生的實例案例案例重要注意的顯示原型和隱式原型是一樣的。面試題測試題測試題報錯對照下圖理解 原型與原型鏈深入理解(圖解) 原型(prototype) 函數的 prototype 屬性(圖) 每個函數都有一個prototype屬性,它默認指向一個Object空對象(即稱為:原型對象) 原型對象中有...
摘要:此時的原型對象包括一個指向另一個原型的指針,相應的,另一個原型中的指向另一個構造函數。這種關系層層遞進,就通過一個原型對象鏈接另一個構造函數的原型對象的方式實現了繼承。 讀這篇之前,最好是已讀過我前面的關于對象的理解和封裝類的筆記。第6章我一共寫了3篇總結,下面是相關鏈接:讀《javaScript高級程序設計-第6章》之理解對象讀《javaScript高級程序設計-第6章》之封裝類 一...
摘要:繼承的是超類型中構造函數中的屬性,如上繼承了屬性,但沒有繼承原型中的方法。上述造成的結果是子類型實例中有兩組超類型的構造函數中定義的屬性,一組在子類型的實例中,一組在子類型實例的原型中。 ECMAScript只支持實現繼承,主要依靠原型鏈來實現。與實現繼承對應的是接口繼承,由于script中函數沒有簽名,所以無法實現接口繼承。 一、原型鏈 基本思想:利用原型讓一個引用類型繼承另一個引用...
閱讀 854·2021-11-19 11:29
閱讀 3349·2021-09-26 10:15
閱讀 2855·2021-09-22 10:02
閱讀 2433·2021-09-02 15:15
閱讀 1970·2019-08-30 15:56
閱讀 2408·2019-08-30 15:54
閱讀 2903·2019-08-29 16:59
閱讀 635·2019-08-29 16:20