這些前端基礎題你能答對幾道?(測試你的基礎掌握,附答案解析)

在三大框架盛行的時代, 基本上會個Vue就能在小公司渾水摸魚。可是當想突破的時候就會意識到基礎的重要性。前端

JavaScript中有不少重要特性及概念。好比原型,原型鏈,this,閉包,做用域,隱式轉換等等。若是不能熟練掌握,在進階中級前端開發工程師的道路上一定是困難重重。數組

用一個小時把這些題作完。檢測一下你的基礎掌握程度。bash

正題

第 1 題

if(false){
    var a = 1;
    let b = 2;
}
console.log(a);
console.log(b);
複製代碼
查看解析
// 輸出
undefined

ReferenceError: b is not defined
複製代碼

var不會產生塊級做用域,let會產生塊級做用域。閉包

僞代碼至關於:框架

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

第 2 題

var a = 1;
if(true){
    console.log(a);
    let a = 2;
}
複製代碼
查看解析
// 輸出

ReferenceError: Cannot access 'a' before initialization

複製代碼

let聲明的變量不會提高,而且會產生暫存死區。在let聲明變量以前訪問變量會拋出錯誤。函數


第 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);
複製代碼
查看解析
// 輸出

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 題

console.log(c);
var c;
function c(a) {
    console.log(a);
    var a = 3;
    function a(){
    }
}
c(2);
複製代碼
查看解析
// 輸出 

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

function a(){
}
複製代碼

變量提高也有優先級, 函數聲明 > arguments > 變量聲明ui


第 5 題

var c = 1;
function c(c) {
    console.log(c);
    var c = 3;
}
console.log(c);
c(2);
複製代碼
查看解析
//  輸出

1

TypeError: c is not a function

複製代碼

因爲函數聲明會提高,當函數外的console.log(c)執行時,c已經被賦值爲1。所以,執行c(2)時會拋出TypeError,由於1不是函數。this


第 6 題

var name = 'erdong';
(function () {
    if (typeof name === 'undefined') {
        var name = 'chen';
        console.log(name);
    } else {
        console.log(name);
    }
})();
複製代碼
查看解析
// 輸出 

chen

複製代碼

自執行函數執行時,會先進行變量提高(這裏涉及到執行上下文不過多說,必定要搞懂執行上下文),在自執行函數執行時,僞代碼爲:spa

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 題

var a = 10;  
function test() {  
    a = 100;  
    console.log(a);  
    console.log(this.a);  
    var a;  
    console.log(a); 
}
test();  
複製代碼
查看解析
// 輸出

100
10
100
複製代碼

test()爲函數獨立調用,做用域中的this綁定爲全局對象window

test函數執行時,var a被提高到了做用域頂部,所以函數做用域中存在一個變量a。因此在函數中訪問的a都是局部做用域中的a


第 8 題

if (!('a' in window)) {
    var a = 1;
}
console.log(a);
複製代碼
查看解析
// 輸出
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 題

var a = 1;

function c(a, b) {
    console.log(a);
    a = 2;
    console.log(a);
}
c();
複製代碼
查看解析
//輸出

undefined 

2
複製代碼

跟第4題相似。


第 10 題

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

obj.del();
複製代碼
查看解析
// 輸出
obj(指向的值)

1

複製代碼

當經過obj.del()調用del函數時,del函數做用域中的this綁定爲obj

在函數做用域中訪問val時,因爲函數中並無變量val,所以實際上訪問的是全局做用域中的val,即 1

這裏考察的是this的指向,必定要熟練掌握。


第 11 題

var name = "erdong";
var object = {
    name: "chen",
    getNameFunc: function () {
        return function () {
            return this.name;
        }
    }
}
console.log(object.getNameFunc()());
複製代碼
查看解析
// 輸出

erdong
複製代碼

object.getNameFunc()(),先執行object.getNameFunc()返回一個函數:

function () {
    return this.name;
}
複製代碼

返回的函數再執行,至關於

(function () {
    return this.name;
})();
複製代碼

此時的this綁定爲window。所以輸出全局變量name的值erdong


第 12 題

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

複製代碼
查看解析
//輸出

chen
複製代碼

object.getNameFunc()執行時,此時getNameFunc中的this綁定爲object,所以that = objectobject.getNameFunc()返回的函數再執行時,產生閉包,所以返回的函數也能訪問到外層做用域中的變量that,所以object.nameobject.name,即 chen


第 13 題

(function() {
  var a = b = 3;
})();
console.log(typeof a === 'undefined');
console.log(typeof b === 'undefined');
複製代碼
查看解析
// 輸出

true

false
複製代碼

首先要明白var a = b = 3是怎樣執行的,僞代碼:

b = 3;
var a = b;
複製代碼

所以在自執行函數執行時,b因爲未經var等操做符聲明,爲全局變量。a爲函數做用域中的局部變量。所以在外面訪問ab時,其值分別爲ReferenceError: a is not defined3。可是typeof檢測未聲明的變量不會拋出錯誤,會返回'undefined'。所以typeof atypeof b分別返回'undefined''number'


第 14 題

var a = 6;
setTimeout(function () {
    a = 666;
}, 0)
console.log(a);
複製代碼
查看解析
//輸出

6
複製代碼

setTimeout爲宏任務。即便設置延遲爲0ms,也是等待同步代碼執行完纔會執行。所以console.log(a)輸出 6


第 15 題

function fn1() {
    var a = 2;
    function fn2 () {
      a++;
      console.log(a);
    }
    return fn2;
}
var f = fn1();
f();
f();
複製代碼
查看解析
// 輸出

3
4
複製代碼

因爲fn1函數執行後返回函數fn2,此時產生了閉包。所以fn2a訪問的是fn1做用域中的變量a,所以第一次a++,以後a3,第二次以後a4


第 16 題

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

console.log(a);
複製代碼
查看解析
//輸出

undefined
複製代碼

實參foo的值爲{foo:{bar:1},所以typeof foo.barundefined

typeof foo.foo.barnumber


第 17 題

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

複製代碼
查看解析
//輸出

false
複製代碼

因爲構造函數f的返回值爲f。所以new f()的值爲f。因此console.log(new f() instanceof f)console.log(f instanceof f),即 false


第 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);
複製代碼
查看解析
// 輸出

1,undefined

2,3

複製代碼

var b = new A(); 實例化b時,Aprototype

A.prototype = {
    constructor:A,
    n:1
}
複製代碼

當訪問b.nb.m時,經過原型鏈找到A.prototype指向的對象上,即b.n = 1,b.m = undefined

var c = new A(); 實例化c時,Aprototype

A.prototype = {
    n: 2,
    m: 3
}
複製代碼

當訪問a.na.m時,經過原型鏈找到A.prototype指向的對象上,此時A.prototype重寫,所以a.n = 2,b.m = 3


第 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();  
複製代碼
查看解析
// 輸出

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.prototypeF的原型鏈上,因此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 題

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();
複製代碼
查看解析
// 輸出

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 題

console.log(false.toString()); 
console.log([1, 2, 3].toString()); 
console.log(1.toString()); 
console.log(5..toString());
複製代碼
查看解析
// 輸出

'false'
'1,2,3'
Uncaught SyntaxError: Invalid or unexpected token
'5'
複製代碼

當執行1.toString();時,因爲1.也是有效數字,所以此時變成(1.)toString()。沒有用.調用toString方法,所以拋出錯誤。

正確的應該是:

1..toString();
1 .toString();
(1).toString();
複製代碼

第 22 題

console.log(typeof NaN === 'number');
複製代碼
查看解析
//輸出

true
複製代碼

NaN爲不是數字的數字。雖然它不是數字,可是它也是數字類型。


第 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); 
複製代碼
查看解析
//輸出

'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 題

var a = 666;
console.log(++a);
console.log(a++);
console.log(a);
複製代碼
查看解析
// 輸出

667
667
668
複製代碼

++a先執行+1操做,再執行取值操做。 此時a的值爲667。所以輸出667

a++先執行取值操做,再執行+1。 此時輸出667,隨後a的值變爲668

--aa--同理。

使用這類運算符時要注意:

1)這裏的++--不能用做於常量。好比

1++; // 拋出錯誤
複製代碼

2)若是a不是數字類型,會首先經過Number(a),將a轉換爲數字。再執行++等運算。


第 25 題

console.log(typeof a);
function a() {}
var a;
console.log(typeof a);
複製代碼
查看解析
// 輸出

'function'
'function'
複製代碼

跟第4題相似。函數會優先於變量聲明提早。所以會忽略var a


第 26 題

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

複製代碼
查看解析
// 輸出
'undefined'
'string'
'undefined'
複製代碼

a爲聲明未賦值,默認爲undefined,b的值爲字符串'undefined',c爲未定義。

typeof一個未定義的變量時,不會拋出錯誤,會返回'undefined'。注意typeof返回的都是字符串類型。


第 27 題

var x = 1;
if(function f(){}){
    x += typeof f;
}
 
console.log(x);
複製代碼
查看解析
//輸出

1undefined
複製代碼

function f(){}當作if條件判斷,其隱式轉換後爲true。可是在()中的函數不會聲明提高,所以f函數在外部是不存在的。所以typeof f = 'undefined',因此x += typeof f,至關於x = x + 'undefined''1undefined'


第 28 題

var str = "123abc";
console.log(typeof str++);
複製代碼
查看解析
// 輸出

'number'
複製代碼

在24題解析時提到,使用++運算符時(不管是前置仍是後置),若是變量不是數字類型,會首先用Number()轉換爲數字。所以typeof str++至關於typeof Number(str)++。因爲後置的++是先取值後計算,所以至關於typeof Number("123abc")。即typeof NaN,因此輸出'number'


第 29 題

console.log('b' + 'a' + +'a'+'a');
複製代碼
查看解析
// 輸出

baNaNa
複製代碼

'b' + 'a' + +'a'+'a'至關於'ba' + +'a'+'a',+'a'會將'a'轉換爲數字類型,即+'a' = NaN。因此最終獲得'ba' + NaN +'a',經過字符串拼接,結果爲:baNaNa


第 30 題

var obj = {n: 1};
function fn2(a) {
    a.n = 2;
}
fn2(obj);
console.log(obj.n);
複製代碼
查看解析
// 輸出

2
複製代碼

函數傳遞參數時,若是是基本類型爲傳遞,若是是引用類型,爲引用地址的值傳遞。其實都是值傳遞。所以形參aobj引用地址相同,都指向同一個對象。當執行a.n,實際上共同指向的對象修改了,添加了個n屬性,所以obj.n2


第 31 題

var x = 10;
function fn() {
    console.log(x);
}
function show(f) {
    var x = 20;
    f();
}
show(fn);
複製代碼
查看解析
// 輸出

10
複製代碼

JavaScript採用的是詞法做用域,它規定了函數內訪問變量時,查找變量是從函數聲明的位置向外層做用域中查找,而不是從調用函數的位置開始向上查找。所以fn函數內部訪問的x是全局做用域中的x,而不是show函數做用域中的x


第 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'));
複製代碼
查看解析
//輸出

1
true
false
true

複製代碼

in操做符:檢測指定對象(右邊)原型鏈上是否有對應的屬性值。 hasOwnProperty方法:檢測指定對象自身上是否有對應的屬性值。二者的區別在於in會查找原型鏈,而hasOwnProperty不會。

示例中對象foo自身上存在goo屬性,而它的原型鏈上存在bar屬性。

經過這個例子要注意若是要判斷foo上是否有屬性goo,不能簡單的經過if(foo.goo){}判斷,由於goo的值可能爲undefined或者其餘可能隱式轉換爲false的值。


第 33 題

Object.prototype.bar = 1;

var foo = {
    moo: 2
};
for(var i in foo) {
    console.log(i); 
}
複製代碼
查看解析
// 輸出

'moo'
'bar'
複製代碼

for...in...遍歷對象上除了Symbol之外的可枚舉屬性,包括原型鏈上的屬性。


第 34 題

function foo1() {
    return {
        bar: "hello"
    };
}
function foo2() {
    return 
    {
        bar: "hello"
    };
}
console.log(foo1());
console.log(foo2());
複製代碼
查看解析
// 輸出

{ bar: "hello" }

undefined
複製代碼

兩個函數惟一區別就是return後面跟的值,一個換行一個不換行。

當咱們書寫代碼時忘記在結尾書寫;時,JavaScript解析器會根據必定規則自動補上;

return
{
    bar: "hello"
}
=> 會被解析成
return;
{
    bar: "hello"
};
複製代碼

所以函數執行後會返回undefined


第 35 題

console.log((function(){ return typeof arguments; })());
複製代碼
查看解析
// 輸出

'object'
複製代碼

arguments爲類數組,類型爲object。所以typeof arguments = 'object'


第 36 題

console.log(Boolean(false));
console.log(Boolean('0'));
console.log(Boolean(''));
console.log(Boolean(NaN));
複製代碼
查看解析
//輸出

false
true
false
fasle

複製代碼

只有下面幾種值在轉換爲布爾值時爲false:

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

複製代碼

除此以外的值在轉換爲布爾值的時候所有爲true


第 37 題

console.log(Array(3));

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

複製代碼
查看解析
// 輸出

[empty × 3] 

[2,3]
複製代碼

使用Array()建立數組時,要注意傳入的值的類型和數量。


第 38 題

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

複製代碼
查看解析
// 輸出

false
複製代碼

第 39 題

var a=[1, 2, 3];
console.log(a.join());
複製代碼
查看解析
//輸出

1,2,3
複製代碼

join方法若是省略參數,默認以,分隔。


第 40 題

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

複製代碼
查看解析
// 輸出

2
複製代碼

在執行a - b時,ab都要轉換爲數字。首先a先轉換爲字符串,[3] => [3].toString() => '3',而後Number(3) => 3b同理。所以轉換以後爲3 - 1 = 2


最後

若是文中有錯誤,請務必留言指正,萬分感謝。

點個贊哦,讓咱們共同窗習,共同進步。

相關文章
相關標籤/搜索