【 學 ES6 ?】 先看看這篇文章,還清ES5的賬吧!

一、前言

  • 雖然不少人入門ES6都是去阮一峯老師的ES6教程ECMAScript 6 入門,可是注意了,阮老師開篇就建議若是你的js基礎不夠紮實,仍是先把基礎打紮實再回來學es6。出來混,ES5的債,早晚要還滴!!(泛指ES6以前的基礎知識)

知識點1:屬性描述對象(詳細資料連接

注:下方基礎題若是對你來你說不能很好的回答,請點擊上方詳細資料連接,系統學習這個知識點 javascript

JavaScript 提供了一個內部數據結構,用來描述對象的屬性,控制它的行爲,好比該屬性是否可寫、可遍歷等等。這個內部數據結構稱爲屬性描述對象(attributes object)php

1 問題一:屬性描述對象有哪些

  1. value
  2. writable
  3. enumerabele
  4. configurable
  5. get
  6. set

2 問題二:configurable的做用,以及設爲false有哪些影響

configurable(可配置性)返回一個布爾值,決定了是否能夠修改屬性描述對象。也就是說,configurable爲false時,value、writable、enumerable和configurable都不能被修改了。css

var obj = Object.defineProperty({}, 'p', {
  value: 1,
  writable: false,
  enumerable: false,
  configurable: false
});

Object.defineProperty(obj, 'p', {value: 2})
// TypeError: Cannot redefine property: p

Object.defineProperty(obj, 'p', {writable: true})
// TypeError: Cannot redefine property: p

Object.defineProperty(obj, 'p', {enumerable: true})
// TypeError: Cannot redefine property: p

Object.defineProperty(obj, 'p', {configurable: true})
// TypeError: Cannot redefine property: p
複製代碼

上面代碼中,obj.p的configurable爲false。而後,改動value、writable、enumerable、configurable,結果都報錯。html

注意,writable只有在false改成true會報錯,true改成false是容許的。html5

var obj = Object.defineProperty({}, 'p', {
  writable: true,
  configurable: false
});

Object.defineProperty(obj, 'p', {writable: false})
// 修改爲功
至於value,只要writable和configurable有一個爲true,就容許改動。

var o1 = Object.defineProperty({}, 'p', {
  value: 1,
  writable: true,
  configurable: false
});

Object.defineProperty(o1, 'p', {value: 2})
// 修改爲功

var o2 = Object.defineProperty({}, 'p', {
  value: 1,
  writable: false,
  configurable: true
});

Object.defineProperty(o2, 'p', {value: 2})
// 修改爲功
複製代碼

另外,writable爲false時,直接目標屬性賦值,不報錯,但不會成功。java

var obj = Object.defineProperty({}, 'p', {
  value: 1,
  writable: false,
  configurable: false
});

obj.p = 2;
obj.p // 1
複製代碼

上面代碼中,obj.p的writable爲false,對obj.p直接賦值不會生效。若是是嚴格模式,還會報錯。node

可配置性決定了目標屬性是否能夠被刪除(delete)。es6

var obj = Object.defineProperties({}, {
  p1: { value: 1, configurable: true },
  p2: { value: 2, configurable: false }
});

delete obj.p1 // true
delete obj.p2 // false

obj.p1 // undefined
obj.p2 // 2
複製代碼

上面代碼中,obj.p1的configurable是true,因此能夠被刪除,obj.p2就沒法刪除。正則表達式

接下來就不寫問題了,若是以上問題你沒有很好的答上來,就能夠點開連接開學了,嘿嘿json

知識點2:RegExp 對象(詳細資料連接

注:下方基礎題若是對你來你說不能很好的回答,請點擊上方詳細資料連接,系統學習這個知識點

1 問題一:知道正則裏\1, \2表示什麼意思嗎?

/(.)b(.)\1b\2/.test("abcabc") // true
複製代碼
  • 正則表達式內部,還能夠用\n引用括號匹配的內容,n是從1開始的天然數,表示對應順序的括號。
  • 上面的代碼中,\1表示第一個括號匹配的內容(即a),\2表示第二個括號匹配的內容(即c)。

2 String.prototype.replace()中,第二個參數能夠是字符串或者函數,當是字符串的時候$1,$2表示什麼意思?

'hello world'.replace(/(\w+)\s(\w+)/, '$2 $1')
// "world hello"
複製代碼

replace方法的第二個參數可使用美圓符號$,用來指代所替換的內容。

  • $&:匹配的子字符串。
  • $`:匹配結果前面的文本。
  • $':匹配結果後面的文本。
  • $n:匹配成功的第n組內容,n是從1開始的天然數。
  • $$:指代美圓符號$。

3 貪婪模式是什麼?

var s = 'aaa';
s.match(/a+/) // ["aaa"]
s.match(/a+?/) // ["a"]
複製代碼

上面爲何不同呢,由於兩次+以後有個,這是開啓非貪婪模式的標記。

除了非貪婪模式的加號,還有非貪婪模式的星號(*)和非貪婪模式的問號(?)。

  • +?:表示某個模式出現1次或屢次,匹配時採用非貪婪模式。
  • *?:表示某個模式出現0次或屢次,匹配時採用非貪婪模式。
  • ??:表格某個模式出現0次或1次,匹配時採用非貪婪模式。

4 請看如下案例, 爲何返回false?知道lastIndex屬性嗎?

var r = /x/g;
var s = '_x_x';

r.lastIndex = 4;
r.test(s) // false
複製代碼

5 字符串的match方法,第一個參數能夠是正則,那正則裏有g的模式有什麼問題嗎?

注意,使用組匹配時,不宜同時使用g修飾符,不然match方法不會捕獲分組的內容。

var m = 'abcabc'.match(/(.)b(.)/g);
m // ['abc', 'abc']
複製代碼

能夠看到,捕獲組沒有捕獲分組內容。可是match不加g模式的時候,能捕獲第一次遇見的捕獲組內容

var m = 'abcabc'.match(/(.)b(.)/);
m
// ['abc', 'a', 'c']
複製代碼

6 知道非捕獲組、先行斷言、先行否認斷言嗎?

(?:x)稱爲非捕獲組(Non-capturing group),表示不返回該組匹配的內容,即匹配的結果中不計入這個括號。

var m = 'abc'.match(/(?:.)b(.)/);
m // ["abc", "c"]
複製代碼

上面代碼中的模式,一共使用了兩個括號。其中第一個括號是非捕獲組,因此最後返回的結果中沒有第一個括號,只有第二個括號匹配的內容。

x(?=y)稱爲先行斷言(Positive look-ahead),x只有在y前面才匹配,y不會被計入返回結果。好比,要匹配後面跟着百分號的數字,能夠寫成/\d+(?=%)/

「先行斷言」中,括號裏的部分是不會返回的。

var m = 'abc'.match(/b(?=c)/);
m // ["b"]
複製代碼

上面的代碼使用了先行斷言,b在c前面因此被匹配,可是括號對應的c不會被返回。

x(?!y)稱爲先行否認斷言(Negative look-ahead),x只有不在y前面才匹配,y不會被計入返回結果。好比,要匹配後面跟的不是百分號的數字,就要寫成/\d+(?!%)/

/\d+(?!\.)/.exec('3.14')
// ["14"]
複製代碼

上面代碼中,正則表達式指定,只有不在小數點前面的數字纔會被匹配,所以返回的結果就是14。

「先行否認斷言」中,括號裏的部分是不會返回的。

var m = 'abd'.match(/b(?!c)/);
m // ['b']
複製代碼

上面的代碼使用了先行否認斷言,b不在c前面因此被匹配,並且括號對應的d不會被返回。

知識點3:實例對象和new命令(詳細資料連接

1 知道new 命令的原理嗎?

使用new命令時,它後面的函數依次執行下面的步驟。

  • 建立一個空對象,做爲將要返回的對象實例。
  • 將這個空對象的原型,指向構造函數的prototype屬性。
  • 將這個空對象賦值給函數內部的this關鍵字。
  • 開始執行構造函數內部的代碼。

2 知道new.target,Object.create()嗎?

函數內部可使用new.target屬性。若是當前函數是new命令調用,new.target指向當前函數,不然爲undefined。

function f() {
  console.log(new.target === f);
}

f() // false
new f() // true
複製代碼

構造函數做爲模板,能夠生成實例對象。可是,有時拿不到構造函數,只能拿到一個現有的對象。咱們但願以這個現有的對象做爲模板,生成新的實例對象,這時就可使用Object.create()方法。

var person1 = {
  name: '張三',
  age: 38,
  greeting: function() {
    console.log('Hi! I\'m ' + this.name + '.'); } }; var person2 = Object.create(person1); person2.name // 張三 person2.greeting() // Hi! I'm 張三.
複製代碼

上面代碼中,對象person1是person2的模板,後者繼承了前者的屬性和方法。

知識點4:DOM事件模型

1 DOM裏監聽函數的this指向哪裏?(詳細資料連接)

// 例如:
// HTML 代碼以下
// <button id="btn">點擊</button>
var btn = document.getElementById('btn');

btn.addEventListener(
  'click',
  function (e) {
    console.log(this.id);
  },
  false
);
複製代碼

上面的代碼裏,this指向的是觸發事件的那個元素節點

2 鼠標事件相關問題?(詳細資料連接)

2.1 鼠標裏的雙擊事件是什麼,鼠標按下右鍵觸發什麼事件?

  • dblclick:在同一個元素上雙擊鼠標時觸發。
  • contextmenu:按下鼠標右鍵時(上下文菜單出現前)觸發,或者按下「上下文菜單鍵」時觸發。

2.2 鼠標事件裏clientX, screenX, offsetX有什麼區別?

  • MouseEvent.clientX屬性返回鼠標位置相對於瀏覽器窗口左上角的水平座標(單位像素)
  • MouseEvent.screenX屬性返回鼠標位置相對於屏幕左上角的水平座標(單位像素)
  • MouseEvent.offsetX屬性返回鼠標位置與目標節點左側的padding邊緣的水平距離(單位像素)

圖示以下:

2.3 如何知道用戶是否按下了大寫鍵?

MouseEvent.getModifierState方法返回一個布爾值,表示有沒有按下特定的功能鍵。它的參數是一個表示功能鍵的字符串。

document.addEventListener('click', function (e) {
  console.log(e.getModifierState('CapsLock'));
}, false);
複製代碼

知識點5:touch事件相關問題?(詳細資料連接)

1 什麼是Touchlist?

  • 由Touch對象構成的數組,經過event.touches取到。
  • 一個Touch對象表明一個觸點,當有多個手指觸摸屏幕時,TouchList就會存儲多個Touch對象。

2 touch事件裏TouchEvent.touches和TouchEvent.changedTouches的區別是什麼?

  • changedTouches也是一個 TouchList 對象,對於touchstart 事件, 這個 TouchList 對象列出在這次事件中新增長的觸點。
  • 對於touchmove事件,列出和上一次事件相比較,發生了變化的觸點。對於touchend ,列出離開觸摸平面的觸點(這些觸點對應已經不接觸觸摸平面的手指)。

touchend這裏要特別注意,touches和targetTouches只存儲接觸屏幕的觸點,要獲取觸點最後離開的狀態要使用changedTouches。

知識點6 drag & drop事件相關問題?(詳細資料連接)

1 綁定在拖拽目標的事件和綁定在放置目標的事件分別有哪些?

綁定在拖拽目標

事件名 描述
dragstart 當用戶開始拖拽一個元素或者一個文本選取區塊的時觸發
drag 當用戶正在拖拽一個元素或者一個文本選取區塊的時觸發
dragend 當用戶結束拖拽一個元素或者一個文本選取區塊的時觸發。(如放開鼠標按鍵或按下鍵盤的 escap 鍵)

綁定在放置目標

事件名 描述
dragenter 當用戶開始拖拽一個元素或者一個文本選取區塊的時觸發
dragover 當用戶正在拖拽一個元素或者一個文本選取區塊的時觸發
dragleave 當用戶結束拖拽一個元素或者一個文本選取區塊的時觸發。(如放開鼠標按鍵或按下鍵盤的 escap 鍵)
drop 當一個元素或文字選取區塊被放置至一個有效的放置目標時觸發。

2 將文件從操做系統拉進瀏覽器,會觸發dragstart和dragend事件嗎?

不會

3 爲何要在dragover事件上阻止默認事件(event.preventDefault())?

  • 因爲網頁的大部分區域不適合做爲放下拖拉元素的目標節點,因此這個事件的默認設置爲當前節點不容許接受被拖拉的元素。
  • 若是想要在目標節點上放下的數據,首先必須阻止這兩個事件的默認行爲。

4 在進行拖放時,每一個event對象中都有DataTransfer對象來保存被拖動的數據,請問,DataTranfer中dropEffect屬性和effectAllowed屬性的區別?

  • DataTransfer.dropEffect屬性用來設置放下(drop)被拖拉節點時的效果,會影響到拖拉通過相關區域時鼠標的形狀。 例如:
target.addEventListener('dragover', function (e) {
  e.preventDefault();
  e.stopPropagation();
  e.dataTransfer.dropEffect = 'copy';
});
複製代碼
  • DataTransfer.effectAllowed屬性設置本次拖拉中容許的效果。例如:
source.addEventListener('dragstart', function (e) {
  e.dataTransfer.effectAllowed = 'move';
});

target.addEventListener('dragover', function (e) {
  ev.dataTransfer.dropEffect = 'move';
});
複製代碼

5 如何利用dataTransfer對象傳遞數據?

主要是用到DataTransfer.setData()DataTransfer.getData()方法, 例如

document.addEventListener('dragstart', function (event) {
  // 被拖拉節點的背景色變透明
  event.dataTransfer.setData('data',this.nodeName);
}, false);

document.addEventListener('drop', function( event ) {
  // 防止事件默認行爲(好比某些元素節點上能夠打開連接),
  event.preventDefault();
  console.log(event.dataTransfer.getData('data'))
}, false);
複製代碼

知識點6 瀏覽器加載腳本和渲染相關問題(詳細資料連接)

1 請簡要說一下瀏覽器加載js腳本的原理?

正常的網頁加載流程是這樣的。

  • 瀏覽器一邊下載 HTML網頁,一邊開始解析。也就是說,不等到下載完,就開始解析。
  • 解析過程當中,瀏覽器發現<script>元素,就暫停解析,把網頁渲染的控制權轉交給 JavaScript 引擎。
  • 若是<script>元素引用了外部腳本,就下載該腳本再執行,不然就直接執行代碼。
  • JavaScript 引擎執行完畢,控制權交還渲染引擎,恢復往下解析 HTML 網頁。

2 爲何加載外部腳本時,瀏覽器會暫停頁面渲染?

緣由是 JavaScript 代碼能夠修改 DOM,因此必須把控制權讓給它,不然會致使複雜的線程競賽的問題

3 從以上js腳本加載原理來看,爲何js腳本最好放在頁面底部?

  • 若是外部腳本加載時間很長(一直沒法完成下載),那麼瀏覽器就會一直等待腳本下載完成,形成網頁長時間失去響應,瀏覽器就會呈現「假死」狀態,這被稱爲「阻塞效應」。

  • 爲了不這種狀況,較好的作法是<script>標籤都放在頁面底部

4 加載css會阻塞DOM的解析嗎?加載css會阻塞DOM的渲染嗎?

css的加載和解析不會阻塞html的解析,但會阻塞渲染。

5 不一樣的瀏覽器有哪些知名的渲染引擎?渲染引擎的渲染流程是什麼?

不一樣的瀏覽器有不一樣的渲染引擎。

  • Firefox:Gecko 引擎
  • Safari:WebKit 引擎
  • Chrome:Blink 引擎
  • IE: Trident 引擎
  • Edge: EdgeHTML 引擎

渲染引擎處理網頁,一般分紅四個階段。

  • 解析代碼:HTML 代碼解析爲 DOM,CSS 代碼解析爲CSSOM(CSS Object Model)。
  • 對象合成:將 DOM 和 CSSOM 合成一棵渲染樹(render tree)。
  • 佈局:計算出渲染樹的佈局(layout)。
  • 繪製:將渲染樹繪製到屏幕。

以上四步並不是嚴格按順序執行,每每第一步還沒完成,第二步和第三步就已經開始了。因此,會看到這種狀況:網頁的 HTML 代碼還沒下載完,但瀏覽器已經顯示出內容了。

5.5 瀏覽器渲染中發生的重回和重流是什麼?

  • 渲染樹轉換爲網頁佈局,稱爲佈局流(flow);佈局顯示到頁面的這個過程,稱爲繪製(paint)。它們都具備阻塞效應,而且會耗費不少時間和計算資源。

  • 頁面生成之後,腳本操做和樣式表操做,都會觸發重流(reflow)重繪(repaint)。用戶的互動也會觸發重流和重繪,好比設置了鼠標懸停(a:hover)效果、頁面滾動、在輸入框中輸入文本、改變窗口大小等等。

  • 重流重繪並不必定一塊兒發生,重流必然致使重繪重繪不必定須要重流。好比改變元素顏色,只會致使重繪,而不會致使重流;改變元素的佈局,則會致使重繪和重流。

5.6 瀏覽器解析js的大概過程?

早期,瀏覽器內部對 JavaScript 的處理過程以下:

  • 讀取代碼,進行詞法分析(Lexical analysis),將代碼分解成詞元(token)。
  • 對詞元進行語法分析(parsing),將代碼整理成「語法樹」(syntax tree)。
  • 使用「翻譯器」(translator),將代碼轉爲字節碼(bytecode)。
  • 使用「字節碼解釋器」(bytecode interpreter),將字節碼轉爲機器碼。

逐行解釋將字節碼轉爲機器碼,是很低效的。爲了提升運行速度,現代瀏覽器改成採用「即時編譯」(Just In Time compiler,縮寫 JIT),即字節碼只在運行時編譯,用到哪一行就編譯哪一行,而且把編譯結果緩存(inline cache)。一般,一個程序被常常用到的,只是其中一小部分代碼,有了緩存的編譯結果,整個程序的運行速度就會顯著提高。

知識點7 cookie(詳細資料連接)

1 cookie的數量和大小限制是多少?

不一樣瀏覽器對 Cookie 數量和大小的限制,是不同的。通常來講,單個域名設置的 Cookie 不該超過30個,每一個 Cookie 的大小不能超過4KB。超過限制之後,Cookie 將被忽略,不會被設置 。

2 什麼狀況下,兩個網址能共享cookie?

瀏覽器的同源政策規定,兩個網址只要域名相同和端口相同,就能夠共享 Cookie(參見《同源政策》一章)。注意,這裏不要求協議相同。也就是說,example.com 設置的 Cookie,能夠被https://example.com讀取。

3 設置cookie裏的Expires,Max-Age字段的區別是什麼?

  • Expires屬性指定一個具體的到期時間,到了指定時間之後,瀏覽器就再也不保留這個 Cookie。它的值是 UTC 格式,可使用Date.prototype.toUTCString()進行格式轉換。
Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT;
複製代碼
  • Max-Age屬性:指定從如今開始 Cookie 存在的秒數,好比60 * 60 * 24 * 365(即一年)。過了這個時間之後,瀏覽器就再也不保留這個 Cookie。

  • 若是同時指定了ExpiresMax-Age,那麼Max-Age的值將優先生效。

  • 若是Set-Cookie字段沒有指定ExpiresMax-Age屬性,那麼這個 Cookie 就是 Session Cookie,即它只在本次對話存在,一旦用戶關閉瀏覽器,瀏覽器就不會再保留這個 Cookie

4 設置cookie裏的Secure,HttpOnly字段的區別是什麼?

Secure屬性指定瀏覽器只有在加密協議 HTTPS 下,才能將這個 Cookie 發送到服務器。該屬性只是一個開關,不須要指定值。若是通訊是 HTTPS 協議,該開關自動打開。

HttpOnly屬性指定該 Cookie 沒法經過 JavaScript 腳本拿到,主要是document.cookie屬性、XMLHttpRequest對象和 Request API 都拿不到該屬性。

知識點8 同源限制相關問題

1 同源指的是什麼?

  • 協議相同
  • 域名相同
  • 端口相同

23 哪些行爲受到同源策略的限制?

目前,若是非同源,共有三種行爲受到限制

(1) 沒法讀取非同源網頁的 Cookie、LocalStorage 和 IndexedDB。

(2) 沒法接觸非同源網頁的 DOM。

(3) 沒法向非同源地址發送 AJAX 請求(能夠發送,但瀏覽器會拒絕接受響應)
複製代碼

3 HTML5如何實現窗口間數據通訊,請簡要介紹一下?(詳細資料

postMessage是html5引入的API,postMessage()方法容許來自不一樣源的腳本採用異步方式進行有效的通訊,能夠實現跨文本文檔,多窗口,跨域消息傳遞.多用於窗口間數據通訊,這也使它成爲跨域通訊的一種有效的解決方案。

舉一個postMessage跨域通訊的案例,並介紹其API

父窗體建立跨域iframe併發送信息

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	
<iframe src="http://127.0.0.1:9090/b.html" name="postIframe" onload="messageLoad()"></iframe>

<script>
	function messageLoad(){
		var url = "http://127.0.0.1:9090";
		window.postIframe.postMessage("給我tsort的信息",url); //發送數據
	}

	window.onmessage = function(e){
		e = e || event;
		console.log(e.data); //接收b返回的數據,在控制檯有兩次輸出
	}
</script>
</body>
</html>
複製代碼

子窗體接收信息並處理

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<script>
	window.onmessage = function(e){
		e = e || event;
		alert(e.data); //當即彈出a發送過來的數據
		e.source.postMessage("好的,請稍等三秒!",e.origin); //當即回覆a

		var postData = {name:"tsrot",age:24};
		var strData = JSON.stringify(postData); //json對象轉化爲字符串
		setTimeout(function(){
			e.source.postMessage(strData,e.origin);
		},3000); //3秒後向a發送數據
	}
</script>
</body>
</html>
複製代碼

4 克服了 AJAX 只能同源使用的限制的CORS請介紹一下?(詳細資料

4.1 CORS裏的簡單請求和非簡單請求的區別是什麼?

只要同時知足如下兩大條件,就屬於簡單請求。

1)請求方法是如下三種方法之一。

HEAD
GET
POST
複製代碼

2)HTTP 的頭信息不超出如下幾種字段。

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限於三個值application/x-www-form-urlencoded、multipart/form-data、text/plain
複製代碼

4.2 瀏覽器發現此次跨域 AJAX 請求是簡單請求,就自動在頭信息之中添加哪一個字段,表示什麼意思?

添加一個Origin字段。說明本次請求來自哪一個域(協議 + 域名 + 端口)

4.3 若是origin指定的地址,不在服務器的許可範圍內,瀏覽器會怎樣,那在服務器許可的範圍,響應頭會多出哪幾個字段?

若是Origin指定的源,不在許可範圍內,服務器會返回一個正常的 HTTP 迴應。瀏覽器發現,這個迴應的頭信息沒有包含Access-Control-Allow-Origin字段(詳見下文),就知道出錯了,從而拋出一個錯誤,被XMLHttpRequestonerror回調函數捕獲。注意,這種錯誤沒法經過狀態碼識別,由於 HTTP 迴應的狀態碼有多是200。

若是Origin指定的域名在許可範圍內,服務器返回的響應,會多出幾個頭信息字段。

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: FooBar
Content-Type: text/html; charset=utf-8
複製代碼

4.4 Access-Control-Allow-Credentials: true表示什麼意思?

  • CORS 請求默認不包含 Cookie 信息(以及 HTTP 認證信息等),這是爲了下降 CSRF 攻擊的風險。
  • 可是某些場合,服務器可能須要拿到 Cookie,這時須要服務器顯式指定Access-Control-Allow-Credentials字段,告訴瀏覽器能夠發送 Cookie。

4.5 非簡單請求中的預檢請求是什麼,預檢請求有哪些不一樣於普通請求的請求頭?

  • 非簡單請求的 CORS 請求,會在正式通訊以前,增長一次 HTTP 查詢請求,稱爲預檢請求(preflight)
  • 瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使用哪些 HTTP 方法和頭信息字段。

舉例:

var url = 'http://api.alice.com/cors';
var xhr = new XMLHttpRequest();
xhr.open('PUT', url, true);
xhr.setRequestHeader('X-Custom-Header', 'value');
xhr.send();
複製代碼

上面代碼中,HTTP 請求的方法是PUT,而且發送一個自定義頭信息X-Custom-Header

瀏覽器發現,這是一個非簡單請求,就自動發出一個「預檢」請求,要求服務器確承認以這樣請求。下面是這個「預檢」請求的 HTTP 頭信息。

OPTIONS /cors HTTP/1.1
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...
複製代碼

「預檢」請求用的請求方法是OPTIONS,表示這個請求是用來詢問的。頭信息裏面,關鍵字段是Origin,表示請求來自哪一個源。

除了Origin字段,「預檢」請求的頭信息包括兩個特殊字段。

(1)Access-Control-Request-Method
複製代碼

該字段是必須的,用來列出瀏覽器的 CORS 請求會用到哪些 HTTP 方法,上例是PUT。

(2)Access-Control-Request-Headers
複製代碼

該字段是一個逗號分隔的字符串,指定瀏覽器 CORS 請求會額外發送的頭信息字段,上例是X-Custom-Header。

4.6 預檢請求的響應?

  • 非簡單請求的 CORS 請求,會在正式通訊以前,增長一次 HTTP 查詢請求,稱爲預檢請求(preflight)
  • 瀏覽器先詢問服務器,當前網頁所在的域名是否在服務器的許可名單之中,以及可使用哪些 HTTP 方法和頭信息字段。

服務器收到「預檢」請求之後,檢查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段之後,確認容許跨源請求,就能夠作出迴應。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain
複製代碼

知識點9 history對象訪問瀏覽器會話歷史API相關問題?(詳細資料連接)

1 history.pushState()是什麼意思,它會跳轉網頁嗎?

History.pushState()方法用於在歷史中添加一條記錄。

window.history.pushState(state, title, url)
複製代碼

該方法接受三個參數,依次爲:

  • state:一個與添加的記錄相關聯的狀態對象,主要用於popstate事件。該事件觸發時,該對象會傳入回調函數。也就是說,瀏覽器會將這個對象序列化之後保留在本地,從新載入這個頁面的時候,能夠拿到這個對象。若是不須要這個對象,此處能夠填null。
  • title:新頁面的標題。可是,如今全部瀏覽器都忽視這個參數,因此這裏能夠填空字符串。
  • url:新的網址,必須與當前頁面處在同一個域。瀏覽器的地址欄將顯示這個網址。 假定當前網址是example.com/1.html,使用pushState()方法在瀏覽記錄(History 對象)中添加一個新記錄。
var stateObj = { foo: 'bar' };
history.pushState(stateObj, 'page 2', '2.html');
複製代碼

此API不會跳轉網頁。

2 history.pushState()以後,用戶點擊瀏覽器的倒退按鈕,會觸發什麼事件?

會觸發popstate 事件 使用方法以下

window.addEventListener('popstate', function(event) {
  console.log('location: ' + document.location);
  console.log('state: ' + JSON.stringify(event.state));
});
複製代碼

知識點10 URL對象相關問題?(詳細資料連接)

1 URL 的編碼和解碼中,URL只能包含兩類合法的字符,是那兩類?

  • URL 元字符:分號(;)逗號(,)斜槓(/)問號(?)冒號(:)at(@)&等號(=)加號(+)美圓符號($)井號(#)
  • 語義字符:a-zA-Z0-9連詞號(-)下劃線(_)點(.)感嘆號(!)波浪線(~)星號(*)單引號(')圓括號(())

除了以上字符,其餘字符出如今 URL 之中都必須轉義,規則是根據操做系統的默認編碼,將每一個字節轉爲百分號(%)加上兩個大寫的十六進制字母。

2 URL提供了哪些URL的編碼/解碼方法?

JavaScript 提供四個 URL 的編碼/解碼方法。

  • encodeURI()
  • encodeURIComponent()
  • decodeURI()
  • decodeURIComponent()

一、 encodeURI()

encodeURI()方法用於轉碼整個 URL。它的參數是一個字符串,表明整個 URL。它會將元字符和語義字符以外的字符,都進行轉義。

encodeURI('http://www.example.com/q=春節')
// "http://www.example.com/q=%E6%98%A5%E8%8A%82"
複製代碼

二、encodeURIComponent()

encodeURIComponent()方法用於轉碼 URL 的組成部分,會轉碼除了語義字符以外的全部字符,即元字符也會被轉碼。因此,它不能用於轉碼整個 URL。它接受一個參數,就是 URL 的片斷。

encodeURIComponent('春節')
// "%E6%98%A5%E8%8A%82"
encodeURIComponent('http://www.example.com/q=春節')
// "http%3A%2F%2Fwww.example.com%2Fq%3D%E6%98%A5%E8%8A%82"
複製代碼

上面代碼中,encodeURIComponent()會連 URL 元字符一塊兒轉義,因此若是轉碼整個 URL 就會出錯。

三、decodeURI() 四、decodeURIComponent()

3和4,都是1,2的逆運算

3 URL對象的實例有哪些經常使用屬性和方法?

var url = new URL('http://www.example.com:4097/path/a.html?x=111#part1');

url.href
// "http://user:passwd@www.example.com:4097/path/a.html?x=111#part1"
url.pathname
// "/path/a.html"
url.search
// "?x=111"
複製代碼

經常使用的靜態方法有

  • URL.createObjectURL()

我本身常常會用這個API作本地圖片預覽。以下案例

<body>
	<div id="display" />
	<input type="file" id="fileElem" multiple accept="image/*" onchange="handleFiles(this.files)">
	<script>
		var div = document.getElementById('display');

		function handleFiles(files) {
			for (var i = 0; i < files.length; i++) {
				var img = document.createElement('img');
				console.log(window.URL.createObjectURL(files[i]))
				img.src = window.URL.createObjectURL(files[i]);
				div.appendChild(img);
			}
		}
	</script>
</body>

複製代碼

注意,每次使用URL.createObjectURL方法,都會在內存裏面生成一個 URL 實例。若是再也不須要該方法生成的 URL 字符串,爲了節省內存,可使用URL.revokeObjectURL()方法釋放這個實例。

  • URL.revokeObjectURL()

URL.revokeObjectURL方法用來釋放URL.createObjectURL方法生成的 URL 實例。它的參數就是URL.createObjectURL方法返回的 URL 字符串。

下面爲上一段的示例加上URL.revokeObjectURL()。

var div = document.getElementById('display');

function handleFiles(files) {
  for (var i = 0; i < files.length; i++) {
    var img = document.createElement('img');
    img.src = window.URL.createObjectURL(files[i]);
    div.appendChild(img);
    img.onload = function() {
      window.URL.revokeObjectURL(this.src);
    }
  }
}
複製代碼

知識點11 Blob 對象?(詳細資料連接)

Blob構造函數接受兩個參數。第一個參數是數組,成員是字符串或二進制對象,表示新生成的Blob實例對象的內容;第二個參數是可選的,是一個配置對象,目前只有一個屬性type,它的值是一個字符串,表示數據的 MIME 類型,默認是空字符串。

var htmlFragment = ['<a id="a"><b id="b">hey!</b></a>'];
var myBlob = new Blob(htmlFragment, {type : 'text/html'});
複製代碼

1 Blob對象的實例如何保存JSON?

例子以下:

var obj = { hello: 'world' };
var blob = new Blob([ JSON.stringify(obj) ], {type : 'application/json'});
複製代碼

2 File 對象是什麼?(詳細資料

File對象表明一個文件,用來讀寫文件信息。它繼承了 Blob對象,或者說是一種特殊的 Blob對象,全部可使用 Blob 對象的場合均可以使用它。 下面代碼中,file是用戶選中的第一個文件,它是 File 的實例。

// HTML 代碼以下
// <input id="fileItem" type="file">
var file = document.getElementById('fileItem').files[0];
file instanceof File // true
複製代碼

3 FileReader 對象是什麼?

FileReader對象用於讀取File對象或Blob對象所包含的文件內容。

瀏覽器原生提供一個FileReader構造函數,用來生成 FileReader 實例。

var reader = new FileReader();
複製代碼

經常使用的FileReader 有如下的實例屬性

  • FileReader.result:讀取完成後的文件內容,有多是字符串,也多是一個 ArrayBuffer 實例。
  • FileReader.onload:load事件(讀取操做完成)的監聽函數,一般在這個函數裏面使用result屬性,拿到文件內容。

下面是監聽load事件的一個例子。

// HTML 代碼以下
// <input type="file" onchange="onChange(event)">

function onChange(event) {
  var file = event.target.files[0];
  var reader = new FileReader();
  reader.onload = function (event) {
    console.log(event.target.result)
  };

  reader.readAsText(file);
}
複製代碼

FileReader 比較重要的實例方法。

  • FileReader.readAsDataURL():讀取完成後,result屬性將返回一個 Data URL 格式(Base64 編碼)的字符串,表明文件內容。對於圖片文件,這個字符串能夠用於<img>元素的src屬性。注意,這個字符串不能直接進行 Base64 解碼,必須把前綴data:*/*;base64,從字符串裏刪除之後,再進行解碼。
  • FileReader.readAsText():讀取完成後,result屬性將返回文件內容的文本字符串。該方法的第一個參數是表明文件的 Blob 實例,第二個參數是可選的,表示文本編碼,默認爲 UTF-8

下面是一個例子。

/* HTML 代碼以下
  <input type="file" onchange="previewFile()">
  <img src="" height="200">
*/

function previewFile() {
  var preview = document.querySelector('img');
  var file    = document.querySelector('input[type=file]').files[0];
  var reader  = new FileReader();

  reader.addEventListener('load', function () {
    preview.src = reader.result;
  }, false);

  if (file) {
    reader.readAsDataURL(file);
  }
複製代碼

知識點12 FormData 對象?(詳細資料連接)

Blob構造函數接受兩個參數。第一個參數是數組,成員是字符串或二進制對象,表示新生成的Blob實例對象的內容;第二個參數是可選的,是一個配置對象,目前只有一個屬性type,它的值是一個字符串,表示數據的MIME 類型,默認是空字符串。

1 FormData 對象的實例,有哪些經常使用的方法?

  • FormData.append(key, value):添加一個鍵值對。若是鍵名重複,則會生成兩個相同鍵名的鍵值對。若是第二個參數是文件,還可使用第三個參數,表示文件名。
  • FormData.set(key, value):設置指定鍵名的鍵值,參數爲鍵名。若是鍵名不存在,會添加這個鍵值對,不然會更新指定鍵名的鍵值。若是第二個參數是文件,還可使用第三個參數,表示文件名。
  • FormData.delete(key):刪除一個鍵值對,參數爲鍵名。
  • FormData.get(key):獲取指定鍵名對應的鍵值,參數爲鍵名。若是有多個同名的鍵值對,則返回第一個鍵值對的鍵值。
  • FormData.getAll(key):返回一個數組,表示指定鍵名對應的全部鍵值。若是有多個同名的鍵值對,數組會包含全部的鍵值。

案例以下:

var formData = new FormData();
// 設置某個控件的值
formData.set('username', '張三');
formData.get('username') // "張三"
formData.set('username', '張三');
formData.append('username', '李四');
formData.get('username') // "張三"
formData.getAll('username') // ["張三", "李四"]

formData.append('userpic[]', myFileInput.files[0], 'user1.jpg');
formData.append('userpic[]', myFileInput.files[1], 'user2.jpg');
複製代碼

2 enctype 屬性是什麼,有哪些值?(詳細資料

表單可以用四種編碼,向服務器發送數據。編碼格式由表單的enctype屬性決定。

(1)GET 方法

若是表單使用GET方法發送數據,enctype屬性無效。

<form
  action="register.php"
  method="get"
  onsubmit="AJAXSubmit(this); return false;"
>
</form>
複製代碼

數據將以 URL 的查詢字符串發出。

?foo=bar&baz=The%20first%20line.%0AThe%20second%20line.
複製代碼

(2)application/x-www-form-urlencoded

若是表單用POST方法發送數據,並省略enctype屬性,那麼數據以application/x-www-form-urlencoded格式發送(由於這是默認值)。

<form
  action="register.php"
  method="post"
  onsubmit="AJAXSubmit(this); return false;"
>
</form>
複製代碼

發送的 HTTP 請求以下。

Content-Type: application/x-www-form-urlencoded

foo=bar&baz=The+first+line.%0D%0AThe+second+line.%0D%0A
複製代碼

上面代碼中,數據體裏面的%0D%0A表明換行符(\r\n)。

(3)text/plain

若是表單使用POST方法發送數據,enctype屬性爲text/plain,那麼數據將以純文本格式發送。

<form
  action="register.php"
  method="post"
  enctype="text/plain"
  onsubmit="AJAXSubmit(this); return false;"
>
</form>
複製代碼

發送的 HTTP 請求以下。

Content-Type: text/plain

foo=bar
baz=The first line.
The second line.
複製代碼

(4)multipart/form-data

若是表單使用POST方法,enctype屬性爲multipart/form-data,那麼數據將以混合的格式發送。

<form
  action="register.php"
  method="post"
  enctype="multipart/form-data"
  onsubmit="AJAXSubmit(this); return false;"
>
</form>
複製代碼

發送的 HTTP 請求以下。

Content-Type: multipart/form-data; boundary=---------------------------314911788813839

-----------------------------314911788813839
Content-Disposition: form-data; name="foo"

bar
-----------------------------314911788813839
Content-Disposition: form-data; name="baz"

The first line.
The second line.

-----------------------------314911788813839--
複製代碼

這種格式也是文件上傳的格式。

相關文章
相關標籤/搜索