> 文章列表 > JavaScript学习笔记(二)

JavaScript学习笔记(二)

JavaScript学习笔记(二)

文章目录

    • 第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. 原始值与引用值

  1. 原始值(primitive value):最简单的数据。保存原始值的变量是按值访问的。
  2. 引用值(reference value):由多个值构成的对象。保存引用值的对象是按引用访问的。
  3. 动态属性
    • 引用值可以随时添加、修改和删除其属性和方法
    • 原始值不能有属性,尽管尝试给原始值添加属性不会报错。
  4. 复制值
    • 原始值复制的是原来值的副本。
    • 引用值复制的值实际上是一个指针,它指向存储在堆内存中的对象。所以操作完成后,两个变量实际上指向同一个对象,一个对象上面的变化会在另一个对象上反映出来。
  5. 传递参数:ECMAScript中所有函数的参数都是按值传递的。
  6. 确定类型
    • typeof操作符:适合用来判断一个变量是否为原始类型。typeof(variable)
    • instanceof操作符:适合用来判断引用类型的变量。result = variable instanceof constructor

2. 执行上下文与作用域

  1. 每个上下文都有一个关联的变量对象(variable object)。
  2. 上下文中的代码在执行的时候回创建变量对象的一个作用域链(scope chain)。
  3. 如果上下文是函数,则其活动对象(activation)用作变量对象。
  4. 全局上下文的变量对象始终是作用域链的最后一个变量对象。
  5. 内部上下文可以通过作用域链访问外部上下文中的一切,反之不行。
  6. 作用域链增强:下面两种情况都会在作用域链前端添加一个变量对象。(不太懂)
    • try/catch语句的catch块
    • with语句
  7. 变量声明
    • 使用var的函数作用域声明
      • var声明变量时,会被自动添加到最接近的上下文。如果未经声明就被初始化,则自动被添加到全局上下文。
      • var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前,这个现象叫做“提升”(hoisting)。
    • 使用let的块级作用域声明
      • let在同一作用域内不能声明两次。会抛出SyntaxError。
    • 使用const的常量声明
      • 声明的同时必须初始化
      • 一经声明,在其生命周期的任何时候都不能再重新赋值。
      • const声明只应用到顶级原语或者对象。也就是说,赋值为对象的const变量不能再被重新赋值为其他引用值,但对象的键不受限制。
    • 标识符查找

3. 垃圾回收

  1. JavaScript通过自动内存管理实现内存分配和闲置资源回收。
  2. 标记清理:JavaScript最常用的垃圾回收策略
    • 变量进入上下文时,加上存在于上下文的标记;变量离开上下文时,加上离开上下文标记。
    • 垃圾回收程序运行的时候,会标记存储中的所有变量。然后,将所有在上下文中的变量,以及在上下文中的变量引用的变量的标记去掉。在此之后,再被加上标记的变量就是待删除的了。随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存。
  3. 引用计数:一种没那么常用的垃圾回收策略
    • 思路是对每个值都记录它被引用的次数。
    • 很快就遇到了严重问题:循环引用。
  4. 性能
  5. 内存管理
    • 优化内存占用的最佳手段就是保证在执行代码时只保存必要的数据。如果数据不再必要,那么把它设置为null,从而释放其引用。这也可以叫做解除引用。
    • 通过const和let声明提升性能
    • 隐藏类和删除操作(不太懂)
    • 内存泄漏
      • 意外声明全局变量是最常见但是也最容易修复的内存泄漏问题。
      • 定时器也可能会导致内存泄漏。闭包
    • 静态分配与对象池

第5章:基本引用类型

引用类型跟类有点像,但不是一个概念。

1. Date:参考了Java早期版本中的java.util.Date

  1. 创建日期对象:let now = new Date();
  2. 参数传入表示该日期的毫秒数,不给Date构造函数传参数的话,创建的对象保存当前日期和时间。
  3. Date.parse():接收一个表示日期的字符串参数,将字符串参数转换为表示该日期的毫秒数。如果字符串参数不表示日期,返回NaN。
  4. Date.UTC():也返回日期的毫秒数。参数是年、零起点月、日、时、分、秒、毫秒。只有前两个时必需的。
  5. Date.now():返回方法执行日期和时间的毫秒数。
  6. toLocaleString():返回与浏览器运行的本地环境一致的日期和时间。
  7. toString():返回带市区信息的日期和时间。
  8. valueOf():返回的是日期的毫秒表示。
  9. 日期格式化方法:
    • toDateString()
    • toTimeString()
    • toLocaleDateString()
    • toLocaleTimeString()
    • toUTCString()
  10. 日期/时间组件方法(106页/131)

2. RegExp

  1. 语法:let expression = /pattern/flags;
  2. pattern(模式)
    • 所有元字符在模式中必须转义(使用反斜杠\\转义),包括:( [ { \\ ^ $ | ) ] } ? * + .
  3. flags(标记)
    • g:全局模式。
    • i:不区分大小写。
    • m:多行模式。表示查找到一行文本末尾时会继续查找。
    • y:粘附模式。表示只查找从lastIndex开始及之后的字符串。
    • u:Unicode模式。
    • s:dotAll模式。表示元字符.匹配任何字符(包括\\n或\\r)。
  4. 正则表达式也可以用构造函数创建,接收两个参数:模式字符串和(可选的)标记字符串。new RegExp(pattern, flags);
  5. 使用RegExp也可以基于已有的正则表达式实例,并可选择性修改它们的标记。
  6. 实例属性
    • global:是否设置了g标记
    • ignoreCase:是否设置了i标记
    • unicode:是否设置了u标记
    • sticky:是否设置了y标记
    • lastIndex:整数,源字符串中下一次搜索的开始位置,始终从0开始。
    • multiline:是否设置了m标记
    • dotAll:是否设置了s标记
    • source:正则表达式的字面量字符串,没有开头和结尾的斜杠。
    • flags:正则表达式的标记字符串。没有前后斜杠。
  7. 实例方法
    • exec():用于配合捕获组使用。
      • 参数:要应用的字符串。
      • 返回值:
        • index:字符串中模式匹配的起始位置。
        • input:要查找的字符串。
      • 如果设置了全局模式,每次调用该方法返回一个匹配的信息。如果没有设置,无论调用多少次,只会返回第一个匹配信息。全局模式下每次调用exec()都会更新lastIndex值。
    • test():
      • 参数:要应用的字符串。
      • 返回值:匹配返回true,否则返回false。
  8. 构造函数属性:没有任何Web标准出处,不要在生产环境中使用!!!
  9. 模式局限

3. 原始值包装类型

  1. Boolean:对应布尔值的引用类型。建议永远不要使用。
  2. 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)。
  3. 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。
        • 如果按照字母表顺序,字符串应该排在字符串参数后头,返回正值。
    • HTML方法。基本不用了。
  4. 单例内置对象
    • Global
      • 在全局作用域中定义的变量和函数都会变成Global对象的属性。
      • URL编码方法
        • encodeURI()方法
        • encodeURIComponent()方法
      • eval()方法:一个完整的ECMAScript解释器。
      • Global对象属性
        JavaScript学习笔记(二) JavaScript学习笔记(二)
      • window对象
        • 浏览器将window对象实现为Global对象的代理,因此,所有全局作用域中声明的变量和函数都变成了window的属性。
    • Math:Math对象作为保存数学公式、信息和计算的地方。
      • Math对象属性
        JavaScript学习笔记(二)
      • 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。
      • 其他方法
        JavaScript学习笔记(二)

第6章:集合引用类型

1. Object

  1. 创建Object实例
    • 使用new操作符和Object构造函数。let person = new Object();
    • 使用对象字面量表示法。let person = {}
  2. 存取属性的两种方式:点语法和中括号语法。

2. Array:每个槽位可以存储任意类型的数据,数组大小是动态的。

  1. 创建数组
    • 构造函数 new Array();
    • 数组字面量表示法 let arr = [];
    • 用于创建数组的静态方法 from() 和 of()
  2. 数组空位
    • 可以使用一串逗号来创建空位。
    • 实践中要避免使用数组空位,如果确实需要,可以显式地用undefined值代替。
  3. 数组索引,同C语言
  4. 检测数组
    • 在只有一个网页(因而只有一个全局作用域)的情况下,使用instanceof操作符就可以
    • Array.isArray()方法
  5. 迭代器方法
    • keys():返回数组索引的迭代器。
    • values():返回数组元素的迭代器。
    • entries():返回索引/值对的迭代器。
  6. 复制和填充方法
    • 批量复制方法copyWithin()。
    • 填充数组方法fill()。
  7. 转换方法
    • toLocaleString()、toString()、valueOf():返回一个逗号分隔的数组值的字符串。
    • join():接收一个参数,表示字符串分隔符,返回一个由指定字符串分隔符连接的字符串。如果不传入参数,默认使用逗号。
  8. 栈方法
    • push()方法:进栈
    • pop()方法:出栈
  9. 队列方法
    • shift()方法:出队。shift()和push()可以把数组当队列使用。
    • unshift()方法:在数组开头添加任意多个值,然后返回新的数组长度。unshift()和pop()可以在相反方向上模拟队列。
  10. 排序方法
    • reverse():将数组元素反向排列。
    • sort():按照升序重新排列数组元素。会在每一项上调用String()转型函数,然后比较字符串来决定顺序,即使数组的元素都是数值,也会先把数组转换为字符串再比较、排序。
    • sort()方法可以接受一个比较函数作为参数,用于判断哪个值应该排在前面。比较函数可以简写为箭头函数。
  11. 操作方法
    • concat()方法:在现有数组全部元素的基础上创建一个新数组。
    • slice()方法:用于创建一个包含原有数组中一个或多个元素的新数组。
    • splice()方法:在数组中间插入元素。
      • 删除。2个参数:要删除的第一个元素的位置和要删除的元素数量。
      • 插入。3个参数:开始位置、0(要删除的元素数量)、要插入的元素。可以有第四、第五个元素。
      • 替换。3个参数:开始位置、要删除的元素数量、要插入的任意多个元素。
      • 始终返回一个数组,包含从数组中被删除的元素,如果没有删除元素,返回空数组。
  12. 搜索和位置方法
    • 按严格相等搜索:indexOf()、lastIndexOf()、includes()
    • 按断言函数搜索:
      • 断言函数接收3个元素:元素、索引、数组本身。其中元素是数组中当前搜索的元素,索引是当前元素的索引,数组是正在搜索的数组。断言函数返回真值,表示是否匹配。
      • find():返回第一个匹配的元素。
      • findIndex():返回第一个匹配元素的索引。
  13. 迭代方法:对数组每一项都运行传入的函数
    • every():如果对每一项函数都返回true,则这个方法返回true。
    • filter():函数返回true的项会组成数组之后返回。
    • forEach():没有返回值。
    • map():返回由每次函数调用的结果构成的数组。
    • some():如果有意向函数返回true,则这个方法返回true。
  14. 归并方法
    • reduce():从前往后
    • reduceRight():从后往前

3. 定型数组(没看懂 P155 180)

  1. ArrayBuffer
  2. DataView
  3. 定型数组

4. Map

  1. 基本API
    • 使用new关键字和Map构造函数可以创建一个空映射。
    • 初始化后可以使用set()方法再添加键/值对。
    • 可以使用get()和has()进行查询。
    • 可以通过size属性获取映射中的键/值对数量。
    • 可以使用delete()和clear()删除值。
    • Map内部使用SameValueZero比较操作。
  2. 顺序与迭代
    • map实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作。
    • 迭代器能以插入顺序生成[key, value]形式的数组。可以使用entries()方法取得迭代器。可以直接对映射实例使用扩展操作,把映射转换为数组。
    • 如果不使用迭代器,也可以使用回调方式forEach()。
    • keys()和values()分别返回以插入顺序生成键和值的迭代器。
  3. 选择Object还是Map
    • 内存占用:给定固定大小内存,Map大约可以比Object多存储50%的键/值对。
    • 插入性能:Map性能更佳。
    • 查找速度:Object更好一些。
    • 删除性能:Map更好一些。

5. WeakMap(弱映射)

  1. 使用new关键字实例化一个空的WeakMap
  2. 弱映射中的键只能是Object或者继承自Object的类型,尝试使用非对象设置键会抛出TypeError。
  3. 值的类型没有限制。
  4. weakMap实例没有clear()方法

6. Set

  1. 基本API
    • 使用new关键字和Set构造函数可以创建一个空集合。
    • 初始化后,可以使用add()增加值,使用has()查询,通过size取得元素数量,使用delete()和clear()删除元素。
    • Set可以包含任何JavaScript数据类型作为值。
    • 用作值的对象和其他“集合”类型在自己的内容或属性被修改时也不会改变(不太明白,啥意思呢?pdf199)
  2. 顺序与迭代
    • Set会维护值插入时的顺序,因此支持按顺序迭代。
    • 可以通过values()方法及其别名方法keys()或者Symbol.iterator属性,取得迭代器。
    • 可以直接对集合实例使用扩展操作,把集合转换为数组。
    • 集合的entries()方法返回一个迭代器,可以按照插入顺序产生包含两个元素的数组,这两个元素是集合中每个值的重复出现。如果不使用迭代器,可以使用forEach()方法。
  3. 定义正式集合操作
    • 在子类上实现静态方法,然后在实例方法中使用这些静态方法。

7. WeakSet(弱集合)

  1. 使用new关键字实例化一个空的WeakSet。
  2. 弱集合中的值只能是Object或者继承自Object的类型,尝试使用非对象设置值会抛出TypeError。
  3. 初始化后可以使用add()再添加新值,使用has()查询,使用delete()删除。
  4. 不可迭代。

8. 迭代与扩展操作

  1. 4种原生集合类型定义了默认迭代器:Array,所有定型数组,Map,Set
  2. 上述所有类型支持顺序迭代,可以传入for-of循环
  3. 上述所有类型兼容扩展操作符。浅复制(只会复制对象引用)特有用。