摘要:前言文章主要基于高級(jí)程序設(shè)計(jì)總結(jié)的基本重寫了全文補(bǔ)充知識(shí)點(diǎn)新增實(shí)例優(yōu)化排版新增檢測(cè)方法技巧用法構(gòu)造函數(shù)創(chuàng)建一個(gè)用護(hù)定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類型之一命令執(zhí)行構(gòu)造函數(shù)返回一個(gè)實(shí)例對(duì)象構(gòu)造函數(shù)一個(gè)指定對(duì)象實(shí)例的類型的函數(shù)傳慘一
前言
文章主要基于<< Javascrpt 高級(jí)程序設(shè)計(jì)3 >>總結(jié)的!!!
PS: 2018/05/09 基本重寫了全文,補(bǔ)充知識(shí)點(diǎn),新增實(shí)例,優(yōu)化排版
PS: 2018/05/11 新增檢測(cè)方法,技巧用法
new constructor(arguments):
創(chuàng)建一個(gè)用護(hù)定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類型之一
new命令: 執(zhí)行構(gòu)造函數(shù)返回一個(gè)實(shí)例對(duì)象
構(gòu)造函數(shù)(constructor): 一個(gè)指定對(duì)象實(shí)例的類型的函數(shù)
傳慘(arguments): 一個(gè)用來(lái)被構(gòu)造函數(shù)調(diào)用的慘數(shù)列表
注意點(diǎn)幾個(gè):
默認(rèn)構(gòu)造函數(shù)首字母大寫區(qū)分函數(shù)類型
在不傳遞任何慘數(shù)的情況new constructor可以省略括號(hào)
構(gòu)造函數(shù)與其他函數(shù)的唯一區(qū)別: 就在于調(diào)用它們的方式不同.(任何函數(shù),只要通過(guò) new 操作符來(lái)調(diào)用,那它就可以作為構(gòu)造函數(shù);而任何函數(shù),如果不通過(guò) new 操作符來(lái)調(diào)用,那它跟普通函數(shù)也不會(huì)有什麼兩樣)
使用構(gòu)造函數(shù)的主要問(wèn)題,就是每個(gè)方法都要在每個(gè)實(shí)例上重新創(chuàng)建一遍
new存在的意義在于它實(shí)現(xiàn)了javascript中的繼承,而不僅僅是實(shí)例化了一個(gè)對(duì)象
這是基本用法,大家都懂的,然后我們往深層次里挖掘下底層原理怎麼運(yùn)作的.
假設(shè)有個(gè)函數(shù)
function Person(name) { this.name = name || "mike", this.getAge = function () { console.log(10); } } var man = new Person; var women = new Person("tracy") console.log(man.name, women.name) // mike tracy
當(dāng)代碼執(zhí)行時(shí)會(huì)經(jīng)過(guò)幾個(gè)步驟:
以下是我基于JS高程3總結(jié)的:
一個(gè)新的空對(duì)象被創(chuàng)建
創(chuàng)建執(zhí)行的時(shí)候,將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此 this 就指向了這個(gè)新對(duì)象)
執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)等初始化工作
如果構(gòu)造函數(shù)返回了一個(gè)“對(duì)象”,那麼這個(gè)對(duì)象會(huì)取代整個(gè)new出來(lái)的結(jié)果.如果構(gòu)造函數(shù)沒有返回對(duì)象,那麼new出來(lái)的結(jié)果為步驟1創(chuàng)建的對(duì)象,(ps:一般情況下構(gòu)造函數(shù)不返回任何值,如果想覆蓋這個(gè)返回值,可以選擇返回一個(gè)普通對(duì)象.);
以下是原版:
創(chuàng)建一個(gè)新對(duì)象
將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此 this 就指向了這個(gè)新對(duì)象)
執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)
返回新對(duì)象.
下面詳細(xì)舉例
1、如果構(gòu)造函數(shù)不返回任何值則按照其他語(yǔ)言一樣返回實(shí)例化對(duì)象(即步驟1創(chuàng)建的對(duì)象).
function Person() { } var man = new Person(); console.log(man) // Person {}
2、如果構(gòu)造函數(shù)返回的是基本類型 (string, number, boolean, null,undefined) 也按照其他語(yǔ)言一樣返回實(shí)例化對(duì)象(即步驟1創(chuàng)建的對(duì)象).如果你們還搞不懂基本類型跟引用對(duì)象的區(qū)別,可以參考我之前寫的文章關(guān)於javascript基本類型和引用類型小知識(shí)
function Person() { return "我是基本類型" } var man = new Person(); console.log(man)//Person {}
3、若返回值是引用類型,則實(shí)際返回值為這個(gè)引用類型.
function Person() { return { age: 18 } } var man = new Person(); console.log(man) //Object {age: 18}
初學(xué)者特別應(yīng)該注意的是他們之間是不同的,所謂的構(gòu)造函數(shù)是創(chuàng)建一個(gè)用戶定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象類型之一
正常來(lái)說(shuō)構(gòu)造函數(shù)不需要有返回值的,可以認(rèn)為構(gòu)造函數(shù)和普通函數(shù)的最大差別就是:構(gòu)造函數(shù)中沒有return語(yǔ)句,普通函數(shù)可以有return語(yǔ)句;構(gòu)造函數(shù)中會(huì)使用this關(guān)鍵字定義成員變量和成員方法,普通的函數(shù)不會(huì)使用this關(guān)鍵字定義成員變量和方法.
像第二種情況即使返回基本類型也會(huì)被忽略掉,只有選擇返回一個(gè)普通對(duì)象才會(huì)取代整個(gè)new出來(lái)的結(jié)果
每個(gè)函數(shù)都有一個(gè) prototype 屬性, prototype 就是指向通過(guò)調(diào)用構(gòu)造函數(shù)而創(chuàng)建的那個(gè)對(duì)象實(shí)例的原型對(duì)象,作用是可以讓所有對(duì)象實(shí)例共享它所包含的屬性和方法.
在JavaScript中一切皆對(duì)象,每個(gè)對(duì)象都是繼承自另一個(gè)對(duì)象,所以對(duì)象都有自己的原型對(duì)象(除了null以外).
所以除了在構(gòu)建函數(shù)內(nèi)部定義屬性方法共享之外,我們還可以在構(gòu)造函數(shù)的原型對(duì)象上添加共享的自定義屬性方法.
function Person() { } //原型鏈添加函數(shù) Person.prototype.getAge = function () { console.log(18) } //實(shí)例化 var man = new Person(), women = new Person(); man.getAge() // 18 women.getAge() // 18
有一種情況是對(duì)象實(shí)例自身已經(jīng)賦有同名屬性方法會(huì)覆蓋 prototype 上的屬性方法.這個(gè)認(rèn)知是不準(zhǔn)確的,下面的原型鏈會(huì)講到這部分.
function Person() { } //原型鏈添加函數(shù) Person.prototype.getAge = function () { console.log(18) } //實(shí)例化 var man = new Person(); man.getAge = function () { console.log(81) } man.getAge() // 81
還有一種情況是在構(gòu)造函數(shù)的原型對(duì)象上添加共享的自定義屬性方法并且實(shí)例化對(duì)象之后,再次修改原型對(duì)象上的方法.同樣會(huì)影響到輸出結(jié)果,依然下面的原型鏈會(huì)講到這部分.
function Person() { } //原型鏈添加函數(shù) Person.prototype.getAge = function () { console.log(18) } //實(shí)例化 var man = new Person(); //修改原型鏈自定義函數(shù) Person.prototype.getAge = function () { console.log(81) } man.getAge() // 81原型鏈
下面引出JS高程三解析片段----------
理解原型對(duì)象(關(guān)鍵詞 prototype, constructor, __proto__)
無(wú)論什麼時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype 屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象.在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè) constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向 prototype 屬性所在函數(shù)的指針.
就拿前面的例子來(lái)說(shuō),Person.prototype.constructor 指向 Person .而通過(guò)這個(gè)構(gòu)造函數(shù),我們還可繼續(xù)為原型對(duì)象添加其他屬性和方法.創(chuàng)建了自定義的構(gòu)造函數(shù)之后,其原型對(duì)象默認(rèn)只會(huì)取得 constructor 屬性;至于其他方法,則都是從 Object 繼承而來(lái)的.
當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象.
ECMA-262 第 5 版中管這個(gè)指針叫 [[Prototype]] .雖然在腳本中沒有標(biāo)準(zhǔn)的方式訪問(wèn) [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每個(gè)對(duì)象上都支持一個(gè)屬性__proto__ ;而在其他實(shí)現(xiàn)中,這個(gè)屬性對(duì)腳本則是完全不可見的.不過(guò),要明確的真正重要的一點(diǎn)就是,這個(gè)連接存在于實(shí)例與構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在于實(shí)例與構(gòu)造函數(shù)之間.
這里引出兩個(gè)關(guān)鍵知識(shí)點(diǎn):
所有對(duì)象都有屬性__proto__指向該對(duì)象的構(gòu)造函數(shù)的原型對(duì)象,原型鏈就是靠它形成的
函數(shù)對(duì)象除了__proto__,還有屬性prototype指向該方法的原型對(duì)象,它的作用是:構(gòu)造函數(shù)實(shí)例化對(duì)象的時(shí)候,告訴構(gòu)造函數(shù)新創(chuàng)建的對(duì)象的原型是誰(shuí);
間單說(shuō)構(gòu)造函數(shù)、原型和實(shí)例的關(guān)系:每個(gè)構(gòu)造函數(shù)都有一個(gè)原型對(duì)象,原型對(duì)象都包含一個(gè)指向構(gòu)造函數(shù)的指針,而實(shí)例都包含一個(gè)指向原型對(duì)象的內(nèi)部指針.原型鏈可以讓我們做到利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法.
Javascript 一切皆對(duì)象(普通對(duì)象和函數(shù)對(duì)象).每個(gè)函數(shù)對(duì)象都有一個(gè)內(nèi)部鏈接到另一個(gè)對(duì)象它的原型 prototype.該原型對(duì)象有自己的原型,等等,直到達(dá)到一個(gè)以null為原型的對(duì)象.根據(jù)定義,null沒有原型,并且作為這個(gè)原型鏈 prototype chain中的最終鏈接.
例如:
function Person() { this.name = "mike" } var man = new Person; console.log(man.__proto__ === Person.prototype); // true //繼續(xù)深入發(fā)掘它的原型 console.log(Person.prototype.__proto__ === Object.prototype); // true //前面說(shuō)的一切皆對(duì)象是這個(gè)意思 console.log(Function.prototype.__proto__); // Object {} console.log(Array.prototype.__proto__); // Object {} console.log(Number.prototype.__proto__); // Object {} //繼續(xù)深入發(fā)掘它的最終來(lái)源是什麼 console.log(Object.prototype); // Object {} console.log(Object.prototype.__proto__); // null
上面一步一步挖到最初的原型,有個(gè)注意的點(diǎn)容易混淆的,再?gòu)?qiáng)調(diào)一遍prototype是函數(shù)對(duì)象繼承的原型,__proto__是指向創(chuàng)建它的函數(shù)對(duì)象的原型對(duì)象prototype.只有真的弄清楚關(guān)系你才知道下面的區(qū)別
console.log(Function.prototype); // function () {} console.log(Array.prototype); // [Symbol(Symbol.unscopables): Object] console.log(Number.prototype); // Number {[[PrimitiveValue]]: 0} console.log(Object.prototype); // Object {} //下面函數(shù)對(duì)象都是通過(guò)new Function()創(chuàng)建,所以指向必定都是Function.prototype. console.log(Function.__proto__); console.log(Array.__proto__); console.log(Number.__proto__); console.log(Object.__proto__); //細(xì)細(xì)品味這句 console.log(Function.__proto__ === Function.prototype); // true
訪問(wèn)一個(gè)對(duì)象的屬性時(shí),它先在該對(duì)象上搜尋,如果該對(duì)象沒有就搜尋該對(duì)象的原型,如果還沒有就繼續(xù)往該對(duì)象的原型的原型搜索,依此層層向上搜索,直到找到一個(gè)名字匹配的屬性或到達(dá)原型鏈的末尾(即undefined)位置.這就是上面說(shuō)的實(shí)例方法覆蓋原型對(duì)象方法認(rèn)知不準(zhǔn)確的解釋了
function Person() { this.name = "mike" } Person.prototype.age = 10; Person.prototype.getAge = function() { console.log(20) }; var man = new Person; console.log(man.age) // 10 man.getAge() //20 console.log(man.sex) // undefined
原型對(duì)象除了__proto__之外還有一個(gè)constructor屬性,作用是返回對(duì)創(chuàng)建此對(duì)象的函數(shù)的引用.這個(gè)比較間單,直接上實(shí)例
function Person() { this.name = "mike" } var man = new Person; console.log(man.__proto__.constructor === Person); // true console.log(new Array().constructor); // [Function: Array] console.log(new Number().constructor); // [Function: Number] console.log(new Object().constructor); // [Function: Object] console.log(new Function().constructor); // [Function: Function]
實(shí)例化對(duì)象man打印結(jié)果如下.
man.__proto__.constructor === Person
上面獲取原型對(duì)象的方法其實(shí)不安全,
依賴瀏覽器環(huán)境暴露出來(lái)的訪問(wèn)屬性,
在實(shí)例對(duì)象變更原型對(duì)象指向的情況會(huì)失效
function Person() { this.name = "mike" } var man = new Person; man.prototype = Object; console.log(man.prototype); // [Function: Object]
所以我們一般通過(guò)Object.getPrototypeOf方法去獲取.
function Person() { this.name = "mike" } var man = new Person; man.prototype = Object; console.log(man.prototype); // [Function: Object] console.log(Object.getPrototypeOf(man)); // Person {}
如果是想要檢測(cè)某個(gè)對(duì)象是否構(gòu)造函數(shù)的實(shí)例,可以使用instanceof
function Person() { this.name = "mike" } var man = new Person; console.log(man instanceof Person); // true技巧用法
還記得上面說(shuō)的構(gòu)造函數(shù)與其他函數(shù)的唯一區(qū)別,就在于調(diào)用它們的方式不同.任何函數(shù),只要通過(guò) new 操作符來(lái)調(diào)用,那它就可以作為構(gòu)造函數(shù);而任何函數(shù),如果不通過(guò) new 操作符來(lái)調(diào)用,那它跟普通函數(shù)也不會(huì)有什麼兩樣;
用個(gè)小技巧可以讓你沒有使用new操作符也能實(shí)例化構(gòu)造函數(shù),為了區(qū)別改了點(diǎn)代碼.
function Person(name) { //如果是實(shí)例化對(duì)象直接賦值 if (this instanceof Person) { this.name = name } else { //否則重新實(shí)例化 return new Person(name) } } var man = new Person("mike"), women = Person("kitty"); console.log(man.name, women.name); // mike kitty
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/106174.html
摘要:變量有兩種不同的數(shù)據(jù)類型基本類型,引用類型。知識(shí)一基本類型值就是簡(jiǎn)單的數(shù)據(jù)段引用類型值保存的是對(duì)象的引用,不是實(shí)際的對(duì)象。 ECMAScirpt 變量有兩種不同的數(shù)據(jù)類型:基本類型,引用類型。 基本的數(shù)據(jù)類型有:undefined,boolean,number,string,null. 基本類型的訪問(wèn)是按值訪問(wèn)的,就是說(shuō)你可以操作保存在變量中的實(shí)際的值。JavaScript中除了上面的...
摘要:從原型對(duì)象指向構(gòu)造函數(shù)畫一條帶箭頭的線。線上標(biāo)注,表示該原型對(duì)象的構(gòu)造函數(shù)等于。但除此之外,若構(gòu)造函數(shù)所指的顯示原型對(duì)象存在于的原型鏈上,結(jié)果也都會(huì)為。執(zhí)行構(gòu)造函數(shù),并將指針綁定到新創(chuàng)建的對(duì)象上。 做前端開發(fā)有段時(shí)間了,遇到過(guò)很多坎,若是要排出個(gè)先后順序,那么JavaScript的原型與對(duì)象絕對(duì)逃不出TOP3。 如果說(shuō)前端是海,JavaScript就是海里的水 一直以來(lái)都想寫篇文章梳理...
原型與原型鏈理解 1. 什么是原型 JavaScript是一種簡(jiǎn)易的腳本語(yǔ)言,其是由對(duì)象構(gòu)成。每一個(gè)JavaScript對(duì)象(除null外)都和另一個(gè)對(duì)象相關(guān)聯(lián),另一個(gè)對(duì)象就是原型。也就是說(shuō),任何一個(gè)對(duì)象都有原型這個(gè)屬性。 隱式原型(_proto_):上面說(shuō)的這個(gè)原型是JavaScript中的內(nèi)置屬性[[prototype]],此屬性繼承自object對(duì)象,在腳本中沒有標(biāo)準(zhǔn)的方式訪問(wèn)[[pro...
摘要:對(duì)象詳解對(duì)象深度剖析,深度理解對(duì)象這算是醞釀很久的一篇文章了。用空構(gòu)造函數(shù)設(shè)置類名每個(gè)對(duì)象都共享相同屬性每個(gè)對(duì)象共享一個(gè)方法版本,省內(nèi)存。 js對(duì)象詳解(JavaScript對(duì)象深度剖析,深度理解js對(duì)象) 這算是醞釀很久的一篇文章了。 JavaScript作為一個(gè)基于對(duì)象(沒有類的概念)的語(yǔ)言,從入門到精通到放棄一直會(huì)被對(duì)象這個(gè)問(wèn)題圍繞。 平時(shí)發(fā)的文章基本都是開發(fā)中遇到的問(wèn)題和對(duì)...
摘要:由構(gòu)造函數(shù)返回的對(duì)象就是表達(dá)式的結(jié)果。如果構(gòu)造函數(shù)沒有顯式返回一個(gè)對(duì)象,則使用步驟創(chuàng)建的對(duì)象。運(yùn)算符返回一個(gè)布爾值,表示對(duì)象是否為某個(gè)構(gòu)造函數(shù)的實(shí)例。 面向?qū)ο?本人能力有限,有誤請(qǐng)斧正 本文旨在復(fù)習(xí)面向?qū)ο?不包含es6) 本文學(xué)習(xí)思維 創(chuàng)建對(duì)象的方式,獲取對(duì)象屬性 構(gòu)造函數(shù),構(gòu)造函數(shù)的new 做了什么 原型與原型對(duì)象 原型鏈 繼承(借用構(gòu)造繼承、原型繼承、組合繼承、寄生組合繼承)...
閱讀 2458·2021-11-19 09:40
閱讀 3586·2021-11-17 17:08
閱讀 3784·2021-09-10 10:50
閱讀 2214·2019-08-27 10:56
閱讀 1942·2019-08-27 10:55
閱讀 2638·2019-08-26 12:14
閱讀 994·2019-08-26 11:58
閱讀 1494·2019-08-26 10:43