一道 javascript 面试题求教

2019-06-11 15:21:10 +08:00
 noviceiOS

这里有一道面试题:

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(); // 2 
   getName(); // 4
   Foo().getName(); //1 ? 4 ? 2 ?报错   
   getName(); // ?    1
   new Foo.getName(); //  2
   new Foo().getName(); // 3
   new new Foo().getName(); // 3

求问最后三个结果是怎么出来的,谢谢各位了。

4810 次点击
所在节点    JavaScript
32 条回复
czzhengkw
2019-06-11 17:11:21 +08:00
new Foo.getName() => 2
把 Foo.getName 当作构造函数执行

new Foo().getName() => 3
拆成两步:
var foo = new Foo() => 实例化一个 Foo
foo.getName() => 调用原型链上的 getName 方法

new new Foo().getName();
拆成两步:
var foo = new Foo() => 实例化一个 Foo
new foo.getName() => 把原型链上的 getName 方法当作构造函数执行

执行下面这条语句就可以验证了
console.log(new new Foo().getName() instanceof Foo.prototype.getName)
czzhengkw
2019-06-11 17:16:25 +08:00
var a = 1;
(function a(){
a = 2;
console.log(a)})()

a=2 是全局作用域的变量
当 console.log(a)的时候,会先在立即执行函数 a 的作用域里面找 a,如果找不到的话,就找上一层的作用域,即全局作用域

但是它在函数 a 的作用里找到了 a,即函数 a,所以把函数 a 打印了出来
noviceiOS
2019-06-11 17:20:37 +08:00
@czzhengkw

a=2 为什么是全局作用域的变量啊?
wly19960911
2019-06-11 17:22:27 +08:00
@czzhengkw #2 但是调试的时候,你发现 console.log(a)里面的 a 还是 number 值

palmers
2019-06-11 17:24:48 +08:00
@wly19960911 那时候还没有执行 当然是 1
littleylv
2019-06-11 17:27:48 +08:00
实际工作中这么写的人坟头草已经好几米高了
palmers
2019-06-11 17:29:16 +08:00
@wly19960911 对不起 我看错了 我这边也没有复现你这种情况呢?为什么
palmers
2019-06-11 17:31:16 +08:00
@wly19960911 我非常怀疑你的断点还没有进入匿名函数体 只是在外层
YuxiangLuo
2019-06-11 17:34:25 +08:00
第二条 V 站之前讨论过,也没有看到权威解释。可以看看我的研究过程(不保证正确) https://yux.me/p/8
justyeh
2019-06-11 17:35:31 +08:00
Foo.getName();
执行函数的静态方法,输出 2

getName();
重点在于两种声明函数的方法的区别
解析器会先读取函数声明( console.log("5")),并使其在执行任何代码之前可以访问,在任何地方调用都不会有问题;
而函数表达式( console.log("4"))则必须等到解析器执行到它所在的代码行才会真正被执行,提前调用会报错。
这里输出 4

Foo().getName();
执行 Foo 方法导致 window 上的(没有作用域限制,默认是 window ) getName 函数被重新定义
返回的 this 的值取决于执行的位置,此时返回 window,
执行 window.getName()返回 1

getName();
即执行 window.getName(),结果同上

new Foo.getName();
这里我也解释不清楚,调试了一下,和执行属性有关
Foo.getName()先与 new 关键字执行,相当于 new 对象的静态方法
返回 2

new Foo().getName();
在 js 中,对象在调用一个方法时会首先在自身里寻找是否有该方法(对象方法),若没有,则去原型链(原型方法)上去寻找,依次层层递进
这里没有对象方法,执行原型方法,返回 3

new new Foo().getName();
请赐教

PS:以前特意研究过这玩意儿,结果还是忘记了不少,话说面试考这个有那么大意义吗,毕竟可以背下来的东西
kyuuseiryuu
2019-06-11 17:36:10 +08:00
JS 这东西贼玄学,这些花里胡哨的东西了解一下就好了,掌握这么深怕你要么炫技到处写坑爹代码、要么接盘改别人坑爹代码。

JS 啥都好,就这些玩意儿令人诟病。

现实中谁要是这么写,头都要给人剁掉。
wly19960911
2019-06-11 17:36:37 +08:00
@palmers #8 进肯定进了,我确定下浏览器版本问题,
strcmp
2019-06-11 17:37:53 +08:00
做这种题简直是毒瘤
xiangyuecn
2019-06-11 17:38:26 +08:00
append 那段我居然没看懂😂 a=2 这句的这个 a 到底是谁😒???

不过:要是工作中经常会写出题目里面这些代码的人,bug 一定多(不通过运行来检查代码总有一天会被活活绕死)。反观不怎么写这种代码的人 bug 不一定会多。

题外话:虽然代码逻辑性很强,真的强。但命名啊,为什么非要挤着用一个名字?故意写 bug😂

番外篇:论学会合理命名的重要性。
wly19960911
2019-06-11 17:39:27 +08:00
@palmers 换了 49 版本(我们自己的测试版本)
var a = 1;
(function a(){
a = 2;
console.log(a);debugger})()

这段代码断点之后,a 仍旧是 1,什么鬼.....
palmers
2019-06-11 17:49:22 +08:00
@wly19960911 变量的问题 你把函数名改一下
xiangyuecn
2019-06-11 17:50:26 +08:00
#14 配幅图😕

iccfish
2019-06-11 17:56:44 +08:00
Javascript: 我有一百种方法能把你玩死
czzhengkw
2019-06-11 17:59:38 +08:00
@noviceiOS 我想得太简单了
xiangyuecn
2019-06-11 18:02:39 +08:00
#14 加 "use strict"; 就原形毕露了,原来 js 对这种写法自己都看下过去了。。😁😁😁

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/572816

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX