検索
ホームページウェブフロントエンドjsチュートリアル見落とされやすい JavaScript 面接の質問に対する 7 つの質問と回答_JavaScript スキル

この質問は、私が尋ねた一連のフロントエンド面接の質問の最後の質問であり、面接官の包括的な JavaScript 能力をテストするために使用されています。残念なことに、これまでのところ、この質問に完全に答えることができる人はほとんどいません。多くの面接官が彼を過小評価しているからといって難しいのではありません。

トピックは次のとおりです:

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

//请写出以下输出结果:
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

答えは次のとおりです:

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

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

この質問は、私のこれまでの開発経験と、遭遇したさまざまな JS の落とし穴に基づいています。この質問には、変数定義のプロモーション、このポインターの指定、演算子の優先順位、プロトタイプ、継承、グローバル変数の汚染、オブジェクト属性とプロトタイプ属性の優先順位など、多くの知識ポイントが含まれます。

この質問には 7 つの質問が含まれています。以下で説明してください。

最初の質問

まず、この質問の前半で何が行われたかを見てみましょう。まず、Foo という関数を定義し、次に Foo 用の getName という静的プロパティを作成して匿名関数を保存し、次に新しいプロトタイプ オブジェクトを作成しました。 Foo。getName という名前の匿名関数。次に、関数変数式を通じて getName 関数が作成され、最後に getName 関数が宣言されます。

最初の質問 Foo.getName は、当然ながら Foo 関数に格納されている静的プロパティにアクセスします。これは当然 2 です。言うことはありません。

2 番目の質問

2 番目の質問は、getName 関数を直接呼び出すことです。直接呼び出しているため、上記の現在のスコープにある getName という関数にアクセスしているため、1 2 3 とは関係ありません。この質問に対して多くの面接官は5と答えました。ここには 2 つの落とし穴があります。1 つは変数宣言の昇格、もう 1 つは関数式です。

1. 変数宣言の改善

つまり、宣言された変数または関数はすべて、現在の関数の先頭に昇格されます。

たとえば、次のコード:

console.log('x' in window);//true
var x;
x = 0;

コードが実行されると、JS エンジンは宣言ステートメントをコードの先頭に上げ、次のようになります:

var x;
console.log('x' in window);//true
x = 0;

2. 関数式

var getName と function getName はどちらも宣言ステートメントです。違いは、var getName が関数式であるのに対し、function getName は関数宣言であることです。 JS でさまざまな関数を作成する方法の詳細については、ほとんどの人が間違える古典的な JS クロージャーの面接の質問を参照してください。この記事には詳細な説明が記載されています。

関数式の最大の問題は、js がこのコードを 2 行のコードに分割し、別々に実行することです。

たとえば、次のコード:

console.log(x);//输出:function x(){}
var x=1;
function x(){}

実際に実行されるコードは、まず var x=1 を var x; と x = 1; の 2 行に分割し、次に var x と function x(){} を先頭に置きます。

var x;
function x(){}
console.log(x);
x=1;

つまり、最後の関数で宣言された x は変数で宣言された x をカバーし、ログ出力は x 関数になります。

同様に、元の質問のコードの最終実行は次のとおりです:

function Foo() {
 getName = function () { alert (1); };
 return this;
}
var getName;//只提升变量声明
function getName() { alert (5);}//提升函数声明,覆盖var的声明

Foo.getName = function () { alert (2);};
Foo.prototype.getName = function () { alert (3);};
getName = function () { alert (4);};//最终的赋值再次覆盖function getName声明

getName();//最终输出4

第三問

第三個問的 Foo().getName(); 先執行了Foo函數,然後呼叫Foo函數的回傳值物件的getName屬性函數。

Foo函數的第一句  getName = function () { alert (1); };  是一個函數賦值語句,注意它沒有var聲明,所以先向當前Foo函數作用域內尋找getName變量,沒有。接著向目前函數作用域上層,也就是外層作用域內尋找是否含有getName變量,找到了,也就是第二問中的alert(4)函數,將此變數的值賦值為function(){alert(1) }。

此處實際上是將外層作用域內的getName函數修改了。

注意:此處若依然沒有找到會一直向上查找到window對象,若window對像中也沒有getName屬性,就在window對像中創建一個getName變數。

之後Foo函數的回傳值是this,而JS的this問題部落格園中已經有非常多的文章介紹,這裡不再多說。

簡單的講,this的指向是由所在函數的呼叫方式決定的。而此處的直接呼叫方式,this指向window物件。

遂Foo函數回傳的是window對象,相當於執行 window.getName() ,而window中的getName已經被修改為alert(1),所以最後會輸出1

此處檢視了兩個知識點,一個是變數作用域問題,一個是this指向問題。

第四問

直接呼叫getName函數,相當於 window.getName() ,因為這個變數已經被Foo函數執行時修改了,遂結果與第三問相同,為1

第五問

第五問 new Foo.getName(); ,此處考察的是js的運算子優先權問題。

透過查上表可以得知點(.)的優先權高於new操作,遂相當於是:

new (Foo.getName)();
所以實際上將getName函式當作了建構子來執行,遂彈出2。

第六問

第六問 new Foo().getName() ,首先看運算子優先權括號高於new,實際執行為

(new Foo()).getName()
遂先執行Foo函數,而Foo此時作為建構函數卻有回傳值,所以這裡要說明下js中的建構函數回傳值問題。

建構函式的回傳值

在傳統語言中,建構子不應該有回傳值,實際執行的回傳值就是此建構函式的實例化物件。

而在js中建構函式可以有回傳值也可以沒有。

1、沒有回傳值則按照其他語言一樣傳回實例化物件。

2、若有回傳值則檢查其回傳值是否為引用型別。 如果是非引用型別,如基本型別(string,number,boolean,null,undefined)則與無回傳值相同,實際傳回其實例化物件。

3、若回傳值是引用型,則實際回傳值為這個引用型別。

原題中,返回的是this,而this在建構函數中本來就代表當前實例化對象,遂最終Foo函數返回實例化對象。

之後呼叫實例化物件的getName函數,因為在Foo建構子中沒有為實例化物件添加任何屬性,遂到當前物件的原型物件(prototype)中尋找getName,找到了。

遂最終輸出3。

第七問

第七問, new new Foo().getName(); 同樣是運算子優先權問題。

最終實際執行為:

new ((new Foo()).getName)();
先初始化Foo的實例化對象,然後將其原型上的getName函數作為建構子再次new。

遂最終結果為3

最後

就答案狀況而言,第一問100%都可以回答正確,第二問大概只有50%正確率,第三問能回答正確的就不多了,第四問再正確就非常非常少了。其實此題並沒有太多刁鑽匪夷所思的用法,都是一些可能會遇到的場景,而大多數人但凡有1年到2年的工作經驗都應該完全正確才對。

只能說有些人太急躁太輕視了,希望大家透過此文了解js一些特性。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
es6数组怎么去掉重复并且重新排序es6数组怎么去掉重复并且重新排序May 05, 2022 pm 07:08 PM

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

JavaScript的Symbol类型、隐藏属性及全局注册表详解JavaScript的Symbol类型、隐藏属性及全局注册表详解Jun 02, 2022 am 11:50 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

原来利用纯CSS也能实现文字轮播与图片轮播!原来利用纯CSS也能实现文字轮播与图片轮播!Jun 10, 2022 pm 01:00 PM

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

JavaScript对象的构造函数和new操作符(实例详解)JavaScript对象的构造函数和new操作符(实例详解)May 10, 2022 pm 06:16 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

JavaScript面向对象详细解析之属性描述符JavaScript面向对象详细解析之属性描述符May 27, 2022 pm 05:29 PM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

javascript怎么移除元素点击事件javascript怎么移除元素点击事件Apr 11, 2022 pm 04:51 PM

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

整理总结JavaScript常见的BOM操作整理总结JavaScript常见的BOM操作Jun 01, 2022 am 11:43 AM

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。

foreach是es6里的吗foreach是es6里的吗May 05, 2022 pm 05:59 PM

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser は、オンライン試験を安全に受験するための安全なブラウザ環境です。このソフトウェアは、あらゆるコンピュータを安全なワークステーションに変えます。あらゆるユーティリティへのアクセスを制御し、学生が無許可のリソースを使用するのを防ぎます。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 Linux 新バージョン

SublimeText3 Linux 新バージョン

SublimeText3 Linux 最新バージョン