以问题开始:
function Base(){}var base = new Base()
上面两行代码会创建几个对象(object)?
要回答这个问题,先明确一下Javascript里object的概念。
Objects
在Javascript里,几乎一切都是object(Arrays、Functions、Numbers、Objects……),而没有C#里的class的概念。object的本质是一个name-value pairs的集合,其中name是string类型的,可以把它叫做“property”,value包括各种objects(string,number,boolean,array,function…),指的是property的值。
typeof
既然object包含Arrays、Functions、Numbers、Objects……,那怎么区分这些呢?答案是typeof。 typeof返回一个字符串,如typeof(Null) = “object”,typeof(false) = “Boolean”, typeof(1) = “number”。既然总是返回字符串,那么对于typeof (typeof x),不管x是什么,总是返回”string”。
Constructor
JS里没有class,也就没有class里的构造函数,那么object是怎么被创建的呢?用构造器:constructor。constructor其实就是Function,因此本身也是object。开头的function Base(){}就是一个构造器,var b = new Base()就是用这个构造器(通过关键字new)创建了一个叫b的object。至此我们可以得出结论,开头的两行代码至少创建了2个object:一个是Base,类型为function的object,一个是base,类型为object的object。
Function()和Object()
这是两个重要的预定义好的构造器。一切function(比如开头的Base())都是由Function()构造出来的;而Object的prototype将会被所有object继承,下面会讲到。
Function的创建过程
当执行function Base(){this.a = 1}时,相当于var Base = new Function(“this.a = 1”),也就是说,这行代码本身,将使用预定义好的Function() constructor,来构造一个function型object(即Base)出来。在这个创建过程中,js将做哪些事呢?
1, 首先当然会创建一个object起来,Base指向这个object。typeof 这个object = “function”
2, 给Base附上__proto__属性,让它等于Function这个构造器的prototype(也是预定义好的)。这是很重要的一步,也是规律性的一步。(规律:)在执行任意类似varx = new X()时,都会把X的prototype赋给x的__proto__,也就是说,x.__proto__和X.prototype此时会指向同一个对象。
3, 为Base创建call属性,该属性是个function。因此我们可以这样写:Base.Call()
4, 为Base创建Construct属性,该属性也是个function。在执行var base = new Base()时,即会调用这个Construct属性。
5, 为Base创建Scope,Length等属性,略。
6, 为Base创建prototype属性:先用new Object()创建一个对象,为这个对象创建一个属性叫constructor,该属性值设置为Base。再把Base的prototype设置为这个新创建的对象。伪代码如下:
<div> <!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> x </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Object();<br>x.constructor </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Base;<br>Base.prototype </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> x;</span> </div>
先把关注点放到2和6。
__proto__和prototype
从2可以看出来,任意一个用构造器构造出来的object(包括Objects和Functions),都会有__proto__属性,指向该构造器的prototype属性。注意__proto__是个私有属性,在IE上是看不到的,我用的是chrome,可以看到。
从6可以看出,任意一个用new Function()构造出来的functions,都会有prototype属性,该属性是用new Object()构建出来的,初始公开属性只有一个constructor。
原型链
再来分析下第6步的伪代码,也就是为function创建prototype的这一步:
<div> <!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> x </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Object(); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 参见2中的规律,会有x.__proto__= Object.prototype。</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">x.constructor </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> Base;<br>Base.prototype </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> x;</span> </div>
此时我们用Base()构造一个对象出来:
<div> <!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> base</span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Base(); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 参见2中的规律,会有base.__proto__ = Base.prototype,也就是 = x。</span> </div><div> <span style="COLOR: #008000"> </span><span style="COLOR: #008000; FONT-FAMILY: 'Courier New'"> // 因此有base.__proto__.__proto__ = x.__proto__</span> </div><div><span style="COLOR: #008000; FONT-FAMILY: 'Courier New'"> // 而x.__proto__ = Object.prototype(见上一个代码片段) </span></div><div><span style="COLOR: #008000; FONT-FAMILY: 'Courier New'"> // 所以,base.__proto__.__proto__ = Object.prototype.</span></div>
__proto__.__proto__,这就是传说中JS对象的原型链!由于用Function()创建构造器时的关键的第6步,保证了所有object的原型链的顶端,最终都指向了Object.prototype。
Property Lookup
而我们如果要读某个object的某个属性,JS会怎么做呢?
比如有个object叫xxx,我们执行alert(xxx.a),也就是读取xxx的a属性,那么JS首先会到xxx本身去找a属性,如果没找到,则到xxx.__proto__里去找a属性,由此沿着原型链往上,找到即返回(没找到,则返回undefined)。可以来看个例子:
上图得知:base本身是没有constructor属性的,但是base.constructor确实能返回Base这个函数,原因就在于base.__proto__有这个属性。(base.__proto__是啥?就是Base.prototype,上面构建Function的第6步的伪代码里,为Base.prototype.constructor赋值为Base本身。)
Object作为“基类”
另外,由于任意object的原型链的顶端都是Object.prototype。所以,Object.prototype里定义的属性,就会通过原型链,被所有的object继承下来。这样,预定义好的Object,就成了所有对象的“基类”。这就是原型链的继承。
看上图,Object.prototype已经预定义好了一些属性,我们再追加一条属性叫propertyA,那么这个属性和预定义属性一样,都可以从base上读到。
原型继承
已经得知,
对于 var xxx =new Object(); 有xxx.__proto__= Object.prototype;
对于 var xxx =new Base(); 有xxx.__proto__.__proto__= Object.prototype;
看上去很像什么呢?从c#角度看,很像Base是Object的子类,也就是说,由Base()构造出来的object,比由Object()构造出来的object,在原型链上更低一个层级。这是通过把Base.prototype指向由Object()创建的对象来做到的。那么自然而然,如果我想定义一个继承自Base的构造器,只需把改构造器的prototype指向一个Base()构造出来的对象。
<div> <!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="COLOR: #0000ff">function</span><span style="COLOR: #000000"> Derived(){}<br></span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> base </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> </span><span style="COLOR: #0000ff">new</span><span style="COLOR: #000000"> Base();<br>Derived.prototype </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> base;<br></span><span style="COLOR: #0000ff">var</span><span style="COLOR: #000000"> d </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> newDerived(); </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">很容易推算出:d.__proto__.__proto__.__proto__ = Object.prototype.</span> </div>
推算过程:d.__proto__指向Derived.prototype,也就是base;则__proto__.__proto__指向base.__proto__,也就是Base.prototype,也就是某个new object()创建出来的东东,假设是o;则__proto__.__proto__.__proto__指向o.__proto__,也就是Object.prototype。
回答开头的问题,以及几个新的问题
那两行代码至少创建了三个对象:Base、base、Base.prototype。顺便说说,base是没有prototype属性的,只有function类型的object,在被构建时才会被创建prototype属性。
d.constructor会返回什么呢?
构造器Base()和Derived()里都是空的,如果有代码,将会怎么被执行呢?
……
待续。见下篇

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver CS6
視覺化網頁開發工具

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),

禪工作室 13.0.1
強大的PHP整合開發環境