摘要:原型對象內部也有一個指針屬性指向構造函數實例可以訪問原型對象上定義的屬性和方法。在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。
贊助我以寫出更好的文章,give me a cup of coffee?
2017最新最全前端面試題
私有變量和函數在函數內部定義的變量和函數,如果不對外提供接口,外部是無法訪問到的,也就是該函數的私有的變量和函數。
這樣在函數對象Box外部無法訪問變量color和fn,他們就變成私有的了:
var obj = new Box(); alert(obj.color);//彈出 undefined alert(obj.fn);//同上靜態變量和函數
當定義一個函數后通過點號 “.”為其添加的屬性和函數,通過對象本身仍然可以訪問得到,但是其實例卻訪問不到,這樣的變量和函數分別被稱為靜態變量和靜態函數。
實例變量和函數
在面向對象編程中除了一些庫函數我們還是希望在對象定義的時候同時定義一些屬性和方法,實例化后可以訪問,js也能做到這樣
為實例變量和方法添加新的方法和屬性
在box1中修改了a和fn,而在box2中沒有改變,由于數組和函數都是對象,是引用類型,這就說明box1中的屬性和方法與box2中的屬性與方法雖然同名但卻不是一個引用,而是對Box對象定義的屬性和方法的一個復制。
這個對屬性來說沒有什么問題,但是對于方法來說問題就很大了,因為方法都是在做完全一樣的功能,但是卻又兩份復制,如果一個函數對象有上千和實例方法,那么它的每個實例都要保持一份上千個方法的復制,這顯然是不科學的,這可腫么辦呢,prototype應運而生。
基本概念我們創建的每個函數都有一個prototype屬性,這個屬性是一個指針,指向一個對象,這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法。那么,prototype就是通過調用構造函數而創建的那個對象實例的原型對象。
使用原型的好處是可以讓對象實例共享它所包含的屬性和方法。也就是說,不必在構造函數中添加定義對象信息,而是可以直接將這些信息添加到原型中。使用構造函數的主要問題就是每個方法都要在每個實例中創建一遍。
在JavaScript中,一共有兩種類型的值,原始值和對象值。每個對象都有一個內部屬性 prototype ,我們通常稱之為原型。原型的值可以是一個對象,也可以是null。如果它的值是一個對象,則這個對象也一定有自己的原型。這樣就形成了一條線性的鏈,我們稱之為原型鏈。
含義函數可以用來作為構造函數來使用。另外只有函數才有prototype屬性并且可以訪問到,但是對象實例不具有該屬性,只有一個內部的不可訪問的__proto__屬性。__proto__是對象中一個指向相關原型的神秘鏈接。按照標準,__proto__是不對外公開的,也就是說是個私有屬性,但是Firefox的引擎將他暴露了出來成為了一個共有的屬性,我們可以對外訪問和設置。
當我們調用Bro.run()方法時,由于Bro中沒有這個方法,所以,他就會去他的__proto__中去找,也就是Browser.prototype,所以最終執行了該run()方法。(在這里,函數首字母大寫的都代表構造函數,以用來區分普通函數)
當調用構造函數創建一個實例的時候,實例內部將包含一個內部指針(__proto__)指向構造函數的prototype,這個連接存在于實例和構造函數的prototype之間,而不是實例與構造函數之間。
Person的實例person1中包含了name屬性,同時自動生成一個__proto__屬性,該屬性指向Person的prototype,可以訪問到prototype內定義的printName方法,大概就是這個樣子的:
每個JavaScript函數都有prototype屬性,這個屬性引用了一個對象,這個對象就是原型對象。原型對象初始化的時候是空的,我們可以在里面自定義任何屬性和方法,這些方法和屬性都將被該構造函數所創建的對象繼承。
那么,現在問題來了。構造函數、實例和原型對象三者之間有什么關系呢?
構造函數、實例和原型對象的區別實例就是通過構造函數創建的。實例一創造出來就具有constructor屬性(指向構造函數)和__proto__屬性(指向原型對象),
構造函數中有一個prototype屬性,這個屬性是一個指針,指向它的原型對象。
原型對象內部也有一個指針(constructor屬性)指向構造函數:Person.prototype.constructor = Person;
實例可以訪問原型對象上定義的屬性和方法。
在這里person1和person2就是實例,prototype是他們的原型對象。
再舉個栗子:
可以從程序運行結果看出,構造函數的prototype上定義的方法確實可以通過對象直接調用到,而且代碼是共享的。(可以試一下將Animal.prototype.behavior 中的prototype屬性去掉,看看還能不能運行。)在這里,prototype屬性指向Animal對象。
數組對象實例再看個數組對象的實例。當我們創建出array1這個對象的時候,array1實際在Javascript引擎中的對象模型如下:
var array1 = [1,2,3];
array1對象具有一個length屬性值為3,但是我們可以通過如下的方法來為array1增加元素:
array1.push(4);
push這個方法來自于array1的__proto__成員指向對象的一個方法(Array.prototye.push())。正是因為所有的數組對象(通過[]來創建的)都包含有一個指向同一個具有push,reverse等方法對象(Array.prototype)的__proto__成員,才使得這些數組對象可以使用push,reverse等方法。
函數對象實例function Base() { this.id = "base" }
var obj = new Base();
這樣代碼的結果是什么,我們在Javascript引擎中看到的對象模型是:
new操作符具體干了什么呢?其實很簡單,就干了三件事情。
var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);原型鏈
原型鏈:當從一個對象那里調取屬性或方法時,如果該對象自身不存在這樣的屬性或方法,就會去自己關聯的prototype對象那里尋找,如果prototype沒有,就會去prototype關聯的前輩prototype那里尋找,如果再沒有則繼續查找Prototype.Prototype引用的對象,依次類推,直到Prototype.….Prototype為undefined(Object的Prototype就是undefined)從而形成了所謂的“原型鏈”。
這里,用構造器Shape()新建了一個實體,然后用它去覆蓋該對象的原型。
原型繼承
原型繼承:
在原型鏈的末端,就是Object構造函數prototype屬性指向的那個原型對象。這個原型對象是所有對象的祖先,這個老祖宗實現了諸如toString等所有對象天生就該具有的方法。其他內置構造函數,如Function,Boolean,String,Date和RegExp等的prototype都是從這個老祖宗傳承下來的,但他們各自又定義了自身的屬性和方法,從而他們的子孫就表現出各自宗族的那些特征。
ECMAScript中,實現繼承的方法就是依靠原型鏈實現的。
原型鏈的問題:原型鏈雖然很強大,可以用它來實現繼承,但它也存在一些問題。其中最主要的問題來自包含引用類型的值原型。包含引用類型的原型屬性會被所有實例共享;而這也正是為什么要在構造函數中,而不是在原型對象中定義屬性的原因。在通過原型來實現繼承時,原型實際上回變成另一個類型的實例。于是,原先的實例屬性也就變成了原型的屬性。
在創建子類型的實例時,不能向超類型的構造函數中傳遞參數。實際上,應該說是沒有辦法在不影響所有對象實例的情況下,給超類型的構造函數傳遞參數。再加上剛剛討論的由于原型中包含引用類型值所帶來的問題,實踐中很少會多帶帶使用原型鏈。
再舉個栗子:
__ptoto__屬性
__ptoto__屬性(IE瀏覽器不支持)是實例指向原型對象的一個指針,它的作用就是指向構造函數的原型屬性constructor,通過這兩個屬性,就可以訪問原型里的屬性和方法了。
Javascript中的對象實例本質上是由一系列的屬性組成的,在這些屬性中,有一個內部的不可見的特殊屬性——__proto__,該屬性的值指向該對象實例的原型,一個對象實例只擁有一個唯一的原型。
__proto__屬性和prototype屬性的區別
prototype是function對象中專有的屬性。
__proto__是普通對象的隱式屬性,在new的時候,會指向prototype所指的對象;
__ptoto__實際上是某個實體對象的屬性,而prototype則是屬于構造函數的屬性。__ptoto__只能在學習或調試的環境下使用。
1.先查找構造函數實例里的屬性或方法,如果有,就立即返回。
2.如果構造函數的實例沒有,就去它的原型對象里找,如果有,就立即返回
構造函數的
綜上,整理一下:
構造函數.prototype = 原型對象 原型對象.constructor = 構造函數(模板) 原型對象.isPrototypeof(實例對象) 判斷實例對象的原型 是不是當前對象工廠模式
function createObject(name,age){ var obj = new Object(); obj.name = name; obj.age = age; return obj; }
工廠模式解決了實例化對象大量重復的問題,但還有一個問題,那就是根本無法搞清楚他們到底是哪個對象的實例。
使用構造函數的方法,既解決了重復實例化的問題,又解決了對象識別的問題。
使用構造函數的方法和工廠模式的不同之處在于:
1.構造函數方法沒有顯示的創建對象(new Object()); 2.直接將屬性和方法賦值給this對象 3.沒有return 語句
當使用了構造函數,并且new 構造函數(),那么就在后臺執行了new Object();
函數體內的this代表了new Object()出來的對象
1.判斷屬性是在構造函數的實例里,還是在原型里,可以使用`hasOwnProperty()`函數 2.字面量創建的方式使用constructor屬性不會指向實例,而會指向Object,構造函數創建的方式則相反 為什么指向Object?因為Box.prototype = {};這種寫法其實就是創建了一個新對象。 而每創建一個函數,就會同時創建它的prototype,這個對象也會自動獲取constructor屬性 3.如果是實例方法,不同的實例化,他們的方法地址是不一樣的,是唯一的 4.如果是原型方法,那么他們的地址的共享的
原型擴展:詳解js閉包
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/87620.html
摘要:看下面一個例子優點使用構造器函數的好處在于,它可以在創建對象時接收一些參數。按照慣例,構造函數的函數名應始終以一個大寫字母開頭,以區分普通函數。返回該對象的源代碼。使您有能力向對象添加屬性和方法。 基本概念 ECMA關于對象的定義是:無序屬性的集合,其屬性可以包含基本值、對象或者函數。對象的每個屬性或方法都有一個名字,而每個名字都映射到一個值。 類 在現實生活中,相似的對象之間往往都有...
摘要:執行行代碼,我們可以看到控制臺打印出來的結果如下結果印證了我們上面講的內容指向的構造函數指向的原型對象原型對象中指向構造函數。 在javascript中原型和原型鏈機制是最難懂的部分(沒有之一),同時也是最重要的部分,在學習的過程中你可能認認真真的看了一遍但還是完全不懂書上說的什么,的確是這樣的,我在學習的時候可是反復看了4、5遍才初步理解了。 下面我把我的理解總結了一下希望對你們有...
摘要:如下代碼所示,可以使用構造函數來創建父對象,這樣做的話,自身的屬性和構造函數的原型的屬性都將被繼承。方法繼承自對象這是中構造函數鏈的一個示例。 代碼復用及其原則 代碼復用,顧名思義就是對曾經編寫過的代碼的一部分甚至全部重新加以利用,從而構建新的程序。在談及代碼復用的時候,我們首先可以想到的是繼承性。代碼復用的原則是: 優先使用對象組合,而不是類繼承 在js中,由于沒有類的概念,因此實例...
摘要:當這步完成,這個對象就與構造函數再無聯系,這個時候即使構造函數再加任何成員,都不再影響已經實例化的對象了。此時,對象具有了和屬性,同時具有了構造函數的原型對象的所有成員,當然,此時該原型對象是沒有成員的。 前言 本篇文章用來記錄下最近研究對象的一些心得,做一個記錄與總結,以加深自己的印象,同時,希望也能給正在學習中的你一點啟發。本文適合有一定JavaScript基礎的童鞋閱讀。原文戳這...
摘要:原文地址詳解的類博主博客地址的個人博客從當初的一個彈窗語言,一步步發展成為現在前后端通吃的龐然大物。那么,的類又該怎么定義呢在面向對象編程中,類是對象的模板,定義了同一組對象又稱實例共有的屬性和方法。這個等同于的屬性現已棄用。。 前言 生活有度,人生添壽。 原文地址:詳解javascript的類 博主博客地址:Damonare的個人博客 ??Javascript從當初的一個彈窗語言,一...
閱讀 984·2021-11-23 09:51
閱讀 3470·2021-11-22 12:04
閱讀 2716·2021-11-11 16:55
閱讀 2921·2019-08-30 15:55
閱讀 3222·2019-08-29 14:22
閱讀 3351·2019-08-28 18:06
閱讀 1240·2019-08-26 18:36
閱讀 2126·2019-08-26 12:08