Je viens de démissionner il y a quelques années et j'aimerais pour partager une de mes questions. Question d'entretien, cette question est la dernière question d'une série de Questions d'entretien frontales que j'ai posées. Malheureusement, dans le cas. Ce n'est pas qu'il soit difficile pour les gens de répondre complètement correctement, c'est juste que la plupart des enquêteurs les sous-estiment.
La question est la suivante :
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();
La réponse est :
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
Cette question est basée sur mon développement précédent, c'est un ensemble d'expériences et de divers pièges JS rencontrés. Cette question implique de nombreux points de connaissance, notamment la promotion de la définition des variables, le pointage de ce pointeur, la priorité de l'opérateur, le prototype, l'héritage, la pollution des variables globales, la priorité des attributs d'objet et des attributs de prototype, etc.
Cette question contient 7 questions, veuillez les expliquer ci-dessous.
Regardons ce qui a été fait dans la première moitié de cette question. Tout d'abord, nous avons défini une fonction appelée Foo, puis avons créé un attribut statique appelé getName pour Foo pour stocker un. Fonction anonyme, puis créez une nouvelle fonction anonyme appelée getName pour l'objet prototype de Foo. Ensuite, une fonction getName est créée via une expression de variable de fonction, et enfin une fonction getName est déclarée.
La première question, Foo.getName, est naturellement d'accéder aux propriétés statiques stockées sur la fonction Foo, qui est naturellement 2. Il n'y a rien à dire.
Deuxième question, appelez directement la fonction getName. Puisqu'il est appelé directement, il accède à la fonction appelée getName dans la portée actuelle ci-dessus, cela n'a donc rien à voir avec 1 2 3. De nombreux enquêteurs ont répondu à cette question par 5. Il y a deux pièges ici, l'un est la promotion de la déclaration de variable et l'autre est l'expression de la fonction.
C'est-à-dire que toutes les variables déclarées ou fonctions déclarées seront promues en haut de la fonction actuelle.
Par exemple, le code suivant :
console.log('x' in window);//true var x;
x = 0;
Lorsque le code est exécuté, le moteur js lèvera la déclaration en haut du code, en changeant For :
var x; console.log('x' in window);//true x = 0;
var getName et function getName sont toutes deux des instructions de déclaration, la différence est que var getName est une expression de fonction et que la fonction getName est une déclaration de fonction. Pour plus de détails sur la façon de créer diverses fonctions dans JS, consultez l'article « Questions d'entretien de clôture JS classiques que la plupart des gens posent par erreur ».
Le plus gros problème avec les expressions de fonction est que js divisera ce code en deux lignes de code et les exécutera séparément.
Par exemple, le code suivant :
console.log(x);//输出:function x(){} var x=1; function x(){}
Le code réellement exécuté est, d'abord divisé var x=1 en var x ; et x = 1; deux lignes, puis montez les deux lignes var x; et function x(){} vers le haut pour devenir :
var x; function x(){} console.log(x); x=1;
Donc, le x déclaré par la fonction finale couvre le x déclaré par la variable, et la sortie du journal est la fonction x.
De même, l'exécution finale du code dans la question d'origine est :
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
Non. Foo().getName(); de Sanwen exécute d'abord la fonction Foo, puis appelle la fonction d'attribut getName de l'objet de valeur de retour de la fonction Foo.
La première phrase de la fonction Foo getName = function () { alert (1 }); Notez qu'elle n'a pas de déclaration var, recherchez donc d'abord la variable getName dans. la portée actuelle de la fonction Foo. Il n'y a pas de . Regardez ensuite la couche supérieure de la portée de la fonction actuelle, c'est-à-dire la portée externe, pour voir si elle contient la variable getName. Nous l'avons trouvée, qui est la fonction alert(4) dans la deuxième question. variable à function(){alert(1) }.
Voici en fait la modification de la fonction getName dans la portée externe.
Remarque : s'il n'est toujours pas trouvé ici, il recherchera jusqu'à l'objet window. S'il n'y a pas d'attribut getName dans l'objet window, créez une variable getName dans l'objet window. .
La valeur de retour de la fonction Foo est la suivante, et il existe déjà de nombreux articles sur ce problème dans le blog JS, je n'entrerai donc pas plus en détail ici.
Pour faire simple, l'intérêt de ceci est déterminé par la méthode d'appel de la fonction. Dans la méthode d'appel direct ici, cela pointe vers l'objet window.
Ensuite, la fonction Foo renvoie l'objet window, ce qui équivaut à exécuter window.getName(), et le getName dans la fenêtre a été modifié en alert(1), donc il finira par afficher 1
Ceci Deux points de connaissance ont été étudiés ici, l'un est le problème de la portée variable et l'autre est le problème de ce pointage.
Appelez directement la fonction getName, ce qui équivaut à window.getName(). Parce que cette variable a été modifiée par la fonction Foo lors de son exécution, le résultat est le. identique à la troisième question, qui est 1
La cinquième question new Foo.getName( ); voici la question de la priorité de l'opérateur de js.
priorité de l'opérateur js :
Lien de référence : http://www.php.cn/
En recherchant le tableau It on peut savoir que la priorité du point (.) est supérieure à la nouvelle opération, ce qui équivaut à :
new (Foo.getName)();
Donc la fonction getName est en fait utilisé comme constructeur à exécuter, puis 2 apparaît.
第六问 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一些特性。
并祝愿大家在新的一年找工作面试中胆大心细,发挥出最好的水平,找到一份理想的工作。
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!