一些出乎意料的题及面试题的积累
变量提升
1 | if (!"abc" in window) { |
闭包
1 | for (var i = 0; i < liListlength; i++) { |
1 | function fun(n, o) { |
综合(1)
1 | function Foo() { |
首先定义了一个叫 Foo 的函数,然后为 Foo 创建了一个叫 getName 的静态属性存储了一个匿名函数,之后为 Foo 的原型对象创建了一个叫 getName 的匿名函数。之后又通过函数变量表达式创建了一个 getName 的函数,最后声明一个叫做 getName 函数。
Foo.getName();
答案: 2
Foo.getName()访问的 Foo 函数上存储的静态属性
1 | function User(name) { |
注意以下几点:
- 调用公有方法,公有属性,我们必须要实例化对象,也就是用 new 操作符实例化对象,就可构造函数实例化对象的方法和属性,并且公有方法是不能调用私有方法和静态方法的。
- 静态方法和静态属性就是我们无需实例化就可以调用。
- 而对象的私有方法和属性,外部是不可以访问的。
getName()
答案是 4
直接调用 getName 函数。既然是直接调用,那么就是访问当前作用域内的 getName 的函数,所以这里应该是 4 或者 5.这里的坑有,一是变量声明提升,而是函数表达式和函数声明的区别。答案是 4,5 的函数声明被 4 的函数表达式覆盖了。
函数声明与函数表达式
1 |
|
JS 解释器中存在一种变量被提升的机制,也就是说函数声明会被提升到作用域的最前面,即使写在代码的最后面,也会被提升到最前面。
而用函数表达式创建的函数是在运行时被赋值,且要等到表达式赋值完成后才能调用。
Foo().getName()
答案是:1
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 变量。
之后就返回了 this,此时的 this 是指向的 window 对象。所以相当于执行了 window.getName()。
getName()
答案是:1
直接调用 getName 函数,相当于 window.getName(),因为这个变量已经被 Foo 函数执行时修改了,遂结果与第三问相同,为 1,也就是说 Foo 执行后把全局的 getName 函数给重写了一次,所以结果就是 Foo()执行重写的那个 getName 函数
new Foo.getName()
答案是:2
此处考察的是 JS 的运算符优先级的问题。MDN 运算符优先级
- 点的优先级比 new 高 所以 Foo.getName 是一起的.
- 因为有(),因此是 new 有参数列表,new 的有参数列表为 18 比函数调用(17)高 ,所以是 new Foo.getName
- 所以最后是(new Foo.getName)();
- 最后弹出 2
new Foo().getName()
答案是:3
new 的有参数列表跟点的优先级都是 18,同级的话按照从左向右的执行顺序,所以先执行 new 的有参数列表,再执行点的优先级,最后进行函数调用。(new Foo()).getName(); new 之后就调用公用办法,调用原型链上的 getName,因此是 3。
new new Foo.getName()
答案是:3
等同于:new ((new Foo()).getName)();
综合(2)
1 | function Foo() { |
异步和单线程
1 | var a = true; |
由于 js 是一个单线程。所以进入到 while 循环之后,就没有现成去完成定时器,所以这是一个死循环。
JS 赋值
1 | var a = { n: 1 }; |
本人的错误思路:a={n:2}
=>a.x=a
=>a.x={n:2}
- 错误点 1:不考虑其他,也应该是
a={n:2},a.x={n:2}
, - 错误点 2:.的优先级比=高,所以先执行
a.x
,由于 a 引用的{n:1}
=>{n:1,x:undefined}
=> b={n:1,x:undeined}
a.x = a = { n: 2 };
=>{n:1,x:undeined} = a ={ n: 2 }
=>a={n:1};{n:1,x:{n:2}}
- 最重要的一点 3:
a={n:2}
已经改变了引用了地址,然而 a 改变引用地址和 b 并没有任何关系,b 仍然指向的{n:1,x:{n:2}}
所以 a.x = undefined b.x ={n:2}
下面 a 在什么情况下会打印 1
1 | var a = ""; //? |
因为==会进行隐式转化 所以我们重写了 toString 方法就可以
1 | var a = { |
实现(5).add(3).minus(2)=>6;
1 | Number.prototype.add = function(n) { |
实现 promise.all
1 | Promise.all = function(promises) { |