文章目录
- 第4章:变量、作用域与内存
- 1. 原始值与引用值
- 2. 执行上下文与作用域
- 3. 垃圾回收
- 第5章:基本引用类型
- 1. Date:参考了Java早期版本中的java.util.Date
- 2. RegExp
- 3. 原始值包装类型
- 第6章:集合引用类型
- 1. Object
- 2. Array:每个槽位可以存储任意类型的数据,数组大小是动态的。
- 3. 定型数组(没看懂 P155 180)
- 4. Map
- 5. WeakMap(弱映射)
- 6. Set
- 7. WeakSet(弱集合)
- 8. 迭代与扩展操作
第4章:变量、作用域与内存
1. 原始值与引用值
- 原始值(primitive value):最简单的数据。保存原始值的变量是按值访问的。
- 引用值(reference value):由多个值构成的对象。保存引用值的对象是按引用访问的。
- 动态属性
- 引用值可以随时添加、修改和删除其属性和方法。
- 原始值不能有属性,尽管尝试给原始值添加属性不会报错。
- 复制值
- 原始值复制的是原来值的副本。
- 引用值复制的值实际上是一个指针,它指向存储在堆内存中的对象。所以操作完成后,两个变量实际上指向同一个对象,一个对象上面的变化会在另一个对象上反映出来。
- 传递参数:ECMAScript中所有函数的参数都是按值传递的。
- 确定类型
- typeof操作符:适合用来判断一个变量是否为原始类型。typeof(variable)
- instanceof操作符:适合用来判断引用类型的变量。result = variable instanceof constructor
2. 执行上下文与作用域
- 每个上下文都有一个关联的变量对象(variable object)。
- 上下文中的代码在执行的时候回创建变量对象的一个作用域链(scope chain)。
- 如果上下文是函数,则其活动对象(activation)用作变量对象。
- 全局上下文的变量对象始终是作用域链的最后一个变量对象。
- 内部上下文可以通过作用域链访问外部上下文中的一切,反之不行。
- 作用域链增强:下面两种情况都会在作用域链前端添加一个变量对象。(不太懂)
- try/catch语句的catch块
- with语句
- 变量声明
- 使用var的函数作用域声明
- var声明变量时,会被自动添加到最接近的上下文。如果未经声明就被初始化,则自动被添加到全局上下文。
- var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前,这个现象叫做“提升”(hoisting)。
- 使用let的块级作用域声明
- let在同一作用域内不能声明两次。会抛出SyntaxError。
- 使用const的常量声明
- 声明的同时必须初始化
- 一经声明,在其生命周期的任何时候都不能再重新赋值。
- const声明只应用到顶级原语或者对象。也就是说,赋值为对象的const变量不能再被重新赋值为其他引用值,但对象的键不受限制。
- 标识符查找
- 使用var的函数作用域声明
3. 垃圾回收
- JavaScript通过自动内存管理实现内存分配和闲置资源回收。
- 标记清理:JavaScript最常用的垃圾回收策略
- 变量进入上下文时,加上存在于上下文的标记;变量离开上下文时,加上离开上下文标记。
- 垃圾回收程序运行的时候,会标记存储中的所有变量。然后,将所有在上下文中的变量,以及在上下文中的变量引用的变量的标记去掉。在此之后,再被加上标记的变量就是待删除的了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。
- 引用计数:一种没那么常用的垃圾回收策略
- 思路是对每个值都记录它被引用的次数。
- 很快就遇到了严重问题:循环引用。
- 性能
- 内存管理
- 优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要,那么把它设置为null,从而释放其引用。这也可以叫做解除引用。
- 通过const和let声明提升性能
- 隐藏类和删除操作(不太懂)
- 内存泄漏
- 意外声明全局变量是最常见但是也最容易修复的内存泄漏问题。
- 定时器也可能会导致内存泄漏。闭包
- 静态分配与对象池
第5章:基本引用类型
引用类型跟类有点像,但不是一个概念。
1. Date:参考了Java早期版本中的java.util.Date
- 创建日期对象:let now = new Date();
- 参数传入表示该日期的毫秒数,不给Date构造函数传参数的话,创建的对象保存当前日期和时间。
- Date.parse():接收一个表示日期的字符串参数,将字符串参数转换为表示该日期的毫秒数。如果字符串参数不表示日期,返回NaN。
- Date.UTC():也返回日期的毫秒数。参数是年、零起点月、日、时、分、秒、毫秒。只有前两个时必需的。
- Date.now():返回方法执行日期和时间的毫秒数。
- toLocaleString():返回与浏览器运行的本地环境一致的日期和时间。
- toString():返回带市区信息的日期和时间。
- valueOf():返回的是日期的毫秒表示。
- 日期格式化方法:
- toDateString()
- toTimeString()
- toLocaleDateString()
- toLocaleTimeString()
- toUTCString()
- 日期/时间组件方法(106页/131)
2. RegExp
- 语法:let expression = /pattern/flags;
- pattern(模式)
- 所有元字符在模式中必须转义(使用反斜杠\转义),包括:( [ { \ ^ $ | ) ] } ? * + .
- flags(标记)
- g:全局模式。
- i:不区分大小写。
- m:多行模式。表示查找到一行文本末尾时会继续查找。
- y:粘附模式。表示只查找从lastIndex开始及之后的字符串。
- u:Unicode模式。
- s:dotAll模式。表示元字符.匹配任何字符(包括\n或\r)。
- 正则表达式也可以用构造函数创建,接收两个参数:模式字符串和(可选的)标记字符串。new RegExp(pattern, flags);
- 使用RegExp也可以基于已有的正则表达式实例,并可选择性修改它们的标记。
- 实例属性
- global:是否设置了g标记
- ignoreCase:是否设置了i标记
- unicode:是否设置了u标记
- sticky:是否设置了y标记
- lastIndex:整数,源字符串中下一次搜索的开始位置,始终从0开始。
- multiline:是否设置了m标记
- dotAll:是否设置了s标记
- source:正则表达式的字面量字符串,没有开头和结尾的斜杠。
- flags:正则表达式的标记字符串。没有前后斜杠。
- 实例方法
- exec():用于配合捕获组使用。
- 参数:要应用的字符串。
- 返回值:
- index:字符串中模式匹配的起始位置。
- input:要查找的字符串。
- 如果设置了全局模式,每次调用该方法返回一个匹配的信息。如果没有设置,无论调用多少次,只会返回第一个匹配信息。全局模式下每次调用exec()都会更新lastIndex值。
- test():
- 参数:要应用的字符串。
- 返回值:匹配返回true,否则返回false。
- exec():用于配合捕获组使用。
- 构造函数属性:没有任何Web标准出处,不要在生产环境中使用!!!
- 模式局限
3. 原始值包装类型
- Boolean:对应布尔值的引用类型。建议永远不要使用。
- Number:对应数值的引用类型。
- toString():可选地接受一个表示基数的参数,并返回响应基数形式的数值字符串。
- toFixed():接收一个参数,表示小数位数。返回包含指定小数点位数的数值字符串。四舍五入,支持0~20个小数位。
- toExponential():接收一个参数,表示小数位数。返回以科学计数法表示的字符串。
- toPrecision():根据实际情况返回最合理的输出结果,可能是固定长度,也可能是科学计数法形式。接收一个参数,表示结果中数字的总位数(不包含指数)。
- Number.isInteger():用于辨别一个数值是否保存为整数。
- Number.isSafeInteger():用于辨别一个数值是否是安全整数。范围从 Number.MIN_SAFE_INTEGER(2^53+1)到 Number.MAX_SAFE_INTEGER(2^53-1)。
- String:对应字符串的引用类型。
- 使用String构造函数来创建一个String对象。 例:New String(“hello world”);
- valueOf()、toLocaleString()、toString()都返回对象的原始字符串。
- length属性,表示字符串中字符的数量。
- JavaScript字符
- charAt()方法返回给定索引位置的字符,由传给方法的整数参数指定。
- charCodeAt()方法可以查看指定码元的字符编码(码元值),不能用来解析代理对字符。为了正确解析既包含单码元字符又包含代理对字符的字符串,可以使用codePointAt()。
- fromCharCode()方法用于根据指定的UTF-16码元创建字符串中的字符。可以接受任意多个数值,返回将所有数值对应的字符拼接起来的字符串。fromCodePoint()可以接收任意数量的码点。
- normalize()方法
- 对字符串进行规范化,有四种规范化形式:“NFD”, “NFC”, “NFKD”, “NFKC”。
- 字符串操作方法
- concat():将一个或多个字符串拼接成一个新字符串。可以接收任意多个参数。使用“+”更方便。
- slice(), substr(), substring():返回调用它们的字符串的一个子字符串,而且都接收一个或两个参数。对于slice(), substring()而言,第一个参数表示字符串开始的位置,第二个参数表示字符串结束的位置[,)。对于substr()而言,第二个参数表示返回的子字符串数量。任何情况下省略第二个字符串都以为止提取到字符串末尾。
- 字符串位置方法
- indexOf():在字符串中定位子字符串,从字符串开头开始查找子字符串。可以接收可选的第二个参数,表示开始搜索的位置,从参数指定位置开始向字符串末尾搜索。
- lastIndexOf():在字符串中定位子字符串,从字符串末尾开始查找子字符串。可以接收可选的第二个参数,表示开始搜索的位置,从参数指定位置开始向字符串开头搜索。
- 字符串包含方法:从字符串中搜索传入的字符串,并返回一个是否包含的布尔值。
- stratsWith():检查开始于索引0的匹配项。
- endsWith():检查开始于索引(String.length-substring.length)的匹配项。
- includes():检查整个字符串。
- trim()方法
- 创建一个字符串副本,删除前、后所有空格符,再返回结果。
- trimLeft()和trimRight()方法分别用于从字符串开始和末尾清理空格符。
- repeat()方法
- 接受一个整数参数,表示要将字符串复制多少次,然后返回拼接所有副本后的结果。
- padStart()和padEnd()方法
- 复制字符串,如果小于指定长度,则在相应一边填充字符,直至满足长度条件。第一个参数是长度,第二个参数是可选的填充字符串,默认为空格。
- 可以将填充字符串截断以匹配指定长度。如果长度小于或等于字符串长度,则会返回原始字符串。
- 字符串迭代与解构
- 迭代字符串中的每个字符
let message = "bac";
let stringIterator = message[Symbol.iterator]();
stringIterator.next();
- 解构
let message = "abc";
[...message];
- 迭代字符串中的每个字符
- 字符串大小写转换
- toLowerCase()、toLocalLowerCase()
- toUpperCase()、toLocalUpperCase()
- 如果不知道代码涉及什么语言,最好使用地区特定的转换方法。
- 字符串模式匹配方法
- match():接收一个参数,可以是正则表达式字符串,也可以是RegExp对象。
- search():参数同match(),返回模式第一个匹配的位置索引,如果没有找到则返回-1。
- replace():字符串替换操作。两个参数,第一个参数可以是一个RegExp对象或一个字符串,第二个参数可以是一个字符串或一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,第一个参数必须为正则表达式并且带全局标记。
- split():根据传入的分隔符将字符串拆分成数组。
- localeCompare()方法
- 比较两个字符串,返回如下3个值中的一个。
- 如果按照字母表顺序,字符串应该排在字符串参数前头,返回负值。
- 如果字符串与字符串参数相等,返回0。
- 如果按照字母表顺序,字符串应该排在字符串参数后头,返回正值。
- 比较两个字符串,返回如下3个值中的一个。
- HTML方法。基本不用了。
- 单例内置对象
- Global
- 在全局作用域中定义的变量和函数都会变成Global对象的属性。
- URL编码方法
- encodeURI()方法
- encodeURIComponent()方法
- eval()方法:一个完整的ECMAScript解释器。
- Global对象属性
- window对象
- 浏览器将window对象实现为Global对象的代理,因此,所有全局作用域中声明的变量和函数都变成了window的属性。
- Math:Math对象作为保存数学公式、信息和计算的地方。
- Math对象属性
- min() 和 max()方法
- 用于确定一组数值中的最小值和最大值。
- 可以使用扩展符
let values = [1, 2, 3, 4, 5];
let max= Math.max(…val);
- 舍入方法
- Math.ceil():向上舍入为最接近的整数。
- Math.floor():向下舍入为最接近的整数。
- Math.round():四舍五入。
- Math.fround():返回数值最接近的单精度(32位)浮点值表示。
- random()方法:返回一个0~1范围内的随机数,其中包含0但不包含1。
- 其他方法
- Math对象属性
- Global
第6章:集合引用类型
1. Object
- 创建Object实例
- 使用new操作符和Object构造函数。let person = new Object();
- 使用对象字面量表示法。let person = {}
- 存取属性的两种方式:点语法和中括号语法。
2. Array:每个槽位可以存储任意类型的数据,数组大小是动态的。
- 创建数组
- 构造函数 new Array();
- 数组字面量表示法 let arr = [];
- 用于创建数组的静态方法 from() 和 of()
- 数组空位
- 可以使用一串逗号来创建空位。
- 实践中要避免使用数组空位,如果确实需要,可以显式地用undefined值代替。
- 数组索引,同C语言
- 检测数组
- 在只有一个网页(因而只有一个全局作用域)的情况下,使用instanceof操作符就可以
- Array.isArray()方法
- 迭代器方法
- keys():返回数组索引的迭代器。
- values():返回数组元素的迭代器。
- entries():返回索引/值对的迭代器。
- 复制和填充方法
- 批量复制方法copyWithin()。
- 填充数组方法fill()。
- 转换方法
- toLocaleString()、toString()、valueOf():返回一个逗号分隔的数组值的字符串。
- join():接收一个参数,表示字符串分隔符,返回一个由指定字符串分隔符连接的字符串。如果不传入参数,默认使用逗号。
- 栈方法
- push()方法:进栈
- pop()方法:出栈
- 队列方法
- shift()方法:出队。shift()和push()可以把数组当队列使用。
- unshift()方法:在数组开头添加任意多个值,然后返回新的数组长度。unshift()和pop()可以在相反方向上模拟队列。
- 排序方法
- reverse():将数组元素反向排列。
- sort():按照升序重新排列数组元素。会在每一项上调用String()转型函数,然后比较字符串来决定顺序,即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序。
- sort()方法可以接受一个比较函数作为参数,用于判断哪个值应该排在前面。比较函数可以简写为箭头函数。
- 操作方法
- concat()方法:在现有数组全部元素的基础上创建一个新数组。
- slice()方法:用于创建一个包含原有数组中一个或多个元素的新数组。
- splice()方法:在数组中间插入元素。
- 删除。2个参数:要删除的第一个元素的位置和要删除的元素数量。
- 插入。3个参数:开始位置、0(要删除的元素数量)、要插入的元素。可以有第四、第五个元素。
- 替换。3个参数:开始位置、要删除的元素数量、要插入的任意多个元素。
- 始终返回一个数组,包含从数组中被删除的元素,如果没有删除元素,返回空数组。
- 搜索和位置方法
- 按严格相等搜索:indexOf()、lastIndexOf()、includes()
- 按断言函数搜索:
- 断言函数接收3个元素:元素、索引、数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,数组是正在搜索的数组。断言函数返回真值,表示是否匹配。
- find():返回第一个匹配的元素。
- findIndex():返回第一个匹配元素的索引。
- 迭代方法:对数组每一项都运行传入的函数
- every():如果对每一项函数都返回true,则这个方法返回true。
- filter():函数返回true的项会组成数组之后返回。
- forEach():没有返回值。
- map():返回由每次函数调用的结果构成的数组。
- some():如果有意向函数返回true,则这个方法返回true。
- 归并方法
- reduce():从前往后
- reduceRight():从后往前
3. 定型数组(没看懂 P155 180)
- ArrayBuffer
- DataView
- 定型数组
4. Map
- 基本API
- 使用new关键字和Map构造函数可以创建一个空映射。
- 初始化后可以使用set()方法再添加键/值对。
- 可以使用get()和has()进行查询。
- 可以通过size属性获取映射中的键/值对数量。
- 可以使用delete()和clear()删除值。
- Map内部使用SameValueZero比较操作。
- 顺序与迭代
- map实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。
- 迭代器能以插入顺序生成[key, value]形式的数组。可以使用entries()方法取得迭代器。可以直接对映射实例使用扩展操作,把映射转换为数组。
- 如果不使用迭代器,也可以使用回调方式forEach()。
- keys()和values()分别返回以插入顺序生成键和值的迭代器。
- 选择Object还是Map
- 内存占用:给定固定大小内存,Map大约可以比Object多存储50%的键/值对。
- 插入性能:Map性能更佳。
- 查找速度:Object更好一些。
- 删除性能:Map更好一些。
5. WeakMap(弱映射)
- 使用new关键字实例化一个空的WeakMap
- 弱映射中的键只能是Object或者继承自Object的类型,尝试使用非对象设置键会抛出TypeError。
- 值的类型没有限制。
- weakMap实例没有clear()方法
6. Set
- 基本API
- 使用new关键字和Set构造函数可以创建一个空集合。
- 初始化后,可以使用add()增加值,使用has()查询,通过size取得元素数量,使用delete()和clear()删除元素。
- Set可以包含任何JavaScript数据类型作为值。
- 用作值的对象和其他“集合”类型在自己的内容或属性被修改时也不会改变(不太明白,啥意思呢?pdf199)
- 顺序与迭代
- Set会维护值插入时的顺序,因此支持按顺序迭代。
- 可以通过values()方法及其别名方法keys()或者Symbol.iterator属性,取得迭代器。
- 可以直接对集合实例使用扩展操作,把集合转换为数组。
- 集合的entries()方法返回一个迭代器,可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复出现。如果不使用迭代器,可以使用forEach()方法。
- 定义正式集合操作
- 在子类上实现静态方法,然后在实例方法中使用这些静态方法。
7. WeakSet(弱集合)
- 使用new关键字实例化一个空的WeakSet。
- 弱集合中的值只能是Object或者继承自Object的类型,尝试使用非对象设置值会抛出TypeError。
- 初始化后可以使用add()再添加新值,使用has()查询,使用delete()删除。
- 不可迭代。
8. 迭代与扩展操作
- 4种原生集合类型定义了默认迭代器:Array,所有定型数组,Map,Set
- 上述所有类型支持顺序迭代,可以传入for-of循环
- 上述所有类型兼容扩展操作符。浅复制(只会复制对象引用)特有用。