Faicso函數問題——JS作用域,原型鍊,變量提升
今天偶然在一個web前端交流群中看到了一道群友分享的JavaScript面試題,感覺有點意思,在此分享下。
本文僅個人觀點,歡迎各位前輩或者小夥伴批評指正錯誤,十分感謝!!
題目:
function Faicso() {
getName = function () { console.log('圖檔') }
return this
}
Faicso.getName = function () { console.log('微傳單')}
Faicso.prototype.getName = function () {console.log('建站')}
var getName = function () {console.log('互動')}
function getName() {console.log('商城')}
// 說說下面的輸出情況
Faicso.getName()
getName()
Faicso().getName()
getName()
new Faicso.getName()
new Faicso().getName()
new new Faicso().getName()
這道題的執行順序很有講究,若是将這七個執行順序調換一下,結果很可能會不同。
輸出結果:
Faicso.getName()//微傳單
getName()// 互動
Faicso().getName() // 圖檔 相當于 window.getName() 但是若是在這裡寫成 window.getName()或 this.getName() 将傳回 '互動'的getName函數
getName() // 圖檔
new Faicso.getName() // 微傳單
new Faicso().getName()// 建站
new new Faicso().getName() // 建站
答案步步詳解
Faicso.getName()
// 微傳單 見題目第五行代碼,為Faicso函數添加getName()方法(在JS中函數也是對象,對象則有屬性和方法)
// 但這裡為Faicso函數直接添加的方法隻能為其本身使用,不能被 new Faicso() 執行個體對象使用
// 要想執行個體對象也能使用 getName()方法的話,需在 Faicso.prototype 上添加此方法(本題有涉及到)
getName()
// 互動 這裡為什麼會是'互動',而不是'商城'或'圖檔'呢?
// 這裡的原因涉及到 變量提升 ,參看下文片段解釋1
Faicso().getName() // 圖檔
// 相當于 window.getName()
// 但是若是在這裡寫成 window.getName()或 this.getName() 将傳回 '互動'的getName函數
// 因為這裡首先調用 執行了Faicso函數,Faicso函數内部又對全局的getName方法重新指派為'圖檔'的函數
getName() // 圖檔
// 因為上一步執行了Faicso函數,為this.getName方法重新指派為'圖檔'的函數,是以這裡再次調用全局的getName方法就會輸出'圖檔'
new Faicso.getName() // 微傳單
// 這裡new 了一個 Faicso.getName()函數的執行個體對象,輸出同調用 Faicso.getName()
new Faicso().getName()// 建站
// 這裡就涉及到了上面提到的 new Faicso()執行個體調用getName()方法
new new Faicso().getName() // 建站
// 這裡是 建立了一個 Faicso()執行個體的getName()方法的執行個體對象
// 而 Faicso()執行個體的getName()方法 同上都是繼承于Faicso.prototype
片段解釋
片段1. getName() // 互動 這裡為什麼會是’互動’,而不是’商城’或’圖檔’呢?
// 這裡的原因涉及到 變量提升
// 原題目代碼
var getName = function () {console.log('互動')}
function getName() {console.log('商城')}
// 相當于 變量提升後的代碼
function getName(){console.log('商城')} // 函數聲明提升 (函數聲明提升優先于變量聲明的提升)
var getName // 變量聲明提升,但指派未提升
getName = function (){console.log('互動')} // 變量聲明提升,但指派未提升
是以最終 ’ 互動’ 的函數覆寫了 ‘商城’ 的函數。