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;
// 对数据执行某些操做
};
复制代码