莫方教程网

专业程序员编程教程与实战案例分享

这些前端面试题你答对?(附答案解析)

在三大框架盛行的时代, 基本上会个 Vue 就能在小公司浑水摸鱼。但是当想突破的时候就会意识到基础的重要性。

JavaScript 中有很多重要特性及概念。比如原型,原型链,this,闭包,作用域,隐式转换等等。如果不能熟练掌握,在进阶中级前端开发工程师的道路上必定是困难重重。

用一个小时把这些题做完。检测一下你的基础掌握程度。

正题

1.

if(false){
    var a = 1;
    let b = 2;
}
console.log(a);
console.log(b);

2.

var a = 1;
if(true){
    console.log(a);
    let a = 2;
}

3.

var a = {n: 1}
var b = a
a.x = a = {n: 2}

console.log(a.n, b.n);
console.log(a.x, b.x);

4.

console.log(c);
var c;
function c(a) {
    console.log(a);
    var a = 3;
    function a(){
    }
}
c(2);

5.

var c = 1
function c(c) {
    console.log(c);
    var c = 3;
}
console.log(c);
c(2);

6.

var name = 'erdong';
(function () {
    if (typeof name === 'undefined') {
        var name = 'chen'
        console.log(name)
    } else {
        console.log(name)
    }
})();

7.

var a = 10;  
function test() {  
    a = 100;  
    console.log(a);  
    console.log(this.a);  
    var a;  
    console.log(a); 
}
test();

8.

if (!(a in window)) {
    var a = 1;
}
console.log(a)

9.

var a = 1

function c(a, b) {
    console.log(a)
    a = 2
    console.log(a)
}
c()

10

var val=1;
var obj={
    val:2,
    del:function(){
        console.log(this);                    
        this.val*=2
        console.log(val) 
    }
}

obj.del();

11

var name = "erdong"
var object = {
    name: "chen",
    getNameFunc: function () {
        return function () {
            return this.name;
        }
    }
}
console.log(object.getNameFunc()());

12

var name = "erdong"
var object = {
    name: "chen",
    getNameFunc: function () {
        var that = this;
        return function () {
            return that.name;
        }
    }
}
console.log(object.getNameFunc()());

13

(function() {
  var a = b = 3;
})();
console.log(typeof a === 'undefined');
console.log(typeof b === 'undefined');

14

var a = 6;
setTimeout(function () {
    a = 666;
}, 0)
console.log(a);

15

function fn1() {
    var a = 2
    function fn2 () {
      a++
      console.log(a)
    }
    return fn2
}
var f = fn1()
f()
f()

16

var a = (function(foo){
    return typeof foo.bar;
})({foo:{bar:1}});

console.log(a);

17

function f(){
    return f;
}
console.log(new f() instanceof f);

18

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

19

var F = function(){}
var O = {};
Object.prototype.a = function(){
    console.log('a')
}
Function.prototype.b = function(){
    console.log('b')
}
var f = new F()

F.a();  
F.b();  
O.a();
O.b();

20

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

21

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

22

console.log(typeof NaN === 'number');

23

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

24

var a = 666;
console.log(++a);
console.log(a++);

25

console.log(typeof a);
function a() {}
var a;
console.log(typeof a);

26

var a;
var b = 'undefined';
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);

27

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

28

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

29

console.log('b' + 'a' + +'a'+'a');

30

var obj = {n: 1};
function fn2(a) {
    a.n = 2;
}
fn2(obj);
console.log(obj.n);

31

var x = 10;
function fn() {
    console.log(x);
}
function show(f) {
    var x = 20;
    f();
}
show(fn);

32

Object.prototype.bar = 1; 
var foo = {
    goo: undefined
};

console.log(foo.bar);
console.log('bar' in foo);

console.log(foo.hasOwnProperty('bar'));
console.log(foo.hasOwnProperty('goo'));

33

Object.prototype.bar = 1;

var foo = {
    moo: 2
};
for(var i in foo) {
    console.log(i); 
}

33

function foo1() {
    return {
        bar: "hello"
    };
}
function foo2() {
    return 
    {
        bar: "hello"
    };
}
console.log(foo1());
console.log(foo2());

35

console.log((function(){ return typeof arguments; })());

36

console.log(Boolean(false));
console.log(Boolean('0'));
console.log(Boolean(''));
console.log(Boolean(NaN));

37

console.log(Array(3));

console.log(Array(2,3));

38

console.log(0.1 + 0.2 == 0.3);

39

var a=[1, 2, 3];
console.log(a.join());

40

var a = [3];
var b = [1];
console.log(a - b);

解析

第1题解析

// 输出
undefined

ReferenceError: b is not defined

var 不会产生块级作用域, let 会产生块级作用域。

示例代码相当于:

var a = 1;
if(false){
    a = 1;
    let b = 2;
}
console.log(a); 
console.log(b);

第2题解析

// 输出

ReferenceError: Cannot access 'a' before initialization

let 声明的变量不会提升,并且会产生暂存死区。在 let 声明变量之前访问变量会抛出错误。

第3题解析

// 输出

2 1

undefined {n: 2}
var b = a,此时a和b指向同一个对象。

.运算符比 = 运算符高,先计算`a.x`,此时 
b = {
    n:1,
    x:undefined
}

相当于给对象添加了x属性。

a.x = a = {n:2};

计算完a.x,再计算 = ,赋值是从右向左,此时a指向一个新对象。
a = {
    n:2
}

a.x已经执行过了,此时对象的x属性赋值为a,此时

对象 = {
    n:1,
    x:{
        n:2
    }
}

即:
a = {
    n:2
}

b = {
    n:1,
    x:{
        n:2
    }
}

查看运算符优先级

第4题解析

// 输出 

function c(){
    console.log(a);
    var c = 3;
    function a(){
    }
}

function a(){
}

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

第5题解析

//  输出

1

TypeError: c is not a function

由于函数声明会提升,当函数外的 console.log(c) 执行时, c 已经被赋值为 1 。因此,执行 c(2) 时会抛出 TypeError ,因为 1 不是函数。

第6题解析

// 输出 

chen

自执行函数执行时,会先进行变量提升( 这里涉及到执行上下文不过多说,一定要搞懂执行上下文),在自执行函数执行时,伪代码为:

var name = 'erdong';
(function () {
    var name;  // 变量name会提升到当前作用域顶部
    if (typeof name === 'undefined') {
        name = 'chen'
        console.log(name)
    } else {
        console.log(name)
    }
})();

所以会执行 if 中的 console.log(name)

第7题解析

// 输出

100
10
100

test() 为函数独立调用,作用域中的 this 绑定为全局对象 window 。

test 函数执行时, var a 被提升到了作用域顶部,因此函数作用域中存在一个变量 a 。所以在函数中访问的 a 都是局部作用域中的 a 。

第8题解析

// 输出
undefined

由于 if 后的 {} 不会产生块级作用域(不包含let,const时),此时的伪代码为:

var a;
if (!(a in window)) {
    a = 1;
}
console.log(a);

var a 相当于 window.a 。因此 !(a in window) 转成布尔值为 false ,不会执行 a = 1 。所有 console.log(a) 输出 undefined 。

第9题解析

//输出

undefined 

2

跟第4题类似。

第10题解析

// 输出
obj(指向的值)

1

当通过 obj.del() 调用 del 函数时, del 函数作用域中的 this 绑定为 obj 。

在函数作用域中访问 val 时,由于函数中并没有变量 val ,因此实际上访问的是全局作用域中的 val ,即 1 。

这里考察的是 this 的指向,一定要熟练掌握。

第11题解析

// 输出

erdong

object.getNameFunc()() ,先执行 object.getNameFunc() 返回一个函数:

function () {
    return this.name;
}

返回的函数再执行,相当于

(function () {
    return this.name;
})();

此时的 this 绑定为 window 。因此输出全局变量 name 的值 erdong 。

第12题解析

//输出

chen

object.getNameFunc() 执行时,此时 getNameFunc 中的 this 绑定为 object ,因此 that = object 。 object.getNameFunc() 返回的函数再执行时,产生闭包,因此返回的函数也能访问到外层作用域中的变量 that ,因此 object.name 为 object.name ,即 chen 。

第13题解析

// 输出

true

false

首先要明白 a = b = 3 是怎样执行的,伪代码:

b = 3;
var a = b;

因此在自执行函数执行时, b 由于为经 var 等操作符声明,因为为全局变量。 a 为函数作用域中的变量。因此在外面访问 a 和 b 时,其值分别为 ReferenceError: a is not defined 和 3 。但是 typeof 检测未声明的变量不会抛出错误,会返回 'undefined' 。因此 typeof a 和 typeof b 分别返回 'undefined' 和 'number'

第14题解析

//输出

6

setTimeout 为宏任务。即使设置延迟为 0ms ,也是等待微任务执行完才会执行。因此 console.log(a) 输出 6

第15题解析

// 输出

3
4

由于 fn1 函数执行后返回函数 fn2 ,此时产生了闭包。因此 fn2 中 a 访问的是 fn1 作用域中的变量 a ,因此第一次 a++ ,之后 a 为 3 ,第二次之后 a 为 4 。

第16题解析

//输出

undefined

实参 foo 的值为 {foo:{bar:1} ,因此 typeof foo.bar 为 undefined 。

typeof foo.foo.bar 为 number 。

第17题解析

//输出

false

由于构造函数 f 的返回值为 f 。因此 new f() 的值为 f 。所以 console.log(new f() instanceof f) 为 console.log(f instanceof f) ,即 false 。

第18题解析

// 输出

1,undefined

2,3

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

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 为

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

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

第19题解析

// 输出

a
b
a
TypeError: o.b is not a function

F 为函数,它也能访问 Object 原型上的方法, O 为对象,不能访问 Function 原型上的方法。

F 的原型链为:

F => F.__proto__ => Function.prototype => Function.prototype.__proto__ => Object.prototype

由于 Object.prototype 在 F 的原型链上,所以 F 能访问 Object.prototype 上的属性和方法。即: F.a() , F.b() 能正常访问。

O 的原型链为:

O => O.__proto__ => Object.prototype

由于 Function.prototype 不在 O 的原型链上,因此 O 不能访问 Function.prototype 上的方法,即 O.b() 抛出错误。

如果你对原型和原型链掌握的好,试着理解下面的示例:

console.log(Object instanceof Function);

console.log(Function instanceof Object);

console.log(Function instanceof Function);

第20题解析

// 输出

20
40
10
20
10
30

Person.getAge(); 此时执行的是 Person 函数上 getAge 方法。

Person.getAge = function () {
    console.log(20)
}

所以输出:20。

getAge(); 此时执行的是全局中的 getAge 方法。此时全局 getAge 方法为:

function () {
    console.log(40)
}

所以输出:40。

Person().getAge(); 由于 Person() 单独执行所以,作用域中的 this 绑定为 window ,相当于 window..getAge() 。同上,执行的都是全局 getAge 方法,但是 Person 执行时,内部执行了

getAge = function () {
    console.log(10)
}

因此全局 getAge 方法现在为:

function () {
    console.log(10)
}

所以输出:10。

new Person.getAge(); 此时相当于实例化 Person.getAge 这个函数,伪代码:

var b = Person.getAge;
new b();

所以输出:20

getAge(); 执行全局 getAge 方法,由于在 Person().getAge() 执行时把全局 getAge 方法赋值为:

function () {
    console.log(10)
}

所以输出:10。

new Person().getAge(); 此时调用的是 Person 原型上的 getAge 方法:

Person.prototype.getAge = function () {
    console.log(30)
}

所以输出:30。

这里要注意:1.变量提升及提升后再赋值。2.调用构造函数时,带 () 和不带 () 的区别。

第21题解析

// 输出

'false'
'1,2,3'
Uncaught SyntaxError: Invalid or unexpected token
'5'

当执行 1.toString(); 时,由于 1. 也是有效数字,因此此时变成 (1.)toString() 。没有用 .调用 toString 方法,因此抛出错误。

正确的应该是:

1..toString();
1 .toString();
(1).toString();

第22题解析

//输出

true

NaN 为不是数字的数字。虽然它不是数字,但是它也是数字类型。

第23题解析

//输出

'122'
'32'
'02'
'112'
'NaN2'
NaN

首先要明白两点:

  1. +a ,会把 a 转换为数字。 -a 会把 a 转换成数字的负值(如果能转换为数字的话,否则为 NaN)。
  2. 字符串与任何值相加都是字符串拼接。

console.log(1 + "2" + "2"); 简单的字符串拼接,即结果为: '122' 。

console.log(1 + +"2" + "2"); 这里相当于 console.log(1 + 2 + "2"); ,然后再字符串拼接。即结果为: '32' 。

console.log(1 + -"1" + "2"); 这里相当于 console.log(1 + -1 + "2"); ,然后再字符串拼接。即结果为: '02' 。

console.log(+"1" + "1" + "2"); 这里相当于 console.log(1 + "1" + "2"); ,然后再字符串拼接。即结果为: '112' 。

console.log( "A" - "B" + "2"); ,由于 'A' - 'B' = NaN ,所以相当于 console.log( NaN + "2"); , 然后再字符串拼接。即结果为: 'NaN2' 。

console.log( "A" - "B" + 2); 同上,相当于 console.log(NaN + 2) ,由于 NaN +任何值还是 NaN ,即结果为: NaN 。

第24题解析

// 输出

666
668

a++ 先执行取值操作,在执行 +1 。 此时输出 666 ,随后 a 的值变为 667 。

++a 先执行 +1 在执行取值操作。 此时 a 的值为 667 + 1 = 668 。

--a 和 a-- 同理。

使用这类运算符时要注意:

1)这里的 ++ 、 -- 不能用作于常量。比如

1++; // 抛出错误

2)如果 a 不是数字类型,会首先通过 Number(a) ,将 a 转换为数字。再执行 ++ 等运算。

第25题解析

// 输出

'function'
'function'

跟第4题类似。函数会优先于变量声明提前。因此会忽略 var a 。

第26题解析

// 输出
'undefined'
'string'
'undefined'

a 为声明未赋值,默认为 undefined , b 的值为字符串 'undefined' , c 为未定义。

typeof 一个未定义的变量时,不会抛出错误,会返回 'undefined' 。注意 typeof 返回的都是字符串类型。

第27题解析

//输出

1undefined

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

第28题解析

// 输出

'number'

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

第29题解析

// 输出

baNaNa

'b' + 'a' + +'a'+'a' 相当于 'ba' + +'a'+'a' , +'a' 会将 'a' 转换为数字类型,即 +'a' = NaN 。所以最终得到 'ba' + NaN +'a' ,通过字符串拼接,结果为: baNaNa

第30题解析

// 输出

4
2
2

函数传递参数时,如果是基本类型为值传递,如果是引用类型,为引用传递。因此实参 a 和 obj指向对象的一个引用。当执行 a.n ,实际上共同引用的对象修改了,添加了个 n 属性,因此 obj.n为 2 。

第31题解析

// 输出

10

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

第32题解析

//输出

1
true
false
true

in 操作符:检测指定对象(右边)原型链上是否有对应的属性值。

hasOwnProperty 方法:检测指定对象自身上是否有对应的属性值。两者的区别在于 in 会查找原型链,而 hasOwnProperty 不会。

示例中对象 foo 自身上存在 goo 属性,而它的原型链上存在 bar 属性。

通过这个例子要注意如果要判断 foo 上是否有属性 goo ,不能简单的通过 if(foo.goo){} 判断,因为 goo 的值可能为 undefined 或者其他可能隐式转换为false的值。

第33题解析

// 输出

'moo'
'bar'

for...in... 遍历对象上除了 Symbol 以外的可枚举属性,包括原型链上的属性。

第34题解析

// 输出

{ bar: "hello" }

undefined

两个函数唯一区别就是 return 后面跟的值,一个换行一个不换行。

当我们书写代码时忘记在结尾书写 ; 时, JavaScript 解析器会根据一定规则自动补上 ; 。

return
{
    bar: "hello"
}
=> 会被解析成
return;
{
    bar: "hello"
};

因此函数执行后会返回 undefined 。

第35题解析

// 输出

'object'

arguments 为类数组,类型为 object 。因此 typeof arguments = 'object' 。

第36题解析

//输出

false
true
false
fasle

只有下面几种值在转换为布尔值时为 false :

+0,-0,NaN,false,'',null,undefined。

除此之外的值在转换为布尔值的时候全部为 true 。

第37题解析

// 输出

[empty × 3] 

[2,3]

使用 Array() 创建数组时,要注意传入的值的类型和数量。

// 输出

false

第39题解析

//输出

1,2,3

join 方法如果省略参数,默认以 , 分隔。

第40题解析

// 输出

2

在执行 a - b 时, a 和 b 都要转换为数字。首先 a 先转换为字符串, [3] => [3].toString() => '3' ,然后 Number(3) => 3 。 b 同理。因此转换之后为 3 - 1 = 3 。

有想了解更多的小伙伴可以加Q群[链接](点击链接加入群聊【web前端技术交流学习群】:https://jq.qq.com/?_wv=1027&k=V6X6AEMu)里面看一下,应该对你们能够有所帮助。

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言