JavaScript高級程序設計筆記

(持續更新中。。。)

第四章 - 變量、做用域與內存

目標

  • 經過變量使用原始值與引用值
  • 理解執行上下文
  • 理解垃圾回收

原始值與引用值

  • 原始值: Undefined、Null、Boolean、Number、String 和 Symbol。按值(by

value)訪問。php

// 包裝類
let name = "Nicholas";
name.age = 27;
console.log(name.age); // undefined 

複製代碼

  • 引用值: 按引用(reference)訪問,引用值能夠隨時添加、修改和刪除其屬性和方法。

  • 複製值

原始值賦值到另外一個變量時,原始值會被複制到新變量的位置。引用值賦值到另外一個變量時,複製的值其實是一個指針,它指向存儲在堆內存中的對象。前端

  • 傳遞參數

函數的參數都是按值傳遞的,至關於複製算法

// 原始值
function addTen(num) {
 num += 10;
 return num;
}
let count = 20; 
86 第 4 章 變量、做用域與內存
let result = addTen(count);
console.log(count); // 20,沒有變化
console.log(result); // 30 
複製代碼
// 引用值
function setName(obj) {
 obj.name = "Nicholas";
}
let person = new Object();
setName(person);
console.log(person.name); // "Nicholas"

複製代碼

執行上下文與做用域

每一個上下文都有一個關聯的變量對象(variable object),而這個上下文中定義的全部變量和函數都存在於這個對象上。雖然沒法經過代碼訪問變量對象,但後臺處理數據會用到它。上下文在其全部代碼都執行完畢後會被銷燬,包括定義在它上面的全部變量和函數。每一個函數調用都有本身的上下文。當代碼執行流進入函數時,函數的上下文被推到一個上下文棧上。在函數執行完以後,上下文棧會彈出該函數上下文,將控制權返還給以前的執行上下文。上下文中的代碼在執行的時候,會建立變量對象的一個做用域鏈(scope chain)。這個做用域鏈決定了各級上下文中的代碼在訪問變量和函數時的順序。代碼正在執行的上下文的變量對象始終位於做用域鏈的最前端。若是上下文是函數,則其活動對象(activation object)用做變量對象。活動對象最初只有一個定義變量:arguments。(全局上下文中沒有這個變量。)做用域鏈中的下一個變量對象來自包含上下文,再下一個對象來自再下一個包含上下文。以此類推直至全局上下文;全局上下文的變量對象始終是做用域鏈的最後一個變量對象。json

  • 全局上下文瀏覽器

  • 在瀏覽器中,全局上下文就是咱們常說的 window 對象安全

垃圾回收

  • 基本思路:肯定哪一個變量不會再使用,而後釋放它佔用的內存。服務器

  • 標記策略:標記清理和引用計數。markdown

  • 標記清理(經常使用):當變量進入上下文,好比在函數內部聲明一個變量時,這個變量會被加上存在於上下文中的標記。當變量離開上下文時,也會被加上離開上下文的標記。cookie

  • 引用計數: 是對每一個值都記錄它被引用的次數。聲明變量並給它賦一個引用值時,這個值的引用數爲 1。若是同一個值又被賦給另外一個變量,那麼引用數加 1。相似地,若是保存對該值引用的變量被其餘值給覆蓋了,那麼引用數減 1。當一個值的引用數爲 0 時,垃圾回收程序下次運行的時候就會釋放引用數爲 0 的值的內存。網絡

  • 性能 垃圾回收程序會週期性運行,若是內存中分配了不少變量,則可能形成性能損失,所以垃圾回收的 時間調度很重要。

  • 隱藏類和刪除操做

    運行期間,V8 會將建立的對象與隱藏類關聯起來,以跟蹤它們的屬性特徵。可以共享相同隱藏類 的對象性能會更好

    // low 不一樣隱藏類
    function Article() {
     this.title = 'Inauguration Ceremony Features Kazoo Band';
    }
    let a1 = new Article();
    let a2 = new Article(); 
    a2.author = 'Jake'; 
    
    複製代碼
    // good 相同隱藏類
    function Article(opt_author) {
     this.title = 'Inauguration Ceremony Features Kazoo Band';
     this.author = opt_author;
    }
    let a1 = new Article();
    let a2 = new Article('Jake'); 
    
    複製代碼

    動態刪除屬性與動態添加屬性致使的後果同樣。

    // low
    function Article() {
     this.title = 'Inauguration Ceremony Features Kazoo Band';
     this.author = 'Jake';
    }
    let a1 = new Article();
    let a2 = new Article();
    delete a1.author; 
    
    複製代碼
    function Article() {
     this.title = 'Inauguration Ceremony Features Kazoo Band';
     this.author = 'Jake';
    }
    let a1 = new Article();
    let a2 = new Article();
    a1.author = null; 
    
    複製代碼
  • 內存泄漏

    • 意外聲明全局變量
    function setName() {
      name = 'Jake';
    } 
    
    複製代碼
    • 定時器
    let name = 'Jake';
    setInterval(() => {
     console.log(name);
    }, 100); 
    
    複製代碼
    • 使用 JavaScript 閉包
    let outer = function() {
     let name = 'Jake';
     return function() {
     return name;
     };
    };
    
    複製代碼
  • 靜態分配與對象池

第十三章 - 客戶端檢測

目標

  • 使用能力檢測
  • 用戶代理檢測的歷史
  • 軟件與硬件檢測
  • 檢測策略

能力檢測

能力檢測(又稱特性檢測)即在 JavaScript 運行時中使用一套簡單的檢測邏輯,測試瀏覽器是 否支持某種特性。

// 例
if (object.propertyInQuestion) {
 // 使用 object.propertyInQuestion
} 

複製代碼

安全能力檢測

// 例
// 好一些,檢測 sort 是否是函數
function isSortable(object) {
 return typeof object.sort == "function";
} 

複製代碼

基於能力檢測進行瀏覽器分析

// 檢測瀏覽器是否支持 Netscape 式的插件
let hasNSPlugins = !!(navigator.plugins && navigator.plugins.length);
// 檢測瀏覽器是否具備 DOM Level 1 能力
let hasDOM1 = !!(document.getElementById && document.createElement &&
 document.getElementsByTagName); 

複製代碼

經過檢測一種或一組能力,並不總能肯定使用的是哪一種瀏覽器。 能力檢測最適合用於決定下一步該怎麼作,而不必定可以做爲辨識瀏覽器的標誌。

用戶代理檢測

用戶代理檢測經過瀏覽器的用戶代理字符串肯定使用的是什麼瀏覽器。用戶代理字符串包含在每一個HTTP 請求的頭部,在 JavaScript 中能夠經過 navigator.userAgent 訪問。

navigator.userAgent

複製代碼

識別瀏覽器與操做系統

  • 識別瀏覽器開發商信息
navigator.vendor
// "Google Inc."

複製代碼
  • 識別瀏覽器所在的操做系統
navigator.platform
// "MacIntel"

複製代碼
  • screen.colorDepth 和 screen.pixelDepth 返回顯示器每像素顏色的位深
console.log(screen.colorDepth); // 24
console.log(screen.pixelDepth); // 24 

複製代碼
  • Geolocation API 暴露當前設備的地理位置。
navigator.geolocation
// Geolocation {}

複製代碼
  • 鏈接屬性
navigator.connection

複製代碼

  • 獲取電池信息

有四個監聽電池信息變化的事件

  • onchargingchange // 加充電狀態變化時
  • onchargingtimechange // 加充電時間變化時
  • ondischargingtimechange // 加放電時間變化時
  • onlevelchange // 加電量百分比變化時
navigator.getBattery().then((b) => console.log(b)); 

複製代碼

  • 處理器核心數
navigator.hardwareConcurrency
// 8

複製代碼
  • 設備內存大小(512MB 返回 0.5,4GB 返回 4)
navigator.deviceMemory
// 8

複製代碼
  • 最大觸點數

電腦沒有觸屏爲 0

navigator.maxTouchPoints
// 0

複製代碼

第十七章 - 事件

目標

  • 理解事件流
  • 使用事件處理程序
  • 瞭解不一樣類型的事件

事件流

  • 事件流描述了頁面接收事件的順序。

  • 事件冒泡:從最具體的元素(文檔樹中最深的節點)開始觸發,而後向上傳播至沒有那麼具體的元素(文檔)

  • 事件捕獲: 事件捕獲的意思是最不具體的節點應該最早收到事件,而最具體的節點應該最後收到事件。

  • 一般建議使用事件冒泡,特殊狀況下可使用事件捕獲。

DOM 事件流

事件捕獲、到達目標和事件冒泡。

事件處理程序

  • 以"on"開頭: onclick
  • HTML中
<input type="button" value="Click Me" onclick="console.log('Clicked')"/> 

複製代碼
  • DOM0 中
let btn = document.getElementById("myBtn");
btn.onclick = function() {
 console.log("Clicked");
}; 

複製代碼
  • DOM2 中
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
 console.log(this.id);
}, false); 

複製代碼
  • IE 中
var btn = document.getElementById("myBtn");
btn.attachEvent("onclick", function() {
 console.log("Clicked");
});

複製代碼
  • 跨瀏覽器事件處理程序
// 新建 EventUtil

var EventUtil = {
 addHandler: function(element, type, handler) {
 if (element.addEventListener) {
 element.addEventListener(type, handler, false);
 } else if (element.attachEvent) {
 element.attachEvent("on" + type, handler);
 } else {
 element["on" + type] = handler;
 }
 },
 removeHandler: function(element, type, handler) {
 if (element.removeEventListener) {
 element.removeEventListener(type, handler, false);
 } else if (element.detachEvent) {
 element.detachEvent("on" + type, handler);
 } else {
 element["on" + type] = null;
 }
 }
}; 

複製代碼
// 使用 EventUtil

let btn = document.getElementById("myBtn")
let handler = function() {
 console.log("Clicked");
};
EventUtil.addHandler(btn, "click", handler);
// 其餘代碼
EventUtil.removeHandler(btn, "click", handler);

複製代碼

事件對象

屬性/方法 類 型 讀/寫 說 明
bubbles 布爾值 只讀 表示事件是否冒泡
cancelable 布爾值 只讀 表示是否能夠取消事件的默認行爲
currentTarget 元素 只讀 當前事件處理程序所在的元素
defaultPrevented 布爾值 只讀 true 表示已經調用 preventDefault()方法(DOM3Events 中新增)
detail 整數 只讀 事件相關的其餘信息
eventPhase 整數 只讀 表示調用事件處理程序的階段:1 表明捕獲階段,2 表明到達目標,3 表明冒泡階段
preventDefault() 函數 只讀 用於取消事件的默認行爲。只有 cancelable 爲 true 才能夠調用這個方法
stopImmediatePropagation() 函數 只讀 用於取消全部後續事件捕獲或事件冒泡,並阻止調用任何後續事件處理程序(DOM3 Events 中新增)
stopPropagation() 函數 只讀 用於取消全部後續事件捕獲或事件冒泡。只有 bubbles爲 true 才能夠調用這個方法
target 元素 只讀 事件目標
trusted 布爾值 只讀 true 表示事件是由瀏覽器生成的。false 表示事件是開發者經過 JavaScript 建立的(DOM3 Events 中新增)
type 字符串 只讀 被觸發的事件類型
View AbstractView 只讀 與事件相關的抽象視圖。等於事件所發生的 window 對象

在事件處理程序內部,this 對象始終等於 currentTarget 的值,而 target 只包含事件的實際 目標。

// 例
// 在 body 添加點擊事件,做用域btn
document.body.onclick = function(event) {
 console.log(event.currentTarget === document.body); // true
 console.log(this === document.body); // true
 console.log(event.target === document.getElementById("myBtn")); // true
};

複製代碼
  • preventDefault()方法用於阻止特定事件的默認動做。(需 cancelable 爲 true)

  • stopPropagation()方法用於當即阻止事件流在 DOM 結構中傳播,取消後續的事件捕獲或冒泡。

用戶界面事件

  • load:在 window 上當頁面加載完成後觸發
window.addEventListener("load", (event) => {
 console.log("Loaded!");
}); 
複製代碼
  • error:在 window 上當 JavaScript 報錯時觸發,在<img>元素上當沒法加載指定圖片時觸發
  • select:在文本框(<input>或 textarea)上當用戶選擇了一個或多個字符時觸發。
  • resize:在 window 或窗格上當窗口或窗格被縮放時觸發。
  • scroll:當用戶滾動包含滾動條的元素時在元素上觸發。<body>元素包含已加載頁面的滾動條。大多數 HTML 事件與 window 對象和表單控件有關。
window.addEventListener("scroll", (event) => {
 if (document.compatMode == "CSS1Compat") {
 console.log(document.documentElement.scrollTop);
 } else {
 console.log(document.body.scrollTop);
 }
}); 
複製代碼

焦點事件

  • blur:當元素失去焦點時觸發。這個事件不冒泡
  • focus:當元素得到焦點時觸發。這個事件不冒泡

鼠標和滾輪事件

  • click:在用戶單擊鼠標主鍵(一般是左鍵)或按鍵盤迴車鍵時觸發。
  • dblclick:在用戶雙擊鼠標主鍵(一般是左鍵)時觸發。
  • mousedown:在用戶按下任意鼠標鍵時觸發。這個事件不能經過鍵盤觸發。
  • mouseenter:在用戶把鼠標光標從元素外部移到元素內部時觸發。
  • mouseleave:在用戶把鼠標光標從元素內部移到元素外部時觸發。
  • mousemove:在鼠標光標在元素上移動時反覆觸發。
  • mouseout:在用戶把鼠標光標從一個元素移到另外一個元素上時觸發。
  • mouseover:在用戶把鼠標光標從元素外部移到元素內部時觸發。
  • mouseup:在用戶釋放鼠標鍵時觸發。

。。。 。。。 。。。 下次再寫,太多了

第十九章 - 表單腳本

目標

  • 理解表單基礎
  • 文本框驗證與交互
  • 使用其餘表單控件

基礎

  • Web 表單在 HTML 中以<form>元素表示,在 JavaScript 中則以 HTMLFormElement 類型表示。

  • 自帶的屬性方法

    • action:請求的 URL,等價於 HTML 的 action 屬性。
    • enctype:請求的編碼類型,等價於 HTML 的 enctype 屬性。
    • method:HTTP 請求的方法類型,一般是"get"或"post",等價於 HTML 的 method 屬性。
    • reset():把表單字段重置爲各自的默認值。
    • submit():提交表單。
  • 提交表單 && 重置表單

let form = document.getElementById("myForm"); 
// 提交表單
form.submit(); 
// 重置表單
form.reset(); 

複製代碼
  • 方法

    • focus()和 blur(), focus聚焦
    // 失焦
    document.forms[0].elements[0].blur(); 
    複製代碼
  • 事件

    • focus, blur, change
    textbox.addEventListener("change", (event) => {
      let target = event.target;
    }); 
    複製代碼

文本框

  • input
// size 寬度
<input type="text" size="25" maxlength="50" value="initial value">

複製代碼
  • textarea
// rows 高度 , cols 高度
<textarea rows="25" cols="5">initial value</textarea> 
複製代碼
  • 選擇文本
// 1
let textbox = document.forms[0].elements["textbox1"];
textbox.select(); 
// 2
textbox.addEventListener("focus", (event) => {
 event.target.select();
}); 

複製代碼

選擇框

  • select和option
<select name="location" id="selLocation">
 <option value="Sunnyvale, CA">Sunnyvale</option>
 <option value="Los Angeles, CA">Los Angeles</option>
 <option value="Mountain View, CA">Mountain View</option>
 <option value="">China</option>
 <option>Australia</option>
</select> 
複製代碼
  • 選中第一個
selectbox.options[0].selected = true; 
複製代碼
  • 元素 contenteditable
// 能夠被編輯
<div  contenteditable></div>
複製代碼

第二十四章 - 網絡請求與遠程資源

目標

  • 使用 XMLHttpRequest 對象
  • 處理 XMLHttpRequest 事件
  • 源域 Ajax 限制
  • Fetch API
  • Streams API

XMLHttpRequest

// 建立
let xhr = new XMLHttpRequest(); 

// 0: open 以前,1: open 以後 2.send 以後 3.:接收中 4. 完成
xhr.onreadystatechange = function() {
 if (xhr.readyState == 4) {
 if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
 alert(xhr.responseText);
 } else {
 alert("Request was unsuccessful: " + xhr.status);
 }
 }
}; 
// get , post 等
xhr.open("get", "example.php", false); 
// send 請求體,沒有必須穿 null
xhr.send(null); 
複製代碼
  • 請求頭
    • Accept:瀏覽器能夠處理的內容類型。
    • Accept-Charset:瀏覽器能夠顯示的字符集。
    • Accept-Encoding:瀏覽器能夠處理的壓縮編碼類型。
    • Accept-Language:瀏覽器使用的語言。
    • Connection:瀏覽器與服務器的鏈接類型。
    • Cookie:頁面中設置的 Cookie。
    • Host:發送請求的頁面所在的域。
    • User-Agent:瀏覽器的用戶代理字符串。
xhr.setRequestHeader("MyHeader", "MyValue"); 
複製代碼
  • FormData
let data = new FormData();
data.append("name", "Nicholas"); 
複製代碼
  • 超時
xhr.timeout = 1000; // 設置 1 秒超時
xhr.ontimeout = function() {
 alert("Request did not return in a second.");
}; 
複製代碼
  • 跨源資源共享 CORS

  • 預檢請求

    • 求使用 OPTIONS 方法發送
  • JSONP

    • JSONP 是「JSON with padding」的簡寫
function handleResponse(response) {
 console.log(`
 You're at IP address ${response.ip}, which is in
 ${response.city}, ${response.region_name}`);
}
let script = document.createElement("script");
script.src = "http://freegeoip.net/json/?callback=handleResponse";
document.body.insertBefore(script, document.body.firstChild); 
複製代碼

Fetch

let r = fetch('/bar', {
 method: 'POST', // 發送請求體時必須使用一種 HTTP 方法
 body: payload,
 headers: jsonHeaders
});
console.log(r); // Promise <pending>
複製代碼
fetch('bar.txt')
 .then((response) => {
   console.log(response.status); // 200
   console.log(response.statusText); // OK 
   response.text().then((data) => {
   console.log(data);
 });
 }); 
複製代碼
  • 中斷
let abortController = new AbortController();
fetch('wikipedia.zip', { signal: abortController.signal })
 .catch(() => console.log('aborted!');
// 10 毫秒後中斷請求
setTimeout(() => abortController.abort(), 10);
// 已經中斷 
複製代碼

Web Socket

let socket = new WebSocket("ws://www.example.com/server.php"); 

let stringData = "Hello world!";
let arrayBufferData = Uint8Array.from(['f', 'o', 'o']);
let blobData = new Blob(['f', 'o', 'o']);
socket.send(stringData);
socket.send(arrayBufferData.buffer);
socket.send(blobData);
// 接收
socket.onmessage = function(event) {
 let data = event.data;
 // 對數據執行某些操做
}; 

複製代碼
  • 狀態
    • WebSocket.OPENING(0):鏈接正在創建。
    • WebSocket.OPEN(1):鏈接已經創建。
    • WebSocket.CLOSING(2):鏈接正在關閉。
    • WebSocket.CLOSE(3):鏈接已經關閉。
    • 其餘事件
    • open:在鏈接成功創建時觸發。
    • error:在發生錯誤時觸發。鏈接沒法存續。
    • close:在鏈接關閉時觸發。

安全

  • 要求經過 SSL 訪問可以被 Ajax 訪問的資源。
  • 要求每一個請求都發送一個按約定算法計算好的令牌(token)。注意,如下手段對防禦 CSRF 攻擊是無效的。
  • 要求 POST 而非 GET 請求(很容易修改請求方法)。
  • 使用來源 URL 驗證來源(來源 URL 很容易僞造)。
  • 基於 cookie 驗證(一樣很容易僞造)。
相關文章
相關標籤/搜索