js面試題(基礎)梳理

墨城發表於2022-05-04

1、JavaScript有幾種資料型別?

number:數字型別
string:字串型別
boolean:布林值型別
undefined:未定義型別
null:空型別
object:物件型別
symbol:symbol型別
bigint:大數字型別

2、JavaScript最大安全數字與最小安全數字?

console.log(Number.MAX_SAFE_INTEGER)
// 9007199254740991
console.log(Number.MIN_SAFE_INTEGER)
// -9007199254740991

3、深拷貝與淺拷貝的區別?

淺拷貝:只拷貝第一層,深層的依然是引用,改變深層會影響原物件
深拷貝:每一層都拷貝了,改變資料不會影響原物件

4、閉包是什麼?

閉包是一個函式,是一個能讓外部訪問到函式內部的函式

優點:使外部能訪問內部,延長內部變數壽命
缺點:濫用閉包造成記憶體洩漏

例子:

function a () {
  let num = 0
  
  // 這是個閉包
  return function () {
     return ++num
  }
}
const b = a()
console.log(b()) // 1
console.log(b()) // 2

5、原型鏈是什麼

原型鏈是一條引用的鏈,例項的隱式原型指向建構函式的顯式原型,可以使用A instanceof B來判斷B是否在A的原型鏈上。

6、什麼是變數提升?函式提升?

變數提升

console.log(name) // undefined
var name = 'Sunshine_Lin'

if (false) {
  var age = 23
}
console.log(age) // undefined 不會報錯

函式提升

console.log(fun) // function fun() {}
function fun() {}

if (false) {
  function fun2(){}
}
console.log(fun2) // undefined 不會報錯

函式提升優先順序 > 變數提升優先順序

console.log(fun) // function fun() {}
var fun = 'Sunshie_Lin'
function fun() {}
console.log(fun) // 'Sunshie_Lin'

7、isNaN 與 Number.isNaN的區別?

isNaN:除了判斷NaN為true外,還會把不能轉成數字判斷為true,例如'dasd'
Number.isNaN:只會判斷NaN為true

8、解決遍歷物件時,把原型上的屬性遍歷出來了咋辦?

使用hasOwnProperty判斷

function Person(name) {
  this.name = name
}
Person.prototype.age = 23
const person = new Person('Sunshine_lin')
for (const key in person) { console.log(key) } // name age
// 使用 hasOwnProperty
for (const key in person) {
  person.hasOwnProperty(key) && console.log(key)
} // name

9、valueOf 與 toString?

valueOf比較偏向於計算,toString偏向於顯示
物件轉換時,優先呼叫toString
強轉字串時優先呼叫toString,強轉數字時優先呼叫valueOf
正常情況下,優先呼叫toString
運算操作符情況下優先呼叫valueOf

10、JavaScript變數在記憶體中具體儲存形式?

基本資料型別:存在棧記憶體裡
引用資料型別:指標存棧記憶體,指向堆記憶體中一塊地址,內容存在堆記憶體中

11、講一講JavaScript的裝箱和拆箱?

裝箱:把基本資料型別轉化為對應的引用資料型別的操作

看以下程式碼,s1只是一個基本資料型別,他是怎麼能呼叫indexOf的呢?

const s1 = 'Sunshine_Lin'
const index = s1.indexOf('_')
console.log(index) // 8

原來是JavaScript內部進行了裝箱操作

1、建立String型別的一個例項;
2、在例項上呼叫指定的方法;
3、銷燬這個例項;

var temp = new String('Sunshine_Lin')
const index = temp.indexOf('_')
temp = null
console.log(index) // 8

拆箱:將引用資料型別轉化為對應的基本資料型別的操作

通過valueOf或者toString方法實現拆箱操作

var objNum = new Number(123);  
var objStr =new String("123");   
console.log( typeof objNum ); //object
console.log( typeof objStr ); //object 
console.log( typeof objNum.valueOf() ); //number
console.log( typeof objStr.valueOf() ); //string

console.log( typeof objNum.toString() ); // string 
console.log( typeof objStr.toString() ); // string

12、null和undefined的異同點有哪些?

相同點

1、都是空型別
2、轉布林值都是false,都是假值
3、null == undefined 為 true

不同點

1、typeof,前者為object,後者為undefined
2、null轉數字為0,undefined轉數字為NaN
3、null === undefined 為 false

13、如何判斷資料型別?

typeof:能判斷string、number、undefined、boolean、function、object(null是object)
Object.prototype.toString.call():能判斷大部分資料型別
instanceOf

14、為什麼typeof null 是object?

不同資料型別底層都是用二進位制來表示的,二進位制前三位為000則會被判斷為object,而null二進位制全是0,所以被判斷成object

15、== 與 === 的區別?

==:比較過程會進行隱式轉換
===:值相同,型別相同才會為true

16、JavaScript的隱式轉換規則?

轉string型別:+(字串連線符)
轉number型別:++/--(自增自減運算子) + - * / %(算術運算子) > < >= <= == != === !== (關係運算子)
轉boolean:!(邏輯非運算子)

17、雙等號左右兩邊的轉換規則?

1、null == undefined 為 true
2、如果有一個運算元是布林值,則在比較相等性之前先將其轉換為數值——false轉換為0,而true轉換為1;
3、如果一個運算元是字串,另一個運算元是數值,在比較相等性之前先將字串轉換為數值
4、如果一個運算元是物件,另一個運算元不是,則呼叫物件的toString()方法,用得到的基本型別值按照前面的規則進行比較

18、undefined >= undefined 為什麼是 false ?

隱式轉換,變成NaN >= NaN,NaN不等於自身也不大於自身

19、null >= null 為什麼是 true?

隱式轉換,變成0 >= 0,為true

20、[] == ![] 為什麼是 true ?

第一步:轉為[] == false
第二步:轉為[] == 0
第三步:轉為'' == 0
第四步:轉為0 == 0

21、0.1 + 0.2 === 0.3,對嗎?

不對,JavaScript存在精度丟失問題,由於有些小數無法用二進位制表示,所以只能取近似值,解決方法有:

先轉大數,再變小數
使用toFixed

22、什麼是匿名函式?
匿名函式,就是沒有名字的函式,比如:

(function(x, y){
    alert(x + y);  
})(2, 3)

23、繫結點選事件有幾種方式?

三種

xxx.onclick = function (){}
<xxx onclick=""></xxx>
xxx.addEventListener('click', function(){}, false)

24、addEventListener的第三個引數是幹嘛的?

決定事件是捕獲階段執行還是冒泡階段執行

true:捕獲
false:預設,冒泡

25、函式宣告和函式表示式的區別?

函式宣告:享受函式提升
函式表示式:歸類於變數宣告,享受變數提升
函式提升優先順序 > 變數提升優先順序

console.log(fun) // fun () {}
// 函式表示式
var fun = function(name) {}
// 函式宣告
function fun () {}
console.log(fun) // fun (name) {}

26、JavaScript的事件流模型有哪些?

事件冒泡:由最具體的元素接收,並往上傳播
事件捕獲:由最不具體的元素接收,並往下傳播
DOM事件流:事件捕獲 -> 目標階段 -> 事件冒泡

27、Ajax、Axios、Fetch有啥區別?

Ajax:是對XMLHttpRequest(XHR)的封裝
Axios:是基於Promise對XHR物件的封裝
Fetch:是window的一個方法,基於Promise,與XHR無關,不相容IE

28、load、$(document).ready、DOMContentLoaded的區別?

$(document).ready、DOMContentLoaded:DOM樹構建完畢,但還沒有請求靜態資源
load:靜態資源請求完畢

29、如何阻止事件冒泡?

function stopBubble(e) {
  if (e.stopPropagation) {
    e.stopPropagation()
  } else {
    window.event.cancelBubble = true;
  }
}

30、如何阻止事件預設行為?

function stopDefault(e) {
  if (e.preventDefault) {
    e.preventDefault();
  } else {
    window.event.returnValue = false;
  }
}

31、什麼是事件委託?

當子元素都需要繫結相同事件時,可以將事件綁在父元素上,優點有:

繫結在父元素,則只需繫結一次,節省效能
後續新增的子元素也可以觸發父元素繫結的事件

32、如何實現陣列去重?

// 使用 Map 去重
function quchong1(arr) {
  const newArr = []
  arr.reduce((pre, next) => {
    if (!pre.get(next)) {
      pre.set(next, 1)
      newArr.push(next)
    }
    return pre
  }, new Map())
  return newArr
}

// 使用 Set 去重
function quchong (arr) {
    return [...new Set(arr)]
}

33、Set與Array的區別是什麼?

Set使用has判斷有無元素,陣列使用索引
Set新增元素使用方法add,陣列用push、unshift
Set長度為size,陣列為length
Set會自動把同樣的基礎資料型別去重,陣列不能
Set刪除元素用delete,陣列用splice、pop、shift
Set可以使用clear清空,陣列需要重新賦值[]
陣列可以傳入new Set(array),實現陣列轉Set
Set可以使用keys、value方法,轉陣列
Set自帶forEach方法進行遍歷

34、Map與Object的區別是什麼?

Map使用set設定屬性,物件使用obj[key] = value
Map使用get獲取屬性值,物件使用obj[key]
Map使用has判斷屬性存在與否,物件只能obj[key]
Map刪除元素使用delete方法,物件使用delete關鍵字
Map使用clear進行情空,物件需要重新賦值{}
Map和物件都可以使用entries方法轉陣列鍵值對
Map自帶forEach方法進行遍歷

35、NaN是什麼?有什麼特點?

typeof NaN 為 number
NaN不等於自身,不大於自身,不小於自身
NaN可以使用Number.isNaN判斷
NaN是假值,轉布林值為false

36、處理非同步的方法有哪些?

回撥函式
Promise
事件監聽
釋出訂閱
async/await

37、JavaScript繼承方式有幾種?

前置工作

// 定義一個動物類
function Animal (name) {
  // 屬性
  this.name = name || 'Animal';
  // 例項方法
  this.sleep = function(){
    console.log(this.name + '正在睡覺!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

1、原型鏈繼承
核心:將父類的例項作為子類的原型

function Cat(){ 
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';

var cat = new Cat();
console.log(cat.name); // cat
cat.eat('fish') // cat正在吃:fish
cat.sleep() // cat正在睡覺!
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

優點:

1、非常純粹的繼承關係,例項是子類的例項,也是父類的例項
2、父類新增原型方法/屬性,子類都能訪問到
3、簡單,易於實現

缺點:

1、要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行,不能放構造器中
2、來自原型物件的所有屬性被所有例項共享
3、建立子例項時,無法向父類建構函式傳參
4、不支援多繼承

2、構造繼承
核心:使用父類的構造器來增強子類例項,等於是複製父類的例項屬性給子類(沒用到原型)

function Cat(name) {
  Animal.call(this);
  this.name = name || 'Tom';
}

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

優點:

1、解決了原型鏈繼承中,子類例項共享父類引用屬性的問題
2、建立子類例項時,可以向父類傳遞引數
3、可以實現多繼承(call多個父類物件)

缺點:

1、例項並不是父類的例項,知識子類的例項
2、是能繼承父類的例項屬性和方法,不能繼承原型屬性/方法
3、無法實現函式複用,每個子類都有父類例項函式的副本,影響效能

3、例項繼承
核心:為父類例項新增新特性,作為子類例項返回

function Cat(name){
  var instance = new Animal();
  instance.name = name || 'Tom';
  return instance;
}

var cat = new Cat();
console.log(cat.name) // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

優點:

1、不限制呼叫方式,不管是new 子類()還是子類(),返回的物件具有相同效果

缺點:

1、例項是父類的例項,不是子類的例項
2、不支援多繼承

4、拷貝繼承
核心:就一個一個拷貝

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  this.name = name || 'Tom';
}

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

優點:

1、支援多繼承

缺點:

1、效率低,記憶體佔用高(因為要拷貝父類的屬性)
2、無法獲取父類不可列舉方法(不可列舉方法,不能使用for in訪問到)

5、組合繼承
核心:通過父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類例項作為子類原型,實現函式複用

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

Cat.prototype.constructor = Cat;

var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

優點:

1、彌補了構造繼承的缺陷,可以繼承例項屬性/方法,也可繼承原型屬性/方法
2、既是子類的例項,也是父類的例項
3、不存在引用屬性共享問題
4、可傳參
5、函式可複用

缺點:

1、呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)

6、寄生組合繼承
核心:通過寄生方式,砍掉父類的例項屬性,這樣,在呼叫兩次父類的構造時,就不會初始化兩次例項方法/屬性,避免繼承組合的缺點

function Cat(name) {
  Animal.call(this);
  this.name = name || 'Tom';
}
// 建立一個沒有例項方法的類
var Super = function () { };
Super.prototype = Animal.prototype;
//將例項作為子類的原型
Cat.prototype = new Super();

// Test Code
var cat = new Cat();
console.log(cat.name); // Tom
cat.sleep() // Tom正在睡覺!
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

優點:

1、堪稱完美

缺點:

1、實現複雜

38、建立一個物件的方式有哪幾種?

new Object

const obj = new Object()
obj.name = 'Sunshine_Lin'

字面量

const obj = { name: 'Sunshin_Lin' }

工廠模式

function createObj(name) {
  const obj = new Object()
  obj.name = name
  return obj
}
const obj = createObj('Sunshine_Lin')

建構函式

function Person(name) {
  this.name = name
}
const person = new Person('Sunshine_Lin')

39、this指向的四種情況?

new操作符

function Person(name) {
  this.name = name
  console.log(this)
}
// this指向當前person例項物件
const person = new Person('Sunshine_Lin')

指向window

function fn() {
  console.log(this)
}
fn() // 瀏覽器window,node裡global

物件呼叫方法

const target = {
  fn: function () { console.log(this) }
}
target.fn() // target

// 這種就是改變了this了
const fn = target.fn
fn() // 瀏覽器window,node裡global

箭頭函式

const obj = {
  name: '林三心',
  fn: () => {
    console.log(this.name)
  }
}
console.log(obj.fn()) // undefined

call、apply、bind改變this

const obj1 = {
  name: '林三心',
  sayName: function() {
    console.log(this.name)
  }
}
const obj2 = {
  name: 'Sunshin_Lin'
}
// 改變sayName的this指向obj2
obj1.sayName.call(obj2) // Sunshin_Lin
// 改變sayName的this指向obj2
obj1.sayName.apply(obj2) // Sunshin_Lin
// 改變sayName的this指向obj2
const fn = obj1.sayName.bind(obj2)
fn() // Sunshin_Lin

40、陣列的常用方法有哪些?

方法作用是否影響原陣列
push在陣列後新增元素,返回長度
pop刪除陣列最後一項,返回被刪項
shift刪除陣列第一項,返回被刪項
unshift陣列開頭新增元素,返回長度
reserve反轉陣列,返回陣列
sort排序陣列,返回陣列
splice擷取陣列,返回被擷取部分
join將陣列變字串,返回字串
concat連線陣列
map相同規則處理陣列項,返回新陣列
forEach遍歷陣列
filter過濾陣列項,返回符合條件的陣列
every每一項符合規則才返回true
some只要有一項符合規則就返回true
reduce接受上一個return和陣列下一項
flat陣列扁平化
slice擷取陣列,返回被擷取區間

41、Math的常用方法有哪些?

方法作用
Math.max(...arr)取arr中的最大值
Math.min(...arr)取arr中的最小值
Math.ceil(小數)小數向上取整
Math.floor(小數)小數向下取整
Math.round(小數)小數四捨五入
Math.sqrt(num)對num進行開方
Math.pow(num, m)對num取m次冪
Math.random() * num取0-num的隨機數

42、JS中有哪些不同型別的彈出框?

在JS中有三種型別的彈出框可用,分別是:

Alert、Confirm、Prompt

43、如何將 JS 日期轉換為ISO標準

var date = new Date();
var n = date.toISOString();
console.log(n);
// YYYY-MM-DDTHH:mm:ss.sssZ

44、如何在JS中編碼和解碼 URL

編碼:encodeURI()
解碼:decodeURI()

45、什麼是BOM?有哪些api?
BOM就是browser object model,瀏覽器物件模型

api作用代表方法或屬性
window.history操縱瀏覽器的記錄history.back() 、history.go(-1)
window.innerHeight獲取瀏覽器視窗的高度
window.innerWidth獲取瀏覽器視窗的寬度
window.location操作重新整理按鈕和位址列location.host:獲取域名和埠
window.location操作重新整理按鈕和位址列location.hostname:獲取主機名
window.location操作重新整理按鈕和位址列location.port:獲取埠號
window.location操作重新整理按鈕和位址列location.pathname:獲取url的路徑
window.location操作重新整理按鈕和位址列location.search:獲取?開始的部分
window.location操作重新整理按鈕和位址列location.href:獲取整個url
window.location操作重新整理按鈕和位址列location.hash:獲取#開始的部分
window.location操作重新整理按鈕和位址列location.origin:獲取當前域名
window.location操作重新整理按鈕和位址列location.navigator:獲取當前瀏覽器資訊

46、BOM 和 DOM 的關係

BOM全稱Browser Object Model,即瀏覽器物件模型,主要處理瀏覽器視窗和框架。

DOM全稱Document Object Model,即文件物件模型,是 HTML 和XML 的應用程式介面(API),遵循W3C 的標準,所有瀏覽器公共遵守的標準。

JS是通過訪問BOM(Browser Object Model)物件來訪問、控制、修改客戶端(瀏覽器),由於BOM的window包含了document,window物件的屬性和方法是直接可以使用而且被感知的,因此可以直接使用window物件的document屬性,通過document屬性就可以訪問、檢索、修改XHTML文件內容與結構。因為document物件又是DOM的根節點。

可以說,BOM包含了DOM(物件),瀏覽器提供出來給予訪問的是BOM物件,從BOM物件再訪問到DOM物件,從而js可以操作瀏覽器以及瀏覽器讀取到的文件。

47、JS中的substr()和substring()函式有什麼區別
substr() 函式的形式為substr(startIndex,length)。它從startIndex返回子字串並返回'length'個字元數。

var s = "hello";
( s.substr(1,4) == "ello" ) // true

substring() 函式的形式為substring(startIndex,endIndex)。它返回從startIndex到endIndex - 1的子字串。

var s = "hello";
( s.substring(1,4) == "ell" ) // true

48、解釋一下 "use strict" ?

“use strict”是Es5中引入的js指令。使用“use strict”指令的目的是強制執行嚴格模式下的程式碼。在嚴格模式下,我們們不能在不宣告變數的情況下使用變數。早期版本的js忽略了“use strict”。

相關文章