value)訪問。php
// 包裝類
let name = "Nicholas";
name.age = 27;
console.log(name.age); // undefined
複製代碼
原始值賦值到另外一個變量時,原始值會被複制到新變量的位置。引用值賦值到另外一個變量時,複製的值其實是一個指針,它指向存儲在堆內存中的對象。前端
函數的參數都是按值傳遞的,至關於複製算法
// 原始值
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);
複製代碼
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"
複製代碼
console.log(screen.colorDepth); // 24
console.log(screen.pixelDepth); // 24
複製代碼
navigator.geolocation
// Geolocation {}
複製代碼
navigator.connection
複製代碼
有四個監聽電池信息變化的事件
navigator.getBattery().then((b) => console.log(b));
複製代碼
navigator.hardwareConcurrency
// 8
複製代碼
navigator.deviceMemory
// 8
複製代碼
電腦沒有觸屏爲 0
navigator.maxTouchPoints
// 0
複製代碼
事件流描述了頁面接收事件的順序。
事件冒泡:從最具體的元素(文檔樹中最深的節點)開始觸發,而後向上傳播至沒有那麼具體的元素(文檔)
事件捕獲、到達目標和事件冒泡。
<input type="button" value="Click Me" onclick="console.log('Clicked')"/>
複製代碼
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log("Clicked");
};
複製代碼
let btn = document.getElementById("myBtn");
btn.addEventListener("click", () => {
console.log(this.id);
}, false);
複製代碼
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 結構中傳播,取消後續的事件捕獲或冒泡。
window.addEventListener("load", (event) => {
console.log("Loaded!");
});
複製代碼
window.addEventListener("scroll", (event) => {
if (document.compatMode == "CSS1Compat") {
console.log(document.documentElement.scrollTop);
} else {
console.log(document.body.scrollTop);
}
});
複製代碼
。。。 。。。 。。。 下次再寫,太多了
自帶的屬性方法
提交表單 && 重置表單
let form = document.getElementById("myForm");
// 提交表單
form.submit();
// 重置表單
form.reset();
複製代碼
方法
// 失焦
document.forms[0].elements[0].blur();
複製代碼
事件
textbox.addEventListener("change", (event) => {
let target = event.target;
});
複製代碼
// size 寬度
<input type="text" size="25" maxlength="50" value="initial value">
複製代碼
// 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 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;
複製代碼
// 能夠被編輯
<div contenteditable></div>
複製代碼
// 建立
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);
複製代碼
xhr.setRequestHeader("MyHeader", "MyValue");
複製代碼
let data = new FormData();
data.append("name", "Nicholas");
複製代碼
xhr.timeout = 1000; // 設置 1 秒超時
xhr.ontimeout = function() {
alert("Request did not return in a second.");
};
複製代碼
跨源資源共享 CORS
預檢請求
JSONP
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);
複製代碼
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);
// 已經中斷
複製代碼
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;
// 對數據執行某些操做
};
複製代碼