# 《JavaScript高级程序设计》笔记 {#《javascript高级程序设计》笔记}
# 第1章 JavaScript简介 {#第1章-javascript简介}
-
JavaScript诞生于1995年
-
一个完整的JavaScript由这三部分组成:
- ECMAScript (核心)
- DOM (文档对象模型)
- BOM (浏览器对象模型)
-
ECMAScript的 宿主环境 包含 :
- 浏览器
- Node
- flash
-
ECMAScript大致规定了下列组成部分:
- 语法
- 类型
- 语句
- 关键字
- 保留字
- 操作符
- 对象
# 第2章 在HTML中使用JavaScript {#第2章-在html中使用javascript}
<script>
标签有下列常见属性:- async 表示立即下载脚本,不妨碍页面的其他操作(异步下载)
- 无法保证每个js的顺序
- 用于互不依赖的js
- 主要目的是不让页面等js
- defer 延迟到文档完全解析和显示之后在执行
- 在
</html>
标签之后执行
- 在
- src 外部文件链接
- type 表示编写代码使用的脚本语言的内容类型
text/javascript
- async 表示立即下载脚本,不妨碍页面的其他操作(异步下载)
# 第3章 基本概念 {#第3章-基本概念}
-
语法,借鉴了C语言
- 区分大小写
- 标识符 ,指的是变量、函数、属性 的名字
- 第一个字符必须是 字母、下划线、或美元符号
- 其他字符可以是字母、下划线、美元符号或数字
-
严格模式
"use strict"
-
数据类型
- 基本数据类型
- Undefined、Null、Boolean、Number、String
typeof
操作符,一般用于基本类型的检测,返回相应类型的字符串- "undefined","boolean","string","number","object","function"
- 复杂数据类型
- Object
- 基本数据类型
-
Null
类型- 表示空对象指针
- 只要意在保存对象的变量还没有真正保证对象,则保存
null
undefined
派生自null
,因此用==
比较返回true
-
浮点数,指的是数值中包含一个小数点,并且小数点后面至少有一位数字
-
NaN
- 任何涉及NaN的操作都返回
NaN
NaN
与任何值都不相等,包括NaN
本身
- 任何涉及NaN的操作都返回
-
数值转换
- 有3个函数可以把非数值转换为数值
- Number() 可以用于任何数据类型
- parseInt() 专门用于字符串转数值,用于解析整数
- parseFloat() 专门用于字符串转数值,用于解析浮点数
- 有3个函数可以把非数值转换为数值
-
字符串
- 数值、布尔值、对象、字符串值本身 都有toString()方法,用于转为字符串
- undefined和null没有toString()方法,但可以使用String()方法
-
Object类型
-
对象其实就是一组数据与功能的集合
-
使用Object()构造函数创建对象
var obj = new Object(); // 同 obj = {}
-
每个对象实例都有下列属性和方法
constructor
指向用于创建当前对象的构造函数 。(对于上面例子而言,就是Object()
)hasOwnProperty(propertyName)
用于检查给定属性是否在当前对象实例中isPrototypeOf(Object)
用于检查传入的对象是否是当前对象的原型propertyIsEnumerable(propertyName)
用于检查给定的属性是否能够使用for-in
来枚举toLocaleString()
返回对象的字符串表示,该字符串与执行环境的地区对应toString()
返回对象的字符串表示valueOf()
返回对象的字符串、数值、布尔值表示。通常与toString()
返回值相同
所有对象都有以上属性和方法
-
-
操作符
- 一元操作符
- ++
- --
- 前置与后置的区别是与其他数运算时,前置会先执行递增(减)再与其他数运算,后置会先与其他数运算再对自身执行递增(减)
- 布尔操作符
- 与 (&&)
- 短路操作,即如果第一个操作数能决定结果,就不会对第二个操作数求值
- 或 (||)
- 短路操作,即如果第一个操作数能决定结果,就不会对第二个操作数求值
- 非 (!)
- 先使用Boolean()转成布尔值再取反
- 与 (&&)
- 一元操作符
-
语句(也称流控制语句)
-
if-else
-
do-while
-
后测试循环语句,在对表达式求值之前,循环体内的代码至少会被执行一次
var i = 0 do { i += 2 } while (i < 10) // 只要i小于10就会一直循环
-
-
while
-
前测试语句
var i = 0 while (i < 10) { i += 2 } // 只要i小于10就会一直循环
-
-
for
-
使用while循环做不到的,使用for循环同样做不到。就是说,for循环只是把与循环有关的代码集合在一个位置
for(初始化;条件;循环后执行){ // ... }
-
break 立即退出循环
-
continue 退出当前单次循环
-
-
for- in 用来枚举对象的属性
-
-
函数
- 任何函数都可以在任何时候返回任何值
- 未指定返回值的函数会返回一个undefined
- 通过arguments访问参数,它是一个类数组
# 第4章 变量、作用域和内存问题 {#第4章-变量、作用域和内存问题}
-
变量包含两种类型的值:
- 基本类型值,指的是简单的数据段
- 引用类型值,指的是那些可能由多个值构成的对象
-
复制变量值
- 复制基本类型的变量值只是复制了该值的副本
- 复制引用类型的变量值时,同样也会将存储在变量对象的值复制一份放到新变量的空间中,不同的是,这个值的副本实际上是一个指针,而这个指针指向存储在堆中的一个对象。两个变量指向同一个对象。
-
传递参数
- 所有函数的参数都是按值传递的
-
检测类型
typeof
检测基础类型instanceof
检测引用类型- 变量 instanceof 构造函数(例:obj instanceof Object)
- 所有引用类型的值都是Object的实例
-
执行环境
- 在浏览器中,全局执行环境是
window
对象 - 每个函数都有自己的执行环境
- 在浏览器中,全局执行环境是
-
作用域链
- 当代码在一个环境中执行时,会创建变量对象的一个作用域链
- 作用域链的前端,始终是当前执行的代码所在环境的变量对象。
- 作用域链中的下一个变量对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含对象。这样一直延续到全局执行环境。
- 全局执行环境的变量对象始终都是作用域链中的最后一个对象。
-
垃圾收集
- JavaScript具有自动垃圾收集机制
- 对于不再使用的变量打上标记,被打上标记的变量将在执行回收时被清除,释放内存空间。
- JavaScript具有自动垃圾收集机制
# 第5章 引用类型 {#第5章-引用类型}
-
引用类型的值是引用类型的一个实例
-
引用类型就是一种数据结构,描述了一类对象所具有的属性和方法
-
创建Object实例的方式有两种:
-
var obj = new Object()
-
var obj = {} // 与 new Object() 相同,但实际不会调用Object构造函数
-
-
访问对象的属性有两种:
- 点表示法 和 方括号表示法
# Array类型 {#array类型}
-
length属性不是只读的
-
检测数组
-
value instanceof Array
-
Array.isArray(value)
-
-
转换方法
- toLocaleString() 与toString()相同
- toString() 返回数组中每个值的字符串形式用逗号分隔拼接而成的字符串
- valueOf() 返回数组本身
# join() 转换方法 (不改原数组) {#join-转换方法-不改原数组}
接收一个参数,用作分隔符的字符串,然后返回包含所有数组项的字符串。
var arr = ['red','blue','green']
var arrStr = arr.join('|') // "red|blue|green"
arr.join() // "red,blue,green"
arr.join('') // "redbluegreen"
# 栈方法,后进先出 push() 、pop() (改变原数组) {#栈方法-后进先出-push-、pop-改变原数组}
- push() 向数组末尾添加成员,返回总长
- pop() 移除数组末尾一个成员,返回该成员
# 队列方法,先进先出 push()、shift() 、unshift() (改变原数组) {#队列方法-先进先出-push-、shift-、unshift-改变原数组}
-
shift() 移除数组首个成员,返回该成员
-
unshift() 在数组前面添加成员,返回总长
push()和shift() 形成队列方法
unshift和pop() 形成反方向队列方法
# 重排序方法 reverse() 反转 sort() 排序 (改变原数组) {#重排序方法-reverse-反转-sort-排序-改变原数组}
- reverse() 反转数组项的顺序
- sort() 接收一个函数作为参数,函数接收两个参数。
-
自定义排序:函数内,如果第一个参数应该位于第二个之前,则手动返回一个负数,如果两个参数相等,手动返回0,如果第一个参数应该位于第二个参数之后,则手动返回一个正数。
// 升序 arr.sort(function(a,b){ if(a < b) { return -1 } else if (a > b) { return 1 } else { retunr 0 } })
-
简写:
arr.sort((a,b) => {
return a-b // 升序, b-a 降序
})
# 操作方法 concat() 拼接,slice() 切片,splice() 移接 {#操作方法-concat-拼接-slice-切片-splice-移接}
-
concat() 拼接数组 (不改原数组)
var arr1 = ['a','b'] var arr2 = arr1.concat('c','d') // ['a','b','c','d']
-
slice() 切片(不改原数组)
-
slice(起始位置 [, 结束位置]) 返回起始位置到结束位置的成员,不包含结束位置。
var arr1 = [1,2,3,4,5] var arr2 = arr1.slice(1,3) // [2,3] var arr3 = arr1.slice(2) // [3,4,5]
-
-
splice() 移接 (改变原数组)
-
splice(起始位置, 要删除的个数,要插入的项)
- 要插入的项 可以有0个或多个
-
splice() 始终返回一个数组,该数组成员中包含原始数组中被删除的项,如果没有则返回空数组。
-
数组最强大的方法,可用于删除、插入、替换操作
arr = [1,2,3,4] arr.splice(1,1) // [2] arr // [1,3,4]
arr = [1,2,3,4] arr.splice(2,0,'a') // [] arr // [1,2,'a',3,4]
arr = [1,2,3,4] arr.splice(3,1,'a') // [4] arr // [1,2,3,'a']
-
# 位置方法 indexOf()、lastIndexOf() {#位置方法-indexof-、lastindexof}
- 查找项的位置,没有则返回-1
- indexOf() 从前面开始找,lastIndexOf() 从后面开始找
# 迭代方法 every()、some() 、filter()、map() 、forEach() (都不会改变原数组) {#迭代方法-every-、some-、filter-、map-、foreach-都不会改变原数组}
-
5个迭代方法,每个方法都接收两个参数:
- 在每项上运行的函数
- 运行函数的作用域对象
-
函数接收三个参数:
- 数组项的值
- 该项的索引
- 数组本身
-
every() 如果函数对每项都返回true,则返回true
-
例:判断数组每一项是否都大于2
var numbers = [1,2,3,2,1] var result = numbers.every((item,index,array) => { return item > 2 }) result // false
-
-
some() 如果函数对任一项返回true,则返回true
-
例:判断数组是否包含大于2的值
var numbers = [1,2,3,2,1] var result = numbers.some((item,index,array) => { return item > 2 }) result // true
-
-
filter() 返回函数会返回true的项组成的数组
-
例:过滤掉数组中小于等于2的数
var numbers = [1,2,3,4,5] var result = numbers.filter((item,index,array) => { return item >2 }) result // [3,4,5]
-
-
map() 返回每次函数调用的结果组成的数组
-
例:给数组每一项乘以2
var numbers = [1,2,3,4,5] var result = numbers.map((item,index,array) => { return item * 2 }) result // [2,4,6,8,10]
-
-
forEach() 循环数组每一项,没有返回值
-
例:循环每一项
var numbers = [1,2,3,4,5] numbers.forEach((item,index,array) => { // 做一些操作 })
-
# 归并方法 reduce() reduceRight() {#归并方法-reduce-reduceright}
-
reduce() 归并为
-
reduceRight() 从右边归并
-
这两个方法都会迭代数组所有项,然后构建一个最终结果并返回
-
方法接收两个参数: 每一项上调用的函数,归并基础的初始值
-
函数接收4个参数:前一个的值、当前值、当前值的索引、数组对象
-
例:求数组每一项之和
var numbers = [1,2,3,4,5] var result = number.reduce((prev,cur,index,arr) => { return prev + cur }) result // 15
-
reduce()方法,第一次执行函数时,prev是数组的第一项,cur是数组的第二项
# 第6章 面向对象的程序设计 {#第6章-面向对象的程序设计}
# 6.1 理解对象 {#_6-1-理解对象}
- 对象的定义:无序属性的集合,其属性可以包含基本值、对象或者函数。
- 一组键值对,其中值可以是数据或函数
# 6.1.1 对象的属性 {#_6-1-1-对象的属性}
包含两种:数据属性 和 访问器属性
# 1.数据属性 {#_1-数据属性}
- configurable 可配置性(限制 delete删除属性和
Object.defineProperty()
方法是否起效。),默认true - enumerable 可列举性,默认true
- writable 可写性,默认true
- value 值,默认undefined
使用Object.defineProperty()
方法修改这些默认属性。接收三个值:属性所在的对象、属性名、描述符对象。
var person = {}
Object.defineProperty(person,'name',{
writable: false,
value: 'xu'
})
console.log(person.name) // xu
person.name = 'gao' // 修改无效
console.log(person.name) // xu
使用此方法定义属性如未指定configurable
、enumerable
、writable
将默认false
。
# 2.访问器属性 {#_2-访问器属性}
包含两个函数:getter函数和setter函数(这两个函数都是非必需)。读取时调用getter,访问时调用setter。
使用Object.defineProperty()
方法定义访问器属性。
var book = {
_year: 2020,
edition: 1
};
Object.defineProperty(book, 'year', {
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2020) {
this._year = newValue
this.edition += newValue - 2020
}
}
})
book.year = 2021
console.log(book.edition) // 2
当getter函数和setter函数只指定其中一个时,另外一个将不能用。
# 6.1.2 定义多个属性 {#_6-1-2-定义多个属性}
Object.defineProperties()
方法定义多个属性。接收两个参数: 要添加或修改属性的对象 、第二个参数是一个对象,其属性与第一个参数中的属性一一对应。
var book = {}
Object.defineProperties(book, {
_year: { // 数据属性
writable: true,
value: 2004
},
edition: { // 数据属性
writable: true,
value: 1
},
year: { // 访问器属性
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
}
})
// 定义了三个属性,每个属性有不同的描述符
# 6.1.3 读取属性的特性(描述符对象) {#_6-1-3-读取属性的特性-描述符对象}
Object.getOwnPropertyDescriptor()
方法获取描述符,接收两个参数: 属性所在的对象、属性名
var book = {}
Object.defineProperties(book, {
_year: { // 数据属性
writable: true,
value: 2004
},
edition: { // 数据属性
writable: true,
value: 1
},
year: { // 访问器属性
get: function() {
return this._year
},
set: function(newValue){
if(newValue > 2004){
this._year = newValue
this.edition += newValue - 2004
}
}
}
})
var descriptor = Object.getOwnPropertyDescriptor(book, "_year")
console.log(descriptor) // {value: 2020, writable: true, enumerable: false, configurable: false}
var descriptor = Object.getOwnPropertyDescriptor(book, "year")
console.log(descriptor) // {enumerable: false, configurable: false, get: ƒ, set: ƒ}
# 6.2 创建对象 {#_6-2-创建对象}
使用Object构造函数或对象字面量方式创建对象。缺点:使用同一个接口创建很多对象时,会产生大量重复代码。解决方案:使用工厂模式的一种变体。