前端知識點

納蘭不是容若發表於2019-04-04

js中new一個物件的過程

使用new關鍵字呼叫函式(new ClassA(…))的具體步驟:

1. 建立空物件;
var obj = {};

2. 設定新物件的constructor屬性為建構函式的名稱,設定新物件的__proto__屬性指向建構函式的prototype物件;
obj.__proto__ = ClassA.prototype;

3. 使用新物件呼叫函式,函式中的this被指向新例項物件:
ClassA.call(obj);  //{}.建構函式();          

4. 將初始化完畢的新物件地址,儲存到等號左邊的變數中
複製程式碼

什麼是閉包?閉包的優缺點


答:閉包是將外部作用域中的區域性變數封閉起來的函式物件。被封閉起來的變數與封閉它的函式物件有相同的生命週期。

優點:一個是前面提到的可以讀取函式內部的變數,另一個就是讓這些變數的值始終保持在記憶體中,不會在f1呼叫後被自動清除。

缺點

  • 由於閉包會使得函式中的變數都被儲存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的效能問題,在IE中可能導致記憶體洩露。解決方法是,在退出函式之前,將不使用的區域性變數全部刪除。
  • 閉包會在父函式外部,改變父函式內部變數的值。所以,如果你把父函式當作物件(object)使用,把閉包當作它的公用方法(Public Method),把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函式內部變數的值。

什麼是盒子模型?CSS-標準盒模型和怪異盒模型的區別?哪個css可以改變盒子模型?


css盒子模型 又稱為框模型(Box Model),包含了元素內容(content)、內邊距(padding)、邊框(border)、外邊距(margin)幾個要素。

標準盒模型

前端知識點

怪異盒模型

前端知識點

區別:當不對doctype進行定義時,會觸發怪異模式。

  • 在標準模式下,一個塊的總寬度= width + margin(左右) + padding(左右) + border(左右)
  • 在怪異模式下,一個塊的總寬度= width + margin(左右)(即width已經包含了padding和border值)

怎麼使div水平居中,垂直居中,水平垂直居中?


以一個分頁dom為例

dom結構

<div class="pagination">
    <ul>
        <li><a href="#">1</a></li>
        <li><a href="#">2</a></li>
        <li><a href="#">3</a></li>
        <li><a href="#">4</a></li>
        <li><a href="#">5</a></li>
    </ul>
</div>
複製程式碼

水平居中

垂直居中

水平垂直居中

position取值

  • static 預設值 沒有定位
  • inherit 規定應該從父元素繼承position屬性的值
  • relative 生成相對定位的元素,相對於其正常位置進行定位
  • absolute 絕對定位 相對於static以外的第一個父元素進行定位
  • fixed 絕對定位 相對於瀏覽器視窗進行定位

sticky佈局

法一:

dom結構

    <div class="wrapper">
        <header>header</header>
        <section style="height:300px">內容</section>
    </div>
    <footer>designer by echo hu</footer>
複製程式碼

css

/*相同dom不同css*/
第一種樣式
footer {
    height: 7em;
    background: #3c3c3c;
}
.wrapper {
    width: 100%;
    min-height: calc(100vh - 7em);
}

第二種樣式
html,body{
    height:100%;
}
footer{
    height:7em;
}
.wrapper{
    height:calc(100% - 7em);
}
複製程式碼

法二:

dom結構

<div class="wrapper">
    <div class="main">
       <div class="content"></div>
    </div>
    <div class="close"></div>
</div>
複製程式碼

css樣式

.wrapper{
    width:100%;
    height:100%;
}
.main{
    min-height:100%;
}
.close{
    width:100%;
    height:32px;
    margin-top:-32px;
}
複製程式碼

flex佈局

what is flex?

flex是Flexible Box的縮寫,意為彈性佈局。

任何一個容器都可指定為flex佈局

.box{
    display:flex;
}
複製程式碼

行內元素也可以使用flex佈局

.box{
    display:inline-flex;
}
複製程式碼
注意:設為flex佈局後,子元素的clear,float,vertical-align屬性將失效

容器的屬性

+ flex-direction
+ flex-wrap
+ flex-flow
+ justify-content
+ align-items
+ align-content
複製程式碼

flex-direction屬性決定主軸的方向

.box{
    flex-direction: row | row-reverse | column | column-reverse
}
複製程式碼

它有四個值

+ row(預設值):主軸為水平方向,起點在左端
+ row-reverse:主軸為水平方向,起點在右端。
+ column:主軸為垂直方向,起點在上沿。
+ column-reverse:主軸為垂直方向,起點在下沿。
複製程式碼

flex-wrap屬性定義,如果一條軸線排不下,如何換行。預設情況下,專案都排在一條線上

.box{
    flex-wrap: nowrap(不換行) | wrap(換行,第一行在上方) | wrap-reverse(換行,第一行在下方)
}
複製程式碼

flex-flow屬性是flex-directionflex-wrap的簡寫,預設row nowrap

.box {
  flex-flow: <flex-direction> || <flex-wrap>;
}
複製程式碼

justify-content屬性定義了專案在主軸上的對齊方式。

它有五個值,具體對齊方式與軸的方向有關。下面假設主軸為從左往右。

+ flex-start(預設值):左對齊
+ flex-end:右對齊
+ center:居中
+ space-between:兩端對齊,專案之間的間隔都相等
+ space-around:每個專案兩側的間隔相等。所以,專案之間的間隔比專案與邊框的間隔大一倍。
複製程式碼

align-items屬性定義專案在交叉軸上如何對齊 它可能取5個值。具體的對齊方式與交叉軸的方向有關,下面假設交叉軸從上到下。

+ flex-start:交叉軸的起點對齊。
+ flex-end:交叉軸的終點對齊。
+ center:交叉軸的中點對齊。
+ baseline: 專案的第一行文字的基線對齊。
+ stretch(預設值):如果專案未設定高度或設為auto,將佔滿整個容器的高度。
複製程式碼

align-content屬性定義了多根軸線的對齊方式。如果專案只有一根軸線,該屬性不起作用。

該屬性可能取6個值。

+ flex-start:與交叉軸的起點對齊。
+ flex-end:與交叉軸的終點對齊。
+ center:與交叉軸的中點對齊。
+ space-between:與交叉軸兩端對齊,軸線之間的間隔平均分佈。
+ space-around:每根軸線兩側的間隔都相等。所以,軸線之間的間隔比軸線與邊框的間隔大一倍。
+ stretch(預設值):軸線佔滿整個交叉軸。
複製程式碼

專案的屬性

以下6個屬性設定在專案上。

+ order 定義專案的排列順序。數值越小,排列越靠前,預設為0
+ flex-grow 屬性定義專案的放大比例,預設為0,即如果存在剩餘空間,也不放大。
+ flex-shrink 屬性定義了專案的縮小比例,預設為1,即如果空間不足,該專案將縮小
+ flex-basis 屬性定義了在分配多餘空間之前,專案佔據的主軸空間
+ flex 是flex-grow, flex-shrink 和 flex-basis的簡寫,預設值為0 1 auto
+ align-self 屬性允許單個專案有與其他專案不一樣的對齊方式,可覆蓋align-items屬性。預設值為auto,表示繼承父元素的align-items屬性,如果沒有父元素,則等同於stretch。
複製程式碼

display取值,元素預設是什麼,內聯元素塊級元素可變元素有哪些?img是什麼?

img是內聯元素

display CSS屬性指定用於元素的呈現框的型別。在 HTML 中,預設的 display 屬性取決於 HTML 規範所描述的行為或瀏覽器/使用者的預設樣式表。

預設值是inline

display取值如下:

none	此元素不會被顯示。
block	此元素將顯示為塊級元素,此元素前後會帶有換行符。
inline	預設。此元素會被顯示為內聯元素,元素前後沒有換行符。
inline-block	行內塊元素。(CSS2.1 新增的值)
list-item	此元素會作為列表顯示。
run-in	此元素會根據上下文作為塊級元素或內聯元素顯示。
compact	CSS 中有值 compact,不過由於缺乏廣泛支援,已經從 CSS2.1 中刪除。
marker	CSS 中有值 marker,不過由於缺乏廣泛支援,已經從 CSS2.1 中刪除。
table	此元素會作為塊級表格來顯示(類似 <table>),表格前後帶有換行符。
inline-table	此元素會作為內聯表格來顯示(類似 <table>),表格前後沒有換行符。
table-row-group	此元素會作為一個或多個行的分組來顯示(類似 <tbody>)。
table-header-group	此元素會作為一個或多個行的分組來顯示(類似 <thead>)。
table-footer-group	此元素會作為一個或多個行的分組來顯示(類似 <tfoot>)。
table-row	此元素會作為一個表格行顯示(類似 <tr>)。
table-column-group	此元素會作為一個或多個列的分組來顯示(類似 <colgroup>)。
table-column	此元素會作為一個單元格列顯示(類似 <col>)
table-cell	此元素會作為一個表格單元格顯示(類似 <td> 和 <th>)
table-caption	此元素會作為一個表格標題顯示(類似 <caption>)
inherit	規定應該從父元素繼承 display 屬性的值。
複製程式碼

float:left情況下是怎樣的,此時如果超出了寬度範圍

該元素從網頁的正常流動中移除,儘管仍然保持部分的流動性

css3的transform

CSS transform 屬性允許你修改CSS視覺格式模型的座標空間。使用它,元素可以被轉換(translate)、旋轉(rotate)、縮放(scale)、傾斜(skew)。

輸入一個URL後會發生什麼?

總體來說分為以下幾個過程:

  • DNS解析

  • TCP連線

  • 傳送HTTP請求

  • 伺服器處理請求並返回HTTP報文

  • 瀏覽器解析渲染頁面

  • 連線結束

tcp 協議,http協議

hit-alibaba.github.io/interview/b…

tcp協議即是傳輸控制協議,

http協議:

HTTP構建於TCP/IP協議之上,預設埠號是80 HTTP是無連線無狀態的

寫一個繼承函式

原型鏈繼承基本思想就是讓一個原型物件指向另一個型別的例項

function Parent() {
  this.property = true
}
Parent.prototype.getParentValue = function () {
  return this.property
}
function Child() {
  this.Childproperty = false
}
Child.prototype = new Parent()
Child.prototype.getChildValue = function () {
  return this.Childproperty
}
var instance = new Child()
console.log(instance.getParentValue()) // true
複製程式碼

寫一個快速排序

"快速排序"的思想很簡單,整個排序過程只需要三步:

(1)在資料集之中,選擇一個元素作為"基準"(pivot)。

(2)所有小於"基準"的元素,都移到"基準"的左邊;所有大於"基準"的元素,都移到"基準"的右邊。

(3)對"基準"左邊和右邊的兩個子集,不斷重複第一步和第二步,直到所有子集只剩下一個元素為止。
複製程式碼
function quickSort(arr) {
  if(arr.length < 2) {
    return arr;
  } else {
    const pivot = arr[0]; // 基準值
    const pivotArr = []; // 一樣大的放中間
    const lowArr= []; // 小的放左邊
    const hightArr = []; // 大的放右邊
    arr.forEach(current => {
      if(current === pivot) pivotArr.push(current);
      else if(current > pivot) hightArr.push(current);
      else lowArr.push(current);
    })
    return quickSort(lowArr).concat(pivotArr).concat(quickSort(hightArr));
  }
}
複製程式碼

寫一個js判斷全等的方法

//利用JSON.stringify,將兩個物件轉化為字串。
字串相等的話,說明兩個物件全等。
let a = {a:0,b:1,c:2};
let b = {a:0,b:1,c:2};
let c = {a:1,b:1,c:2};
let x = JSON.stringify(a) == JSON.stringify(b);
let y = JSON.stringify(a) == JSON.stringify(c);
console.log(x);
console.log(y);
複製程式碼

遍歷物件的方法

var obj={a:'A',b:'B',c:'C'};

1. for ... in 迴圈
for(key in obj){
    console.log(key);// a,b,c
}

2. Object.keys()
Object.keys(obj);//["a", "b", "c"]
複製程式碼

防抖和節流

1、防抖

觸發高頻事件後n秒內函式只會執行一次,如果n秒內高頻事件再次被觸發,則重新計算時間

  • 思路

每次觸發事件時都取消之前的延時呼叫方法

function debounce(fn) {
      let timeout = null; // 建立一個標記用來存放定時器的返回值
      return function () {
        clearTimeout(timeout); // 每當使用者輸入的時候把前一個 setTimeout clear 掉
        timeout = setTimeout(() => { // 然後又建立一個新的 setTimeout, 這樣就能保證輸入字元後的 interval 間隔內如果還有字元輸入的話,就不會執行 fn 函式
          fn.apply(this, arguments);
        }, 500);
      };
    }
    function sayHi() {
      console.log('防抖成功');
    }

    var inp = document.getElementById('inp');
    inp.addEventListener('input', debounce(sayHi)); // 防抖
複製程式碼

2、節流

高頻事件觸發,但在n秒內只會執行一次,所以節流會稀釋函式的執行頻率

  • 思路

每次觸發事件時都判斷當前是否有等待執行的延時函式

function throttle(fn) {
      let canRun = true; // 通過閉包儲存一個標記
      return function () {
        if (!canRun) return; // 在函式開頭判斷標記是否為true,不為truereturn
        canRun = false; // 立即設定為false
        setTimeout(() => { // 將外部傳入的函式的執行放在setTimeout中
          fn.apply(this, arguments);
          // 最後在setTimeout執行完畢後再把標記設定為true(關鍵)表示可以執行下一次迴圈了。當定時器沒有執行的時候標記永遠是false,在開頭被return掉
          canRun = true;
        }, 500);
      };
    }
    function sayHi(e) {
      console.log(e.target.innerWidth, e.target.innerHeight);
    }
    window.addEventListener('resize', throttle(sayHi));
複製程式碼
  • 問題

為什麼要 fn.apply(this, arguments);而不是這樣 fn()

答:加上 apply 確保 在 sayHi 函式裡的 this 指向的是 input物件(不然就指向 window 了,不是我們想要的)。 這裡的箭頭函式依舊是指向 input 物件。

https怎麼保證安全的?

什麼情況下會碰到跨域問題?有哪些解決方法?

  • 跨域問題是這是瀏覽器為了安全實施的同源策略導致的,同源策略限制了來自不同源的document、指令碼,同源的意思就是兩個URL的域名、協議、埠要完全相同。
  • script標籤jsonp跨域、nginx反向代理、node.js中介軟體代理跨域、後端在頭部資訊設定安全域名、後端在伺服器上設定cors。

如何判斷一個變數是物件還是陣列?

function isObjArr(value){
     if (Object.prototype.toString.call(value) === "[object Array]") {
            console.log('value是陣列');
       }else if(Object.prototype.toString.call(value)==='[object Object]'){//這個方法相容性好一點
            console.log('value是物件');
      }else{
          console.log('value不是陣列也不是物件')
      }
}
//ps:千萬不能使用typeof來判斷物件和陣列,因為這兩種型別都會返回"object"複製程式碼

事件迴圈機制

html事件迴圈:
一個瀏覽器環境,只能有一個事件迴圈,而一個事件迴圈可以多個任務佇列(task queue),每個任務都有一個任務源(task source)。

相同任務源的任務,只能放到一個任務佇列中。

不同任務源的任務,可以放到不同任務佇列中。

EcmaScript規範中指出:
任務佇列(Job queue)是一個先進先出的佇列,每一個任務佇列是有名字的,至於有多少個任務佇列,取決於實現。每一個實現至少應該包含以上兩個任務佇列。

結論:EcmaScript的Job queue與HTML的Task queue有異曲同工之妙。它們都可以有好幾個,多個任務佇列之間的順序都是不保證的。

例子:
setImmediate(function(){ 
   console.log(1); 
},0); 

setTimeout(function(){ 
   console.log(2); 
},0);

new Promise(function(resolve){ 
    console.log(3); 
    resolve(); 
    console.log(4); 
}).then(function(){
    console.log(5); 
}); 

console.log(6); 

process.nextTick(function(){ 
    console.log(7); 
}); 

console.log(8);

結果:3 4 6 8 7 5 2 1

事件註冊順序如下:
setImmediate - setTimeout - promise.then - process.nextTick

優先順序關係:
process.nextTick > promise.then > setTimeout > setImmediate

V8實現中,兩個佇列各包含不同的任務:
macrotasks(巨集任務): script(整體程式碼),setTimeout, setInterval, setImmediate, I/O, UI rendering
microtasks(微任務): process.nextTick, Promises, Object.observe, MutationObserver

執行過程如下:
js引擎首先從macrotask queue中取出第一個任務,執行完畢後,將microtask queue中的所有任務取出,按順序全部執行;然後再從macrotask queue中取下一個,執行完畢後,再次將microtask queue中的全部取出; 迴圈往復,直到兩個queue中的任務都取完。

setTimeout會預設延遲4毫秒(ms)。

問題:
process.nextTick也會放入microtask quque,為什麼優先順序比promise.then高呢?

答:process.nextTick 永遠大於promise.then,原因其實很簡單。
在Node中,_tickCallback在每一次執行完TaskQueue中的一個任務後被呼叫,而這個_tickCallback中實質上幹了兩件事:
1. nextTickQueue中所有任務執行掉(長度最大1e4,Node版本v6.9.1)
2. 第一步執行完後執行_runMicrotasks函式,執行microtask中的部分(promise.then註冊的回撥)
所以很明顯process.nextTick > promise.then

複製程式碼

深拷貝和淺拷貝

區別

1.淺拷貝: 將原物件或原陣列的引用直接賦給新物件,新陣列,新物件/陣列只是原物件的一個引用

2.深拷貝: 建立一個新的物件和陣列,將原物件的各項屬性的“值”(陣列的所有元素)拷貝過來,是“值”而不是“引用”

為什麼要使用深拷貝?

我們希望在改變新的陣列(物件)的時候,不改變原陣列(物件)

深拷貝的要求程度

我們在使用深拷貝的時候,一定要弄清楚我們對深拷貝的要求程度:是僅“深”拷貝第一層級的物件屬性或陣列元素,還是遞迴拷貝所有層級的物件屬性和陣列元素?

怎麼檢驗深拷貝成功

改變任意一個新物件/陣列中的屬性/元素, 都不改變原物件/陣列

只做第一層深拷貝

深拷貝陣列(只拷貝第一級陣列元素)

  1. 直接遍歷
var arr = [1,2,3,4];


function copy(arg){
  
  var newArr = [];
  
  for(var i = 0; i < arr.length; i++) {
    newArr.push(arr[i]);
  }
  
  return newArr;
}

var newArry = copy(arr);
console.log(newArry);
newArry[0] = 10;
console.log(newArry); // [10,2,3,4]
console.log(arr)  // [1,2,3,4]
複製程式碼
  1. slice()
var arr = [1,2,3,4]
var copyArr = arr.slice();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

// slice() 方法返回一個從已有的陣列中擷取一部分元素片段組成的新陣列(不改變原來的陣列!)
用法:array.slice(start,end) start表示是起始元素的下標, end表示的是終止元素的下標
當slice()不帶任何引數的時候,預設返回一個長度和原陣列相同的新陣列

複製程式碼
  1. concat()
var arr = [1,2,3,4]
var copyArr = arr.concat();
copyArr[0] = 10;
console.log(copyArr); // [10,2,3,4]
console.log(arr); // [1,2,3,4]

//concat() 方法用於連線兩個或多個陣列。( 該方法不會改變現有的陣列,而僅僅會返回被連線陣列的一個副本。)
用法:array.concat(array1,array2,......,arrayN)
因為我們上面呼叫concat的時候沒有帶上引數,所以var copyArray = array.concat();實際上相當於var copyArray = array.concat([]);
也即把返回陣列和一個空陣列合並後返回
複製程式碼

深拷貝物件

1.直接遍歷

 var obj = {
    name: "張三",
    job: "學生"
  }
  
  function copy (obj) {
    let newobj = {}
    for(let item in obj) {
      newobj[item] = obj[item];
    }
    return newobj;
  }
  
  var copyobj = copy(obj)
  copyobj.name = "李四"
  console.log(copyobj) // {name: '李四', job:: '學生'}
  console.log(obj) // {name: '張三', job:: '學生'}

複製程式碼
  1. ES6的Object.assign
var obj = {
 name: '張三',
 job: '學生'
}

var copyobj = Object.assign({},obj)
copyobj.name = '李四'
console.log(copyobj) // {name: '李四', job:: '學生'}
console.log(obj)    // {name: '張三', job:: '學生'}

Object.assign:用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target),並返回合併後的target
用法: Object.assign(target, source1, source2);  所以 copyObj = Object.assign({}, obj);  這段程式碼將會把obj中的一級屬性都拷貝到 {}中,然後將其返回賦給copyObj
複製程式碼
  1. ES6擴充套件運算子:
var obj = {
  name: '張三',
  job: '學生'
}

var copyobj = {...obj}
copyobj.name = '李四'
console.log(copyobj)
console.log(obj)

擴充套件運算子(...)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中
複製程式碼

ajax請求

// 1.XMLHttpRequest物件用於在後臺與伺服器交換資料   
var xhr = new XMLHttpRequest();
// 2.
xhr.open('GET', url, true);
//3.傳送請求
xhr.send();
//4.接收返回
//客戶端和伺服器端有互動的時候會呼叫onreadystatechange
xhr.onreadystatechange = function() {
    // readyState == 4說明請求已完成
    if (xhr.readyState == 4 && xhr.status == 200 || xhr.status == 304) { 
        // 從伺服器獲得資料 
        fn.call(this, xhr.responseText);  
    }
};
複製程式碼

相關文章