《JavaScript高级程序设计》
  # # 《JavaScript高级程序设计》
javascript书籍中的经典,里面非常多细节解释的十分详细,而且有些晦涩难懂的概念,比如js面向对象、原型链、继承等,也能层层递进,深入浅出。忍不住赞叹:写的太棒了!
# # JavaScript语言
浏览器宿主中的JavaScript = ECMAScript + DOM + BOM。
Web浏览器只是ECMAScript实现的宿主环境之一。宿主环境不仅提供基本的ECMAScript实现,也会提供该语言的扩展(比如DOM/BOM),以便语言与环境之间对接交互。
DOM(文档对象模型)是针对XML但经过扩展用于HTML的应用程序编程接口。DOM把整个页面映射为一个多层节点结构。HTML的每个组成部分都是某种类型的节点,这些节点又包含着不同类型的数据。
- ECMAScript 核心语言功能
- 语法
 - 类型
 - 语句
 - 关键字
 - 保留字
 - 操作符
 - 对象
 
 - DOM(文档对象模型) 
提供访问和操作网页内容的方法与接口- DOM视图 DOM节点(Node类型)
- DOM查找
 - DOM操作
 
 - DOM事件
- 事件捕获 document -> div
 - 事件冒泡 div -> document
 
 - DOM样式 CSS
 
 - DOM视图 DOM节点(Node类型)
 - BOM(浏览器对象模型) 与浏览器交互的方法与接口
- window
- history
 - document 唯一一个既属于BOM又属于DOM的对象
 - navigator
 - screen
 - location
 
 - cookie
 - XMLHttpRequest
 
 - window
 
js 是ECMAScript的具体实现。其定义了包含语法、关键字等,但不包括与浏览器相关的API。 js引擎不是独立运行的,它运行在宿主环境中。web宿主环境就是浏览器。
# # 标签的位置
- 遇到
<script>会暂停解析html + 浏览器遇到<body>标签才开始呈现内容,所以script应该放在body的最后 
# # JavaScript数据类型
从属于ECMAScript规范定义。从技术角度讲,函数在ECMAScript中是对象,不是一种数据结构。(笔者注:所以js语言可以很好的实践函数式编程思想。关于函数式编程思想可以看笔者另外一篇笔记:函数式编程)
- undefined
 - null
 - string
 - number
 - boolean
 - object
 
# # 基本类型/引用类型
JS变量松散,只是在特定时间用于保存特定值的一个名字。即不存在定义某个变量时必须保存何种数据类型
- 基本类型
- 复制直接拷贝副本
 
 - 引用类型
复制的是指针,指针指向真实的内存(js是无法获取以及操作内存,只能通过指针代理)- 当覆盖新的值时,指针指向新对象
 
 
    // 以上解释了这个赋值问题
    var a = { name: 1 }
    var b = a // b和a指向同一个内存地址
    b = { aget: 1 } // b被指向新的内存地址,断开了与a的联系
    
 2
3
4
5
# # 函数
函数是对象,函数名是指针(函数名代理着内存)
    // 以下都是等价的
    function add(a, b) {
        return a + b
    }
    
    var add = function(a, b) {
        return a + b
    }
    
    // 这种方式较为明显的诠释了实质:函数是对象,函数名是指针
    var add = new Function('a', 'b', 'a + b')
    
 2
3
4
5
6
7
8
9
10
11
12
# # 闭包
指有权访问另一个函数作用域中的变量的函数。原理:
- 后台执行环境中,闭包的作用域链包含自己的作用域、包含函数的作用域和全局作用域。
 - 通常函数的作用域及其所有变量都会在函数执行结束后被销毁。
 - 但是,当函数返回一个闭包时,这个函数的作用域将会一直在内存中保存,直到闭包不存在为止。
 
    function addThird(c) {
        var d = 10
        return function (a, b) {
            return a + b + c + d // 该函数能访问另外一个函数作用域的变量:c、d
        }
    }
    
    addThird(3)(1, 2) // 16
    
 2
3
4
5
6
7
8
9
最典型需要闭包案例:
    // 连续打印5,而不是从1~4
    for (var i = 1; i < 5; i++) {
        setTimeout(function() { console.log(i) }, i * 1000)
    }
    
 2
3
4
5
以上代码我们试图假设循环中的每个迭代在运行时都会给自己“捕获”一个i副本,但根据作用域的工作原理,实际情况是尽管循环中的五个函数是在各个迭代中分布定义的,但是这些函数都是被封闭在一个共享的全局作用域中,因此实际上只有一个i。
所以所有函数共享一个i的引用。
# # 解决方案
- 每次迭代都要一个闭包作用域
 
    for (var i = 1; i < 5; i++) {
        (function() {
            var j = i // 存储i副本,使得settimeout函数可以访问到外部作用域
            setTimeout(function() { console.log(j) }, j * 1000)
        })()
    }
    
    // 一般编码更常用这种方式
    for (var i = 1; i < 5; i++) {
        (function(j) {
            setTimeout(function() { console.log(j) }, j * 1000)
        })(i)
    }
    
 2
3
4
5
6
7
8
9
10
11
12
13
14
- 块作用域
 
块作用域本质上是将块变成一个可以被关闭的作用域。
    for (var i = 1; i < 5; i++) {
        let j = i // 块作用域
        setTimeout(function() { console.log(j) }, j * 1000)
    }
    
 2
3
4
5
for循环头部的let声明还有一个特殊行为。这个行为指出变量在循环过程中不止被声明一次,每次迭代都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。
    for (let i = 1; i < 5; i++) {
        setTimeout(function() { console.log(i) }, i * 1000)
    }
    
 2
3
4
# # DOM
DOM(文档对象模型),提供访问和操作网页内容的方法和接口,是针对HTML和XML文档的一个API(扩展XML)。DOM描绘了一个层次化的节点树。
借助DOM提供的API,开发人员可轻松自如的增删改查任何节点,即获得控制页面内容和结构的主动权。
# # DOM级别
# # DOM1级
1998年成为W3C标准,由两个模块组成:DOM Core 和DOM HTML。DOM Core规定如何映射基于XML的文档结构;DOM HTML模块则在DOM Core的基础上扩展,添加了对HTML的对象和方法(比如在对象上直接绑定事件el.onclick=function)。
# # DOM2级
DOM2目标宽泛了很多。主要有DOM2使得DOM1的DOM Core模块经过扩展支持XML命名空间。 同时引入了新的模块:
- DOM 视图
 - DOM 事件(比如DOM2开始支持el.addEventListen('click', funcion)事件监听方式)
 - DOM 样式
 - DOM 遍历
 
# # DOM3级
目的同样是扩展DOM API,以满足操作XML的所有需求。
# # 其他DOM标准
除了DOM Core和DOM HTML接口之外,SVG语言(也是基于XML的)也发布了针对自己的DOM标准,使得SVG对象上可操作相对应的新的API。其他语言还包括MathML、SMIL
# # XHTML命名空间支持
HTML不支持XML命名空间,但XHTML支持XML命名空间。命名空间使用xmlns特性来指定。在混合使用两种语言的情况下,命名空间用处非常大。比如混合了XHTML和SVG语言的文档:
    <html xmlns="http://www.w3.org/1999/xhtml">
        <body>
            <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
                <rect x="0" y="0" widht="100" height="100"></rect>
            </svg>
        </body>
    </html>
    
 2
3
4
5
6
7
8
通过设置命名空间,svg元素的所有子元素,以及这些元素的所有特性,都被认为属于http://www.w3.org/2000/svg命名空间。
由于引入了命名空间,所以DOM2级的Document类型新增了关于命名空间的方法。比如document.createElementNS(namespaceURI, tagName)
# # 节点层次
- Node 所有节点都继承自Node类型(DOM1级定义)
- 节点属性:nodeType/nodeName/nodeValue
 - 节点关系:firstChild/lastChild/childNodes/parentNode/nextSibling/previousSibling
 - 节点操作:appendChild()/replaceChild()/removeChild()/insertBefore()
 
 - Document 文档类型(nodeType=9)。表示整个HTML页面
- window.document是其实例
 - document.documentElement指向<html>标签子元素,document.body指向<body>标签子元素。
 - 查找Node
- getElementById()
 - getElementByName()
 - getElementByTagName()
 
 - 创建Node
- createElement()
 - createTextNode()
 
 
 - Element 元素类型(nodeType=1),最常用类型
- id/className
 - 属性操作:getAttribute()/setAttribute()/removeAttribute()
 
 - Text 文本类型
 
# # DOM扩展
- 选择符API 从此不再需要getElementBy...
- querySelector
 - querySelectorAll
 - matchsSelector
 
 - 元素遍历 弥补使用childNodes和firstChild属性时,行为不一致
- childElementCount
 - firstElementChild
 - lastElementChild
 - previousElementSibling
 - nextElementSibling
 
 - HTML5 围绕如何使用新增标记,定义了大量JavaScirpt API
- getElementByClassName
 - classList
- add
 - contains
 - remove
 - toggle
 
 - 自定义数据属性 data-
 - postMessage
 - 拖放
- draggable属性开启
 - dragstart/drag/dragend/dragenter/dragover/dragleave事件
 - dataTransfer对象传递数据
 
 - audio/video
 - hashchange/popstate
 
 - 专有扩展
- children属性。对childNodes进行简化
 - el.contains(el)方法 某个节点是不是另外一个节点的后代
 
 - DOM2/DOM3
- 样式
- style属性 el.style.width
 
 - 范围(DOM2)
- document.createRange()
 
 - 手动绑定/解除事件
 
 - 样式
 
    var myDiv = document.getElementByClassName('myDiv')
    myDiv.classList.add('current')
    myDiv.style.width = '100px'
    
 2
3
4
# # 事件
- 事件类型
- UI
- load
 - resize
 - scroll
 
 - 焦点
- blur
 - focus
 
 - 鼠标与滚轮
- click
 - dbclick
 - mousedown
 - mouseenter
 - ...
 
 - 键盘
- keydown
 - keypress
 - keyup
 
 - 复合事件(虚拟键盘用到)
- compositionstart
 - compositionupdate
 - compositionend
 
 - 变动事件
- DOMNodeInserted
 
 - HTML5事件
- hashchange
 - contextmenu
 - DOMContentLoaded(形成dom树之后就会触发)
 - beforeunload
 - readstatechange
 
 - 触摸与手势事件
- 触摸:touchstart/touchmove/touchend/touchcancel
 - 手势:gesturestart/gesturechange/gestureend
 
 
 - UI
 
    // DOM0事件处理
    var btn = document.getElementById('myBtn')
    btn.onclick = function() { ... }
    
 2
3
4
    // DOM2事件处理,好处:可以添加多个事件处理程序
    var btn = document.getElementById('myBtn')
    btn.addEventListener('click', function() { ... }, false) // 最后为false,代表冒泡阶段捕获
    
 2
3
4
# # 元素大小
元素的可见大小由高度、宽度决定,包括所有内边距、滚动条和边框大小(注意,不包括外边距)。
# # 1. 偏移量 offset
元素的偏移量。
注意offsetLef和offsetTop是相对于offsetParent元素。
- offsetHeight
 - offsetWidth
 - offsetLeft
 - offsetTop
 

    // 案例:知道某个el元素在页面上的偏移量
    // 等同于el.getBoundingClientRect().top
    function getElementTop(el) {
        var actualTop = el.offsetTop
        var current = el.offsetParent
    
        while(current) {
            actualTop += current.offsetTop
            current = current.offsetParent
        }
        return actualTop
    }
    
 2
3
4
5
6
7
8
9
10
11
12
13
# # 2. 客户区大小 client
指的是元素内容及内边距所占的空间大小(不包括边框和外边距)。
- clientHeight
 - clientWidth
 

    // 案例:获取视口大小
    function getViewport(el) {
        if (document.compatMode == 'BackCompat') {
            // ie 7 以下版本
            return {
                width: document.body.clientWidth,
                height: document.body.clientHeight
            }
        } else {
            return {
                width: document.documentElement.clientWidth,
                height: document.documentElement.clientHeight
            }
        }
    }
    
 2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# # 3. 滚动大小 scroll
指的是包含滚动内容的的元素大小。
有些元素(如html),即使没有执行任何代码也能自动的添加滚动条,但另外一些元素(如div),则需要通过css的overflow属性设置才能滚动。
scrollHeight/scrollWidth主要用于确定元素内容的实际大小。例如带有垂直滚动条的页面总高度是document.documentElement.scrollHeight
- scrollHeight
 - scrollWidth
 - scrollLeft
 - scrollTop
 

# # 4. 确定元素大小
浏览器为每个元素都提供了getBoundingClientRect()方法(注意该方法的兼容性)。这个方法会返回一个矩形对象,包含4个属性: left、top、bottom、right。
这些属性给出了元素在页面中相对于视口(页面坐标原点)的位置。
# # HTML5 JavaScirpt API
- requestAnimationFrame
 - Page Visible API
- IntersectionObserver
 
 - Geolocation API
 - File API
- e.target.files
- name
 - size
 - type
 - lastModifieDate
 
 - FileReader(可以想象为文件系统的XMLHttpRequest)
 - 对象URL createObjectURL
 - 结合拖放事件 e.dataTransfer.files
 - FormData
 
 - e.target.files
 - Web Worker