我經歷的前端面試題(二)

  • 這是來自某出行類大司的一面。
  • 偏Javascript基礎。

js基礎

1.基本類型有哪些

Number String Boolean Null Undefined Symbol (落下沒說)

2.Null 和 Undefined什麼區別?

參考文章:undefined與null的區別

null表示"沒有對象",即該處不應該有值。典型用法是:

(1) 作爲函數的參數,表示該函數的參數不是對象。

(2) 作爲對象原型鏈的終點。

undefined表示"缺少值",就是此處應該有一個值,但是還沒有定義。典型用法是:

(1)變量被聲明瞭,但沒有賦值時,就等於undefined。

(2)  調用函數時,應該提供的參數沒有提供,該參數等於undefined。

(3)對象沒有賦值的屬性,該屬性的值爲undefined。

(4)函數沒有返回值時,默認返回undefined。

區別:

(1)定義:undefined表示一個變量沒有被聲明,或者被聲明瞭但沒有被賦值。(比如,一個沒有傳入實參的形參變量的值爲undefined。再比如,如果一個函數什麼都不返回,則該函數默認返回undefined;)

                     null是一個表示“沒有值”的值,是空對象引用,引用指向爲空 。

(2)類型:undefined的類型(typeof)是undefined;null的類型(typeof)是object。

(3)用Number()轉化成數值:undefined爲NaN ,null爲0。

3.如何判斷數組類型,幾種方法?

參考文章:Js中如何判斷一個對象爲數組類型

var testArr = [1, 2]

console.log (testArr instanceof Array )
console.log( testArr.constructor == Array ) // 不一定準確,因爲數組是引用類型
console.log( Object.prototype.toString.call(testArr) === '[object Array]' )
console.log( Array.isArray( testArr) ) //ES5提供

4.循環有哪些寫法?for括號中有什麼,能不寫嗎?while的條件可以是什麼?結束循環有哪些方式?

結束循環的方法:

  • return ==》結束循環並中斷函數執行;
  • break ==》結束循環函數繼續執行;
  • continue ==》跳過本次循環;
  • for 循環中的變量 i,由於 ES5並沒有塊級作用域的存在,它在循環結束以後仍然存在於內存中,所以建議使用函數自執行的方式來避免;

10.遍歷一個數組的方法?

(1)常用的方法性能對比(由強到弱):for(length緩存,每次計算length、不爲null)、forEach、map、for of 、for in 。參考文章:JS幾種數組遍歷方式以及性能分析對比(已經不知道誰是原作者了,2006年的應該是吧)

(2)我不常用的方法還有:filter、some、every、reduce、reduceRight、find、findIndex

(3)ES6提供的:entries()、keys()、values()

參考文章:js數組遍歷方法總結(頁面好看點就完美了)

它們都返回一個遍歷器對象,可以用for...of循環進行遍歷,唯一的區別是keys()是對鍵名的遍歷、values()是對鍵值的遍歷,entries()是對鍵值對的遍歷。

5.ES6:let 和 var 有哪些區別?

(1)塊作用域:let聲明的變量僅在塊級作用域內有效,var聲明的變量在全局範圍內都有效。

(2)變量提升:let聲明的變量一定要在聲明後使用,否則報錯ReferenceError。var聲明的變量可以在聲明之前使用,值爲undefined,即“變量提升”。

(3)let的“暫時性死區”(TDZ):如果區塊中存在letconst命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。使用let命令聲明變量之前,該變量都是不可用的。這在語法上,稱爲“暫時性死區”(temporal dead zone,簡稱 TDZ)。

if (true) {
  // TDZ開始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ結束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

6.ES6:箭頭函數與普通函數寫法有什麼區別?

參考文章:箭頭函數和普通函數的區別

(1)構造函數:箭頭函數沒有構造函數,不能通過new獲得對象。

(2)參數:箭頭函數不綁定arguments,取而代之用rest參數...解決

let C = (...c) => {
  console.log(arguments) // Uncaught ReferenceError: arguments is not defined
  console.log(c);
}
C(3,82,32,11323);  // [3, 82, 32, 11323]

(3)this指向:箭頭函數不綁定this,會捕獲其所在的上下文的this值,作爲自己的this值。

(先自己分析,再看鏈接裏的具體分析)

示例一:

var obj = {
  a: 10,
  b: function(){
    console.log(this.a); //10
  },
  c: function() {
     return ()=>{
           console.log(this.a); //10
     }
  }
}
obj.b(); 
obj.c()();

示例二: 

var obj = {
  a: 10,
  b: () => {
    console.log(this.a); //undefined
    console.log(this); //window
  },
  c: function() {
    console.log(this.a); //10
    console.log(this); //obj{...}
  }
}
obj.b(); 
obj.c();

(4)使用call()和apply()調用:直傳入參數,不改變this指向。

(5)原型屬性:箭頭函數沒有原型屬性。

(6)箭頭函數不能當做Generator函數,不能使用yield關鍵字。

(7)箭頭函數不能換行。

7.一個頁面引入了1.js和2.js,1.js中有個變量a,2.js能訪問到a變量嗎?怎麼訪問?

我想到的最直接的:html中引用1.js、2.js,2.js中可以訪問1.js中的方法從而訪問到變量。具體怎麼寫?兩種。

方法一:構造函數。

從閉包角度,對於getName,它的作用域鏈中包括包含函數的作用域,所以能訪問到name變量

<!--在html中-->
<script src="coding.js"></script>
<script src="test.js"></script> <!--引用coding.js中的變量-->
// coding.js中
function Person(name){
  var name = name || "noName"
  // 從閉包角度,對於getName,它的作用域鏈中包括包含函數的作用域,所以能訪問到name變量
  this.getName=function(){
      return name; 
  };
  // setName同理
  this.setName=function(value){
    name=value;
  };
}
// test.js
var person = new Person()
console.log(person.name) // undefined
console.log(person.getName()) // noName
var person=new Person('哈哈');
console.log(person.getName());//'哈哈'
person.setName('呀呀');
console.log(person.getName());//'呀呀'

方法二:利用閉包的私有作用域。
構造函數使用函數表達式 並且不用var聲明;公共方法寫在原型鏈上;私有變量是實例共享的;

// coding.js
(function(){
  var name='noName';
  // 構造函數使用函數表達式,然而不用var聲明,所以是全局的
  Person=function(value){
      name = value;
  };
  // 公共方法寫在原型鏈上,都訪問同樣的內部變量,所以私有變量是實例共享的
  Person.prototype.getName=function(){
      return name;
  };
  Person.prototype.setName=function(value){
      name=value;
  }
})();
// test.js
var person = new Person()
console.log('直接訪問:' + person.name)
console.log('無參數訪問:' + person.getName())
var person1=new Person('舊實例');
var person2=new Person('新實例');
console.log(person1.getName());
console.log(person2.getName());

 

方法三:使用本地存儲策略。cookie或者localStorage。(回憶一下做過的微信小程序項目)

方法四:使用參數傳遞。

這兩種方法感覺不是本題的意思,應該屬於跨頁面的數據傳遞。

參考文章:JS實現把一個頁面層數據傳遞到另一個頁面的兩種方式

8.形參和實參分別是什麼。

形參是函數定義的時候的參數。實參是調用該函數實際傳入的參數。

function add(a,b) { // a b 是形參
    return a + b
};
add(1,2); // 1 2 是實參

需要注意的是: 

  • 調用函數傳遞的實參與定義函數規定的形參是依次對應的
  • 超出形參數目的實參不傳遞其值。
  • 如果沒有對應的實參(實參數目少於形參數目)傳入,其值爲undefined。
  • 而函數使用了形參未定義的‘字面量’,出錯:xx is not defined 。
// 關於實參、形參
function add(a, b, c){
  // console.log(arguments)
  console.log(a,b,c)
  console.log(a + b + c)
  // console.log(x) //報錯:x is not defined 
}
add(1,2,3,4)
add(1,2)
add(1,'2',3)

9.說一下作用域鏈。

看前面的總結即可。閉包爲什麼會造成內存泄漏?


數據結構

1.什麼是平衡二叉樹?滿二叉樹?完全二叉樹?

下一篇:


設計模式

整理單獨一篇吧

用vue實現數據雙向綁定舉例子說的觀察者模式。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章