I just resigned a few years ago, and I would like to share one of my questions Interview question, this question is the last question in a set of front-end interview questions that I asked. It is used to assess the interviewer’s comprehensive JavaScript ability. Unfortunately, in the past two years so far, there have been almost no It's not that it's difficult for people to answer completely correctly, it's just that most interviewers underestimate them.
The question is as follows:
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();
The answer is:
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
This question is based on my previous development experience and encounters It is a collection of various pitfalls in JS. This question involves many knowledge points, including variable definition promotion, this pointer pointing, operator priority, prototype, inheritance, global variable pollution, object attribute and prototype attribute priority, etc.
This question contains 7 questions, please explain them separately.
Let’s first look at what is done in the first half of this question. First, a function called Foo is defined, and then a static property called getName is created for Foo to store a Anonymous function, and then create a new anonymous function called getName for Foo's prototype object. Then a getName function is created through a function variable expression, and finally a getName function is declared.
The first question about Foo.getName is naturally to access the static properties stored on the Foo function, which is naturally 2. There is nothing to say.
Second question, call the getName function directly. Since it is called directly, it is accessing the function called getName in the current scope above, so it has nothing to do with 1 2 3. Many interviewers answered this question as 5. There are two pitfalls here, one is variable declaration promotion, and the other is function expression.
That is, all declared variables or declared functions will be promoted to the top of the current function.
For example, the following code:
console.log('x' in window);//true var x;
x = 0;
When the code is executed, the js engine will raise the declaration statement to the top of the code and become:
var x; console.log('x' in window);//true x = 0;
var getName and function getName are both declaration statements. The difference is that var getName is a function expression, while function getName is a function declaration . For details on how to create various functions in JS, see the article "Classic JS Closure Interview Questions Most People Do Mistakenly."
The biggest problem with function expressions is that js will split this code into two lines of code and execute them separately.
For example, the following code:
console.log(x);//输出:function x(){} var x=1; function x(){}
The actual executed code is, first split var x=1 into var x; and x = 1; two lines, and then raise the two lines var x; and function x(){} to the top to become:
var x; function x(){} console.log(x); x=1;
So the final function declaration x covers the x declared by the variable, and the log output is the x function.
Similarly, the final execution of the code in the original question is:
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
The third question The Foo().getName(); first executes the Foo function, and then calls the getName property function of the Foo function's return value object.
The first sentence of the Foo function getName = function () { alert (1); }; is a function assignment statement. Note that it does not have a var declaration, so first look for the getName variable in the scope of the current Foo function. There is no . Then look to the upper layer of the current function scope, that is, the outer scope, to see if it contains the getName variable. We found it, which is the alert(4) function in the second question. Assign the value of this variable to function(){alert(1) }.
Here is actually the getName function in the outer scope that is modified.
Note: If it is still not found here, it will search all the way up to the window object. If there is no getName attribute in the window object, create a getName variable in the window object.
After that, the return value of the Foo function is this, and there are already many articles on the this problem of JS in the blog garden, so I won’t go into more details here.
To put it simply, the point of this is determined by the calling method of the function. In the direct calling method here, this points to the window object.
The Foo function returns the window object, which is equivalent to executing window.getName(), and the getName in the window has been modified to alert(1), so 1
will eventually be output. Two knowledge points were investigated here, one is the variable scope issue, and the other is the this pointing issue.
Directly calling the getName function is equivalent to window.getName(). Because this variable has been modified by the Foo function when it is executed, the result is the same as the third question, which is 1
The fifth question new Foo.getName(); , here is the issue of operator priority of js.
js operator priority:
Reference link: http://www.php.cn/
By looking up the table It can be known that the priority of dot (.) is higher than the new operation, which is equivalent to:
new (Foo.getName)();
So the getName function is actually executed as a constructor , then 2 pops up.
第六问 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一些特性。
并祝愿大家在新的一年找工作面试中胆大心细,发挥出最好的水平,找到一份理想的工作。
The above is the detailed content of Summary of a JavaScript interview question that many front-end programmers often overlook. For more information, please follow other related articles on the PHP Chinese website!