Fork me on GitHub

m-面试题汇总

整理一些有意思的面试题

1

1
2
3
4
5
6
7
8
9
var a = {
n: 1
};
var b = a;
a.x = a = {
n: 2
};
console.log(a.n, b.n);
console.log(a.x, b.x);

解析

1
2
3
//输出
//2, 1
//undefined {n:2}

1 - ab指向同一对象
2 - .运算符优先级高于=,所以先计算a.x
就是给对象添加新属性x,所以 ab指向的对象{n:1, x:undefined}
3 - 然后计算赋值运算,赋值从右到左,此时a指向一个新对象,a->{ n:2 }
4 - a.x已经执行过了,此时对象的x属性赋值为a,也是指向{ n:2 }
即:
a = {n:2}
b = {n:1,x:{n:2}}

2

1
2
3
4
5
6
7
8
9
console.log(c);
var c;
function c(a) {
console.log(a);
var a = 3;
function a(){
}
}
c(2);

解析

1
2
3
4
5
6
7
8
9
10
//输出
function c(a){
console.log(a);
var a = 3;
function a(){
}
}

function a(){
}

变量提升也有优先级, 函数声明 > arguments > 变量声明。

3

1
2
3
4
5
6
7
8
9
var name = 'Grace';
(function () {
if (typeof name === 'undefined') {
var name = 'John';
console.log(name);
} else {
console.log(name);
}
})();

解析

1
2
//输出
John

自执行函数执行时,会先进行变量提升

1
2
3
4
5
6
7
8
9
10
var name = 'Grace';
(function () {
var name; // 变量name会提升到当前作用域顶部
if (typeof name === 'undefined') {
name = 'John'
console.log(name)
} else {
console.log(name)
}
})();

所以执行的是 if 里面的代码

4

1
2
3
4
5
6
7
8
9
10
var val = 1;
var obj = {
val: 2,
del: function () {
console.log(this);
this.val *= 2;
console.log(val);
}
}
obj.del();

解析

1
2
3
//输出
obj(指向的值)
1

当通过 obj.del()调用 del 函数时,del 函数作用域中的 this 绑定为 obj。
在函数作用域中访问 val 时,由于函数中并没有变量 val,因此实际上访问的是全局作用域中的 val,即 1。

5

1
2
3
4
5
6
7
8
9
10
function A() {}
A.prototype.n = 1;
var b = new A();
A.prototype = {
n: 2,
m: 3
}
var c = new A();
console.log(b.n, b.m);
console.log(c.n, c.m);

解析

1
2
3
//输出
1 undefined
2 3

var b = new A(); 实例化 b 时,A 的 prototype 为

1
2
3
4
A.prototype = {
constructor:A,
n:1
}

当访问 b.n 和 b.m 时,通过原型链找到 A.prototype 指向的对象上,即 b.n = 1,b.m = undefined。
var c = new A(); 实例化 c 时,A 的 prototype 为

1
2
3
4
A.prototype = {
n: 2,
m: 3
}

当访问a.na.m时,通过原型链找到A.prototype指向的对象上,此时A.prototype重写,因此a.n = 2,b.m = 3

6

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
 function Person() {
getAge = function () {
console.log(10)
}
return this;
}
Person.getAge = function () {
console.log(20)
}
Person.prototype.getAge = function () {
console.log(30)
}
var getAge = function () {
console.log(40)
}

function getAge() {
console.log(50)
}
Person.getAge();
getAge();
Person().getAge();
new Person.getAge();
getAge();
new Person().getAge();

解析

1
2
3
4
5
6
7
//输出
20
40
10
20
10
30
  • Person.getAge();,执行Person函数上的getAge方法,=》20
  • getAge();,执行全局函数,由
    变量提升,先是var getAge = undefined,接着function getAge() { console.log(50) }
    赋值,执行到var getAge = function () { console.log(40) }
    =》40

  • Person().getAge();,执行Person函数,显示改变全局函数getAge=>
    function () {console.log(10)}
    然后返回this,这里的this就是window
    所以window.getAge() => 10

  • new Person.getAge();,没有参数的new方法,优先级低于.函数,所以先执行Person.getAge,然后实例化这个函数。

    1
    2
    let b=Person.getAge();
    new b() // =>20
  • getAge();,执行全局函数,=》10

  • new Person().getAge();,先执行new Person()实例化Person,接着执行实例的函数,实例上没有该函数,就会执行原型上的函数,就是Person.prototype.getAge = function () { console.log(30) } =>30

7

1
2
3
4
console.log(false.toString());
console.log([1,2,3].toString());
console.log(1.toString());
console.log(5...toString());

解析

1
2
3
4
5
//输出
'false'
1,2,3
Uncaught SyntaxError: Invalid or unexpected token
'5'

1.toString(),实际是(1.)toString(),点会被认为是浮点数。如果执行(1).toString()结果就是 1。
同理,5..toString(),第一个点是浮点数,第二个点是函数调用

8

1
2
3
4
5
6
console.log(1 + "2" + "2");
console.log(1 + +"2" + "2");
console.log(1 + -"1" + "2");
console.log(+"1" + "1" + "2");
console.log( "A" - "B" + "2");
console.log( "A" - "B" + 2);

解析

1
2
3
4
5
6
7
//输出
'122'
'32'
'02'
'112'
'NaN2'
NaN

重点

  1. +a会把a转换为数字,-a会把a转换成数字的负值(如果不能转换为数字就是NaN
  2. 字符串与任何值相加都是字符串拼接
    1 + -"1" + "2"1+(-1)+'2' => 0+'2' => ‘02’

9

1
2
3
4
5
var x = 1;
if(function f(){}){
x += typeof f;
}
console.log(x);

解析

1
2
//输出
1undefined

function f(){}当做 if 条件判断,其隐式转换后为true。但是在函数参数不会声明提升,因此 f 函数在外部是不存在的。因此typeof f = ‘undefined’,所以 x += typeof f,相当于 x = x + ‘undefined’为'1undefined'

10

1
2
var str = "123abc";
console.log(typeof str++);

解析

1
'number'

使用++运算符时(无论是前置还是后置),如果变量不是数字类型,会首先用Number()转换为数字。因此typeof str++相当于typeof Number(str)++。由于后置的++是先取值后计算,因此相当于 typeof Number('123abc')。即 typeof NaN,所以输出'number'

11

1
2
3
4
5
6
7
8
9
var x = 10;
function fn() {
console.log(x);
}
function show(f) {
var x = 20;
f();
}
show(fn);

解析

1
10

JavaScript采用的是词法作用域,规定了函数内访问变量时,查找变量是从函数声明的位置向外层作用域中查找,而不是从调用函数的位置开始向上查找。

-------------本文结束感谢阅读-------------