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('互动')} // 变量声明提升,但赋值未提升
所以最终 ’ 互动’ 的函数覆盖了 ‘商城’ 的函数。