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 验证(一样很容易伪造)。
相关文章
相关标签/搜索