亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

一道超經(jīng)典js面試題Foo.getName()的故事

 更新時間:2022年03月23日 11:03:10   作者:李心一  
Foo.getName算是一道比較老的面試題了,大致百度了一下在17年就有相關文章在介紹它,下面這篇文章主要給大家介紹了關于一道超經(jīng)典js面試題Foo.getName()的相關資料,需要的朋友可以參考下

下面是一道超經(jīng)典的JS面試題。

蘊含了靜態(tài)屬性與實例屬性,變量提升,this指向,new一個函數(shù)的過程

function Foo() {
    getName = function () {
        console.log(1);
    };
    return this;
};
Foo.getName = function () {
    console.log(2);
};
Foo.prototype.getName = function () {
    console.log(3);
};
var getName = function () {
    console.log(4);
};
function getName() {
    console.log(5);
};

Foo.getName(); 
getName(); 
Foo().getName(); 
getName(); 
new Foo.getName();
new Foo().getName();
new new Foo().getName(); 

輸出一下結果

Foo.getName(); //2
getName(); //4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName(); //3
new new Foo().getName(); //3

一、解析:

1.Foo.getName()

我們先看此題的上半部分做了什么,首先定義了一個叫Foo的函數(shù),之后為Foo創(chuàng)建了一個叫getName的靜態(tài)屬性存儲了一個匿名函數(shù),之后為Foo的原型對象新創(chuàng)建了一個叫getName的匿名函數(shù)。之后又通過函數(shù)變量表達式創(chuàng)建了一個getName的函數(shù),最后再聲明一個叫getName函數(shù)。

第一問的 Foo.getName 自然是訪問Foo函數(shù)上存儲的靜態(tài)屬性,自然是2

二、解析:

2.getName()

為何輸出是4,這里考的是變量提升與函數(shù)聲明提升。我們知道使用var聲明變量會存在變量提升的情況,比如下面的例子中,即使在聲明前使用變量a也不會報錯,舉例:

console.log(a)// undefined
var a = 1;
console.log(a)// 1

因為聲明提前會讓聲明提升到代碼的最上層,而賦值操作停留在原地,所以上面代碼等同于:

var a
console.log(a)// undefined
a = 1;
console.log(a)// 1

而函數(shù)聲明(注意是函數(shù)聲明,不是函數(shù)表達式或者構造函數(shù)創(chuàng)建函數(shù))也會存在聲明提前的情況,即我們可以在函數(shù)聲明前調用函數(shù):

fn() // 1
function fn() {
    console.log(1);
};
fn() // 1

//因為函數(shù)聲明提前,導致函數(shù)聲明也會被提到代碼頂端,所以等同于
function fn() {
    console.log(1);
};
fn() // 1
fn() // 1

那這樣就存在一個問題了,變量聲明會提升,函數(shù)聲明也會提升,誰提升的更高呢?在你不知道的JavaScript中明確指出,函數(shù)聲明會被優(yōu)先提升,也就是說都是提升,但是函數(shù)比變量提升更高,所以題目中的兩個函數(shù)順序可以改寫成:

function getName() {
    console.log(5);
};

var getName;

getName = function () {
    console.log(4);
};

這樣就解釋了為什么是輸出4。

三、解析:

3.Foo().getName()

其實可以看出來,我們在執(zhí)行Foo()函數(shù)的時候getName這個變量提升到外部的全局作用域中了,因為在js中,如果對于一個變量沒用用var 或者 let等聲明的話,他就默認是全局屬性,就是window對象的一個屬性。所以在這里我們的全局的getName又被改了

因為我們Foo()執(zhí)行的時候返回了this而這里的this就是window對象 我們需要知道的是在瀏覽器中所有全局的聲明都是window對象的屬性和方法,所以這里我們調用this.getName()就會返回1了。

四、解析:

4.getName()

這里輸出1已經(jīng)毫無懸念,上一分析中,getName的值在Foo執(zhí)行時被修改了,所以再調用getName一樣等同于window.getName(),同樣是輸出1。

五、解析:

5.new Foo.getName()

首先還是先看運算符優(yōu)先級吧,我自個看完的結果是【new Foo() > Foo() > new Foo】,先運算方式2的Foo.getName() 結果為“2”,再new一個Foo實例對象,因此這里new的過程就相當于單純把Foo.getName執(zhí)行了一遍輸出2。

六、解析:

6.new Foo().getName()

這里考了new基本概念,首先這個調用分為兩步,第一步new Foo()得到一個實例,第二步調用實例的getName方法。

我們知道new一個構造函數(shù)的過程大致為,以構造函數(shù)原型創(chuàng)建一個對象(繼承原型鏈),調用構造函數(shù)并將this指向這個新建的對象,好讓對象繼承構造函數(shù)中的構造器屬性,如果構造函數(shù)沒有手動返回一個對象,則返回這個新建的對象。

所以在執(zhí)行new Foo()時,先以Foo原型創(chuàng)建了一個對象,由于Foo.prototype上事先設置了一個getName方法(輸出3的那個),所以這個對象可通過原型訪問到這個方法,其次由于Foo內(nèi)部也沒提供什么構造器屬性,最終返回了一個this(這個this指向實例),因此這里的this還是等同于我們前面概念提到的以Foo原型創(chuàng)建的對象,可以嘗試輸出這個實例,除了原型上有一個getName方法就沒有其它任何屬性,因此這里輸出3。

七、解析:

7.new new Foo().getName()

相當于new(new Foo().getName())

先執(zhí)行new Foo().getName()由6部知道了輸出3,再創(chuàng)建Foo.prototype.getName()的實例返回。結果為3

總結

到此這篇關于js面試題Foo.getName()的文章就介紹到這了,更多相關js面試題Foo.getName()內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論