Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

一道题很“基础”的前端笔试题 #30

Open
liangbus opened this issue Mar 28, 2020 · 0 comments
Open

一道题很“基础”的前端笔试题 #30

liangbus opened this issue Mar 28, 2020 · 0 comments

Comments

@liangbus
Copy link
Owner

liangbus commented Mar 28, 2020

昨天在某公众号上看到下面这么一道题,绕来绕去,但是如果基础不够扎实,也很容易掉坑里,像我刚拿到手写了一下答案,再跑一下,发现自己还是有点知识点有所遗漏,所以开一篇来逐步分析,以加强理解

题目

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();

这一题咋一看,说实话,单词就这么几个,但考察的知识点却很多:全局属性,变量提升,原型属性,继承,函数声明等等

Foo.getName();

结果 alert(2)

Foo 是一个函数,因为后续有给函数声明了一个静态属性 Foo.getName,所以其执行结果就是 alert(2),这里要注意的是,正常情况下函数外部是无法访问到函数内部的属性和方法(这属性私有属性和方法),所以这里不会是 alert(1).
另外有些人可能会被 Foo.prototype.getName 这里给误导了,纠结其会不会覆盖上面的属性,实际上这里声明的是公共方法/属性,通过 Foo.getName 是无法访问到的,除非声明在 proto 上面,实际结果可以自己测试一下。

getName();

结果 alert(4)
这里直接调用 getName 方法,前面没有对象,因些是全局调用,因此我们只需要关心声明在 window 下的 getName 方法,如下

var getName = function () { alert (4);};
function getName() { alert (5);}

这里考察的是 var 关键字的声明提升和函数声明的优先级

函数会首先被提升,然后才是变量 —— 《你不知道的 JavaScript 上卷》

所以这里经过浏览器的预处理,变成

function getName() { alert (5);}
var getName = function () { alert (4);};

alert(5) 会被提升到最高,然后才到 var 关键字声明,再赋值,所以 alert(4) 会覆盖 alert(5)

拓展

console.log(foo)
function foo() {
    return 333
}
var foo = 123

foo // ???

这里可以看到,如果函数更高优先级,那么 var 再声明的话, foo 是不是应该是 undefined ?

事实并不是

foo
ƒ foo() {
    return 333
}

函数提升优先级比变量提升要高,且不会被变量声明覆盖,但是会被变量赋值覆盖。

Foo().getName();

结果

alert(1)

说实话,这里我一开始也是做错了,我认为是 alert(4),当时没发现,Foo 函数里面的 getName 是不带 var 关键字的,所以是相当于覆盖全局的 getName,return this 这里的 this 指的是全局 window。(更多关于this 的介绍,可以查看《你不知道的 JavaScript 上卷》,里面用了两个章节去说明,很详细)

getName();

这里跟之前的一个调用一样,但是因为上面一个执行,导致全局的 getName 被覆盖了,所以输出跟上面一样

new Foo.getName();

结果

alert(2)

以 Foo.getName 作为构造函数实例化,前面我们知道 Foo.getName 是什么,所以 new 就直接把它执行一遍了

new Foo().getName();

结果

alert(3)

这里比上面的多了一个括号,如果不知道 new 运算符的优先级的话,这里很可能就答不对,实际上是 (new Foo()).getName() 这样的运算过程,具体可以看这篇 new与属性访问的顺序
这可以看出,先实例化 Foo,然后取其原型上的 getName 方法

new new Foo().getName();

结果

alert(3)

其实觉得这题有点BT,为了考而考吧 = =|| ,直接抄答案吧,还是考察优先级顺序的问题
new ((new Foo()).getName)();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant