### 2. js中的基礎數據類型有哪幾種? 了解包裝對象嗎?
答:六種,string, number, boolean, undefiend, null, symbol
基礎數據類型臨時創建的臨時對象,稱為包裝對象。其中 number、boolean 和 string 有包裝對象,代碼運行的過程中會找到對應的包裝對象,然后包裝對象把屬性和方法給了基本類型,然后包裝對象被系統進行銷毀。
## 3.對內存泄漏的了解
1. 理解
- 定義:程序中已在堆中分配的內存,因為某種原因未釋放或者無法釋放的問題
- 簡單理解: 無用的內存還在占用,得不到釋放和歸還,比較嚴重的時候,無用的內存還會增加,從而導致整個系統卡頓,甚至崩潰。
2. 生命周期
1. 分配期
? 分配所需要的內存,在js中,是自動分配的
2. 使用期
? 使用分配的內存,就是讀寫變量或者對象的屬性值
3. 釋放期
? 不需要時將該內存釋放,js會自動釋放(除了閉包和一些bug以外)
? 內存泄漏就是出現在這個時期,內存沒有被釋放導致的
3. 可能出現內存泄漏的原因
1. 意外的全局變量
2. DOM元素清空時,還存在引用
3. 閉包
4. 遺忘的定時器
**如何優化內存泄漏?**
* 全局變量先聲明在使用
* 避免過多使用閉包。
* 注意清除定時器和事件監聽器。
## 4.js中數組合并的方法
js 數組合并
let arr1 = \['溫情', '劉聰'\]
let arr2 = \['楊和蘇', '鄧紫棋'\]
let arr3 = \['周延'\]
**1\. arr1.concat(arr2, ······)**
es5 Array.concat() 合并兩個數組, 返回新數組,不會改變原數組
arr = arr1.concat(arr2, arr3);
console.log(arr); ?// \["溫情", "劉聰", "楊和蘇", "鄧紫棋", "周延"\]
**2\. \[…arr1, …arr2,······\]**
es6 展開運算符(…)
arr = \[...arr1, ...arr2, ...arr3\];
console.log(arr); ?// \["溫情", "劉聰", "楊和蘇", "鄧紫棋", "周延"\]
**3\. push(…arr)**
push 結合 ...\[\] 來實現, 會更改原數組
arr1.push(...arr2, ...arr3)
console.log(arr1); ?// \["溫情", "劉聰", "楊和蘇", "鄧紫棋", "周延"
**適合兩個數組,不適合多個數組的方法**
**1\. for + push**
for(let i in arr2) {
? ? arr1.push(arr2\[i\])
}
console.log(arr1); ?// \["溫情", "劉聰", "楊和蘇", "鄧紫棋"\]
**2\. arr1.push.apply(arr1, arr2)**
arr1.push.apply(arr1, arr2)
console.log(arr1); ?// \["溫情", "劉聰", "楊和蘇", "鄧紫棋"\]
## 5.合并對象的方法
**Object.assign()**
es6 Object.assign()方法用于對象的合并,將源對象(source)的所有可枚舉屬性,復制到目標對象(target)
Object.assign()方法的第一個參數是目標對象,后面的參數都是源對象。
let obj1 = {name: '溫情'}
let obj2 = {age: '22'}
**const newObj = Object.assign({}, obj1, obj2);**
console.log(newObj); ?// {name: "溫情", age: "22"}
!注意! Object.assign()實行的是淺拷貝,也就是說如果源對象的屬性是一個對象,那么目標對象得到的是這個對象的引用
let obj1 = {name: {chinese: '楊和蘇', english: 'keyNG'}}
const newObj = Object.assign({}, obj1);
console.log(newObj); ?// name: {chinese: "楊和蘇", english: "keyNG"}
obj1.name.english = 'pig';
console.log(newObj); ?// name: {chinese: "楊和蘇", english: "pig"}
## 6.什么是作用域,什么是作用域鏈?
* 規定變量和函數的可使用范圍稱為作用域
* 查找變量或者函數時,需要從局部作用域到全局作用域依次查找,這些作用域的集合稱作用域鏈。
## **7.JS如何實現異步編程(5種)?**
1) 回調函數(callback)
優點:解決了同步的問題(只要有一個任務耗時很長,后面的任務都必須排隊等著,會拖延整個程序的執行。)
缺點:回調地獄,每個任務只能指定一個回調函數,不能 return.
2) 事件監聽。這種思路是說異步任務的執行不取決于代碼的順序,而取決于某個事件是否發生。比如一個我們注冊一個按鈕的點擊事件或者注冊一個自定義事件,然后通過點擊或者trigger的方式觸發這個事件。
3) Promise
4) Generator
5) 生成器 async/await,是ES7提供的一種解決方案。
## 8.js中的堆內存與棧內存
在js引擎中對變量的存儲主要有兩種位置,**堆內存和棧內存**。
和java中對[內存](https://so.csdn.net/so/search?q=%E5%86%85%E5%AD%98&spm=1001.2101.3001.7020 "內存")的處理類似,**棧內存**主要用于存儲各種**基本類型的**變量,包括Boolean、Number、String、Undefined、Null,\*\*以及對象變量的指針,這時候棧內存給人的感覺就像一個線性排列的空間,每個小單元大小基本相等。
而堆內存主要負責像對象Object這種變量類型的存儲,如下圖

**棧內存中的變量一般都是已知大小或者有范圍上限的**,算作一種簡單存儲。**而堆內存存儲的對象類型數據對于大小這方面,一般都是未知的**。個人認為,這也是為什么null作為一個object類型的變量卻存儲在棧內存中的原因。
**因此當我們定義一個const對象的時候,我們說的常量其實是指針,就是const對象對應的堆內存指向是不變的,但是堆內存中的數據本身的大小或者屬性是可變的。而對于const定義的基礎變量而言,這個值就相當于const對象的指針,是不可變。**
既然知道了const在內存中的存儲,那么const、let定義的變量不能二次定義的流程也就比較容易猜出來了,每次使用const或者let去初始化一個變量的時候,會首先遍歷當前的內存棧,看看有沒有重名變量,有的話就返回錯誤。
說到這里,有一個十分很容易忽略的點,之前也是自己一直沒有注意的就是,使用new關鍵字初始化的之后是不存儲在棧內存中的。為什么呢?new大家都知道,根據構造函數生成新實例,這個時候生成的是**對象**,而不是基本類型。再看一個例子

?我們可以看到new一個String,出來的是對象,而直接字面量賦值和工廠模式出來的都是字符串。但是根據我們上面的分析大小相對固定可預期的即便是對象也可以存儲在棧內存的,比如null,為啥這個不是呢?再繼續看

很明顯,如果a,b是存儲在棧內存中的話,兩者應該是明顯相等的,就像null === null是true一樣,但結果兩者并不相等,說明兩者都是存儲在堆內存中的,指針指向不一致。
## 9.如何去判斷js數據類型?
**?????????首先我們可以用typeof去判斷,typeof只能判斷基本數據類型,對于引用數據類型,- -律返回object,在js中,數組是一種特殊的對象類型, 因此typeof-個數組,返回的是object.
????????還可以通過instanceof來判斷,它不能檢測基本數據類型,它是用來判斷個實例是否屬于某種類型, 使用它的方式可以用Ainstanceof B,如果A是B的實例,則返回true,否則返回flase。
????????然后還可以用constructor來判斷,除了undefined和nul1之外,其它類型都可以通過constructor來判斷,
????????但是如果聲明了一個構造函數,并且把它的原型指向改變了,這種情況下,constructor也不能準確的判斷。
????????通過0bject . prototype . toString,判斷一個對象 只屬于某種內置類型,但是不能準確的判斷一個實例是否屬于某種類型。
原因是因為實例對象可能會自定義toString方法,把這個方法給覆蓋掉,我們可以通過函數. call( )方法,可以在任意值上調用這個方法,幫助我們判斷這個值的類型。**
## 10,怎么允許跨域(跨域解決辦法)
**A、JSONP**
在頁面上,js腳本,css樣式文件,圖片這三種資源是可以與頁面本身不同源的。jsonp就利用了script標簽進行跨域取得數據。
JSONP允許用戶傳遞一個callback參數給服務器端,然后服務器端返回數據時會將這個callback參數作為函數名來包裹住JSON數據。這樣客戶端就可以隨意定制自己的函數來自動處理返回的數據了。
JSONP只能解決get請求,不能解決post請求。
```
<script>
function callback(data){
console.log(data);
}
</script>
<script src="http://localhost:80/?callback=callback"></script>
```
使用ajax實現跨域:
```
<script src="http://code.jquery.com/jquery-latest.js"></script>
$.ajax({
url:'http://localhost:80/?callback=callback',
method:'get',
dataType:'jsonp', //=> 執行jsonp請求
success:(res) => {
console.log(res);
}
})
function callback(data){
console.log(data);
}
```
**B、 CORS跨域資源共享:**
瀏覽器會自動進行CORS通信,實現CORS通信的關鍵是后端。服務端設置Access-Control-Allow-Origin就可以開啟CORS。該屬性表示哪些域名跨域訪問資源。
主要設置以下幾個屬性:
Access-Control-Allow-Origin//允許跨域的域名
Access-Control-Allow-Headers//允許的header類型
Access-Control-Allow-Methods//跨域允許的請求方式
### C、Nginx反向代理
通過nginx配置一個代理服務器將客戶機請求轉發給內部網絡上的目標服務器;并將服務器上返回的結果返回給客戶端。
### D、webpack(在vue.config.js文件中)中 配置webpack-dev-server
```
devServer: {
proxy: {
'/api': {
target: "http://39.98.123.211",
changeOrigin: true, //是否跨域
},
},
},
```
## 11.怎么讓對象的一個屬性不可被改變
### (1) Object.defineProperty()
可以使用Object.defineProperty()方法,讓對象的某一個屬性不可變,把對象某一屬性的writable和configurable設置為false.
```
let obj = {a:1,b:2};
Object.defineProperty(obj,'c',{
value:100000,
writable:false,//當該屬性的 writable 鍵值為 true 時,屬性的值才能被賦值操作修改
configurable:false//當為true時,該屬性的描述符才能夠被改變,同時該屬性也能從對應的對象上被刪除。
})
obj.c = 282031283
console.log(obj.c)//100000
```
### 2)object.preventExtensions()
讓對象不能添加新屬性,可以使用object.preventExtensions()方法。(但是可以修改屬性值)
```
let obj = {a:1,b:2};
Object.preventExtensions(obj);
obj.c = 1000;
console.log(obj)
```
## 12.瀏覽器所用的內核
* IE:Trident內核
* Chrome:以前是webkit內核,現在是Blink內核
* Firefox:Gecko(/?ɡeko?/)內核
* Safari:webkit內核
* Opera:最初使用的是presto內核,后來加入谷歌大軍,從webkit內核又變成了Blink內核
* 360,獵豹瀏覽器:IE+chrome雙內核
## 13、判斷一個函數是普通函數還是構造函數(補全funcA(){})
> 構造函數中this指向new創建的實例。所以可通過在函數內部判斷this是否為當前函數的實例進而判斷當前函數是否作為構造函數。
```
function A(){
if(this instanceof A){
console.log('我是構造函數')
}else{
console.log('我是普通函數')
}
}
A();
new A();
```
## **14.JavaScript 中的提升是什么?**
提升意味著所有的聲明都被移動到作用域的頂部。這發生在代碼運行之前。
對于函數,這意味著你可以從作用域中的任何位置調用它們,甚至在它們被定義之前。
```
hello(); // Prints "Hello world! " even though the function is called "before" declaration
function hello(){
console.log("Hello world! ");
}
```
對于變量,提升有點不同。它在作用域的頂部將 undefined 分配給它們。
例如,在定義變量之前調用它:
```
console.log(dog);//undefined
var dog = "Spot";
```
## **15、js有哪些內置對象?**
數據封裝類對象:Object、Array、Boolean、Number 和 String
其他對象:Function、Arguments、Math、Date、RegExp、Error....
## 16.防抖和節流
### **函數防抖**
當持續觸發事件時,一定時間段內沒有再觸發事件,事件處理函數才會執行一次,如果設定時間到來之前,又觸發了事件,就重新開始延時。也就是說當一個用戶一直觸發這個函數,且每次觸發函數的間隔小于既定時間,那么防抖的情況下只會執行一次。
### 函數節流
當持續觸發事件時,保證在一定時間內只調用一次事件處理函數,意思就是說,假設一個用戶一直觸發這個函數,且每次觸發小于既定值,函數節流會每隔這個時間調用一次
用一句話總結防抖和節流的區別:防抖是將多次執行變為最后一次執行,節流是將多次執行變為每隔一段時間執行
總結防抖和節流函數: js代碼區別就在于if這里是清除定時器還是直接return終止函數
~~~javascript
function throttleOrDebounce(fn,delay=3000) {
let timer=0;
return function (){
// 防抖
// if(timer) clearTimeout(timer);
// 節流
if (timer) return;
timer=setTimeout(()=>{
fn.apply(this,arguments)
timer=0
},delay)
}
}
~~~
## 17.對象的深拷貝
?深拷貝就是對目標的完全拷貝,不像淺拷貝那樣只是復制了一層引用,而是就連值也都復制了。
?深拷貝之后,兩個對象將毫無關聯,不會相互影響。
## 18、?Nodelist和HTMLCollection的區別
1.Nodelist是返回節點的集合,而nodelist里面也有數組,因此元素也是節點的一種,也就是元素節點**nodelist包含所有的節點 :注釋節點、text節點、element節點.....等**
## 22.for和foreach誰更快,為什么?
使用性能測試之后發現for更快,為什么呢?
for 更快
原因:
**forEach每次都要創建一個函數來調用,而for不會創建函數,**
**函數需要獨立的作用域,會有額外的開銷**
越“低級”的代碼,性能往往越好
日常開發別只考慮性能,forEach代碼可讀性更好(基于時間復雜度一樣的情況下,使用可讀性更好的方式更佳)
## **28,前端攻擊手段有哪些?該如何預防?**
**XSS :**跨站腳本攻擊
**DDoS? :**分布式的、大規模的流量訪問,使服務器癱瘓
**CSRF? :**跨站請求偽造
**SQL 注入**
### 手寫一個閉包,閉包的缺陷
### 手寫一個簡單的遞歸,比如n+n-1+n-2+...+1
### ?簡述冒泡和快排的思想
冒泡排序:
> 1、冒泡排序(Bubble Sort),是一種較簡單的排序算法。
> > 它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。
> > 這個算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端,所以命名為冒泡排序。
> 2、穩定性:穩定
快速排序:
> 1、快速排序(Quicksort)是對冒泡排序的一種改進。
>> 快速排序是C.R.A.Hoare于1962年提出的一種劃分交換排序。它采用了一種分治的策略,通常稱其為分治法(Divide-and-ConquerMethod)。
>> 該方法的基本思想是:
>> (1)先從數列中取出一個數作為基準數。
>> (2)分區過程,將比這個數大的數全放到它的右邊,小于或等于它 的數全放到它的左邊。
>> (3)再對左右區間重復第二步,直到各區間只有一個數。
> 2、穩定性:不穩定
### 解釋一下事件冒泡并自己設想一個能應用到事件冒泡的場景
### 說出event對象的3-5個屬性或方法
> 1.event.preventDefault() **如果調用這個方法,默認事件行為將不再觸發**
> 2.event.stopPropagation() & event.stopImmediatePropagation() event.stopPropagation()方法阻止事件冒泡到父元素,阻止任何父事件處理程序被執行
> 3.event.target指向引起觸發事件的元素
> 4.event.currentTarget則是事件綁定的元素
> 5.event.type;代表事件類型;如:click
> 6.event.target;表示觸發事件的源頭,通俗理解:點擊誰觸發了事件,target就是誰
> 7.event.currentTarget;表示包含事件的元素;通俗理解:事件綁定在誰身上,currentTarget就是誰
> 8.event.preventDefault();阻止默認行為;如阻止a標簽的鏈接跳轉
> 9.event.stopPropagation();阻止事件冒泡和事件捕獲;(翻譯propagation:傳播/繁殖/蔓延)
> 10.clientX/clientY;觸發事件時鼠標位于瀏覽器窗口的固定X/Y軸坐標,不受滾動條影響;
> 11.pageX/pageY;觸發事件時鼠標位于瀏覽器窗口的X/Y軸坐標,受滾動條影響;
> 12.screenX/screenY;觸發事件時鼠標位于屏幕的X/Y軸坐標;
### 瀏覽器的緩存機制,Etag和Last-Modified存在的意義
### 假設一個用戶打開你寫的網頁,發現白屏了,你會如何去定位原因
### 簡述xss和csrf,如何防范,如果包含xss的內容已經被提交到了后臺該怎么辦
### js中如何改變this的指向,call和apply和bind的區別
### js如何實現數組的淺拷貝和深拷貝
### 用過哪些js庫,分別有什么特點
### 如何將數組轉換為字符串,如何將字符串轉換為整數,parseInt的第二個參數代表什么
### 有沒有用過grunt gulp webpack這些,前端工程化的意義
### 簡述一下prototype,js的繼承方式,比較基于構造函數繼承和基于原型繼承
### xss和csrf防范
### 事件冒泡的兼容性問題
最后:
### 兩個房間,分別有三個開關和三個燈,每個房間只能進去一次,如何判斷出開關對應的燈(假設一開始都是關閉的)