随笔-119  评论-133  文章-4  trackbacks-0

3 语言基础

【变量】

1、使用var操作符定义的变量会成为包含它的函数的局部变量;但是在函数内定义变量时省略var操作符,可以创建一个全局变量(不推荐)

2、使用var关键字声明的变量会自动提升到函数作用域顶部(只是声明会提升,初始化赋值不会);但是let声明的变量不会在作用域中被提升

3let声明的范围是块作用域,而var声明的范围是函数作用域,块作用域是函数作用域的子集

4let不允许同一个块作用域中出现冗余声明(但是var可以),但是嵌套使用相同的标识符不会报错(这是因为同一个块中没有重复声明),不能混用letvar而对变量进行冗余声明

5、使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量则会)

6、对于let这个声明关键字,不能依赖条件声明模式(因为它是块作用域),但用在for循环中刚好合适(使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量)

7const的行为与let基本相同,唯一区别是用const声明变量时必须同时初始化,且尝试修改const声明的变量会导致运行时错误(但是如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制)

8、有了letconst,大多数开发者会发现自己不再需要var了;很多开发者认为应该优先使用const来声明变量,只在提前知道未来会有修改时,再使用let

【数据类型】

1ECMAScript6种简单数据类型(也称为原始类型):UndefinedNullBooleanNumber

StringSymbol,还有一种复杂数据类型叫Object(也叫引用类型),包含普通对象、数组Array、函数Function、正则RegExp、日期Date

2、特殊值null被认为是一个对空对象的引用,所以typeof null返回的是"object";另外typeof函数返回”function”(为了方便识别,给函数单独标了function)

3、对未声明的变量,只能执行一个有用的操作,就是对它调用typeof。在对未初始化的变量调用typeof时,返回的结果是"undefined",但对未声明的变量调用它时,返回的结果还是"undefined"(所以建议在声明变量的同时进行初始化)

4、在定义将来要保存对象值的变量时,建议使用null来初始化,不要使用其他值

5undefined值是由null值派生而来的,所以==判断为true(所以推荐用===判断)undefinednull,都是假值

6Number类型使用双精度值表示整数和浮点值,浮点值的精确度最高可达17位小数,但在算术计算中远不如整数精确,因此永远不要测试某个特定的浮点值

7、任何涉及NaN的操作始终返回NaN,其次,NaN不等于包括NaN在内的任何值,任何不能转换为数值的值都会导致isNaN()函数返回true

8Number()是转型函数,可用于任何数据类型。后两个函数主要用于将字符串转换为数值,考虑到用Number()函数转换字符串时相对复杂且有点反常规,优先使用parseInt()parseFloat()函数。parseInt()也接收第二个参数,用于指定底数(进制数),parseFloat()只解析十进制值,因此不能指定底数

9String(字符串)数据类型表示零或多个16Unicode字符序列。字符串可以使用双引号(")、单引号(')或反引号(`)标示

10toString()方法可见于数值、布尔值、对象和字符串值,nullundefined值没有toString()方法;在对数值调用toString()方法时,可以接收一个底数参数,即以什么底数来输出数值的字符串表示

11、如果你不确定一个值是不是nullundefined,可以使用String()转型函数,它始终会返回表示相应类型值的字符串(typeof也可以判断)

12、模板字面量最常用的一个特性是支持字符串插值,字符串插值通过在${}中使用一个JavaScript表达式实现

13、即使采用相同的符号描述,在全局注册表中定义的符号跟使用Symbol()定义的符号也并不等同

【操作符】

1、  ECMAScript中的所有数值都以IEEE 754 64位格式存储,但位操作并不直接应用到64位表示,而是先把值转换为32位整数,再进行位操作,之后再把结果转换为64位,特殊值NaNInfinity在位操作中都会被当成0处理

2、  逻辑非操作,如果操作数是NaN,则返回true,如果操作数是undefined,则返回true

3、  +运算符倾向于得到字符串,-运算符-倾向于得到数值,关系运算符倾向于得到数值(任何关系操作符在涉及比较NaN时都返回false)

4、  相等操作符,第一组是等于和不等于,它们在比较之前执行转换。第二组是全等和不全等,它们在比较之前不执行转换。(null==undefined, null != 0, undefined != 0)。由于相等和不相等操作符存在类型转换问题,因此推荐使用全等和不全等操作符。

【语句】

1、  for-in语句用于枚举对象中的非符号键属性;for-of用于遍历可迭代对象的元素

2、  switch语句可以用于所有数据类型,因此可以使用字符串甚至对象,其次,条件的值不需要是常量,也可以是变量或表达式(switch语句在比较每个条件的值时会使用全等操作符,因此不会强制转换数据类型)

【函数】

1ECMAScript中的函数不需要指定是否返回值。任何函数在任何时间都可以使用return语句来返回函数的值,用法是后跟要返回的值


4章变量、作用域与内存

【原始值与引用值】

1、原始值大小固定,因此保存在栈内存上;引用值是对象,存储在堆内存上

2、  JavaScript 不允许直接访问内存位置,因此也就不能直接操作对象所在的内存空间。在操作对象时,实际上操作的是对该对象的引用(reference)而非实际的对象本身

3、  对于引用值而言,可以随时添加、修改和删除其属性和方法(原始值不能有属性)

4、  在通过变量把一个原始值赋值到另一个变量时,原始值会被复制到新变量的位置; 在把引用值从一个变量赋给另一个变量时, 这里复制的值实际上是一个指针,它指向存储在堆内存中的对象, 两个变量实际上指向同一个对象

5、  typeof 虽然对原始值很有用,但它对引用值的用处不大。为了解决这个问题,ECMAScript提供了instanceof操作符

【执行上下文与作用域】

1、  执行上下文分全局上下文、函数上下文和块级上下文。代码执行流每进入一个新上下文,都会创建一个作用域链,用于搜索变量和函数

2、每个上下文都有一个关联的变量对象(variable object),而这个上下文中定义的所有变量和函数都存在于这个对象上。在浏览器中,全局上下文就是我们常说的window对象,因此所有通过var定义的全局变量和函数都会成为window对象的属性和方法

3、上下文在其所有代码都执行完毕后会被销毁,包括定义在它上面的所有变量和函数。每个函数调用都有自己的上下文。当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文

4、上下文中的代码在执行的时候,会创建变量对象的一个作用域链(分清楚上下文<->作用域链<->变量对象的关系),内部上下文可以通过作用域链访问外部上下文中的一切,但外部上下文无法访问内部上下文中的任何东西

5var声明会被拿到函数或全局作用域的顶部,位于作用域中所有代码之前。这个现象叫作“提升”

6、  Let的作用域是块级的,块级作用域由最近的一对包含花括号{}界定,if块、while块、function块,甚至连单独的块也是let声明变量的作用域

7、  使用const声明的变量必须同时初始化为某个值。一经声明,在其生命周期的任何时候都不能再重新赋予新值

【垃圾回收】

1、如果数据不再必要,那么把它设置为null,从而释放其引用。这也可以叫作解除引用。这个建议最适合全局变量和全局对象的属性。


5 基本引用类型

RegExp

1、对象被认为是某个特定引用类型的实例。新对象通过使用new操作符后跟一个构造函数(constructor)来创建

2、正则表达式可以使用字面量形式定义的,也可以使用RegExp构造函数来创建,它接收两个参数:模式字符串和(可选的)标记字符串

3、与其他语言中的正则表达式类似,所有元字符在模式中也必须转义,包括:( [ { \ ^ $ | ) ] } ? * + .

4、在全局匹配模式下,每次调用exec()都会更新lastIndex值,以反映上次匹配的最后一个字符的索引

【原始值包装类型】

1、  由于原始值包装类型的存在,JavaScript中的原始值可以被当成对象来使用。有3种原始值包装类型:BooleanNumberStringObject构造函数作为一个工厂方法,能够根据传入值的类型返回相应原始值包装类型的实例

2、  理解原始布尔值和Boolean对象之间的区别非常重要,强烈建议永远不要使用后者

3、  当某个参数是负值时, slice()方法将所有负值参数都当成字符串长度加上负参数值。

substr()方法将第一个负参数值当成字符串长度加上该值,将第二个负参数值转换为0

substring()方法会将所有负参数值都转换为0

4、  indexOflastIndexOf都可以接收可选的第二个参数,表示开始搜索的位置。这意味着,indexOf()会从这个参数指定的位置开始向字符串末尾搜索,忽略该位置之前的字符;lastIndexOf()则会从这个参数指定的位置开始向字符串开头搜索,忽略该位置之后直到字符串末尾的字符

5、  startsWith()includes()方法接收可选的第二个参数,表示开始搜索的位置;endsWith()方法接收可选的第二个参数,表示应该当作字符串末尾的位置(抹掉那以后的字符)

6、  字符串模式匹配方法有match()search()replace()split()


6 集合引用类型

Object

1、显式地创建Object的实例有两种方式。第一种是使用new操作符和Object构造函数,另一种方式是使用对象字面量(object literal)表示法(对象字面量是对象定义的简写形式) 在对象字面量表示法中,属性名可以是字符串或数值(数值属性会自动转换为字符串),对象字面量已经成为给函数传递大量可选参数的主要方式

2、虽然属性一般是通过点语法来存取的,但也可以使用中括号来存取属性。在使用中括号时,要在括号内使用属性名的字符串形式(””),使用中括号的主要优势就是可以通过变量访问属性(不需要””)。另外,如果属性名中包含可能会导致语法错误的字符,或者包含关键字/保留字时,也可以使用中括号语法

Array

1、  数组中每个槽位可以存储任意类型的数据,数组也是动态大小的,会随着数据添加而自动增长(不会动态缩小)

2、  创建数组的方法,可以使用Array构造函数(可以给构造函数传入一个数值表示length属性,也可以给Array构造函数传入要保存的元素);另一种创建数组的方式是使用数组字面量(array literal)表示法。Array构造函数还有两个ES6新增的用于创建数组的静态方法:from()of()from()用于将类数组结构转换为数组实例,而of()用于将一组参数转换为数组实例。Array.from()还接收第二个可选的映射函数参数。这个函数可以直接增强新数组的值,还可以接收第三个可选参数,用于指定映射函数中this的值

3、  实践中要避免使用数组空位。如果确实需要空位,则可以显式地用undefined值代替

4、  数组length属性不是只读的,通过修改length属性,可以从数组末尾删除或添加元素(使用length属性可以方便地向数组末尾添加元素)

5、  ES6中,Array 的原型上暴露了3个用于检索数组内容的方法:keys()values()entries()keys()返回数组索引的迭代器,values()返回数组元素的迭代器,而entries()返回索引/值对的迭代器(使用ES6的解构可以非常容易地在循环中拆分键/值对)

6、  ES6新增了两个方法:批量复制方法copyWithin(),以及填充数组方法fill()

7、  join()方法接收一个参数,即字符串分隔符,返回包含所有项的字符串

8、  栈是一种后进先出(LIFOLast-In-First-Out)的结构,也就是最近添加的项先被删除。数据项的插入(称为推入,push)和删除(称为弹出,pop)只在栈的一个地方发生,即栈顶(ECMAScript数组提供了push()pop()方法,以实现类似栈的行为)

9、  队列以先进先出(FIFOFirst-In-First-Out)形式限制访问。队列在列表末尾添加数据,但从列表开头获取数据。使用shift()push(),可以把数组当成队列来使用;通过使用unshift()pop(),可以在相反方向上模拟队列,即在数组开头添加新数据,在数组末尾取得数据

10、数组有两个方法可以用来对元素重新排序:reverse()sort(),调用sort()会按照这些数值的字符串形式重新排序,sort()方法可以接收一个比较函数,用于判断哪个值应该排在前面

11、如果传入一个或多个数组,则concat()会把这些数组的每一项都添加到结果数组(打平)

12、slice()用于创建一个包含原有数组中一个或多个元素的新数组。

13、splice()的主要目的是在数组中间插入元素(参数20表明插入而非删除;参数2>0代表要删除的个数)

14、ECMAScript提供两类搜索数组的方法:按严格相等搜索(indexOflastIndexOfincludes)和按断言函数搜索(findfindIndex方法使用了断言函数, 这两个方法也都接收第二个可选的参数,用于指定断言函数内部this的值。)

15、数组定义了5个迭代方法(everyfilterforEachmapsome)

16、ECMAScript为数组提供了两个归并方法:reduce()reduceRight()

17、ECMAScript为数组提供了两个归并方法:reduce()reduceRight()

【定型数组】

1、  定型数组(typed array)指的其实是一种特殊的包含数值类型的数组,ArrayBuffer是所有定型数组及视图引用的基本单位(要读取或写入ArrayBuffer,就必须通过视图)

2、  DataView。这个视图专为文件I/O和网络I/O设计,其API支持对缓冲数据的高度控制,但相比于其他类型的视图性能也差一些(其内存中值的字节序,默认为大端字节序)

3、  定型数组是另一种形式的ArrayBuffer视图,它特定于一种ElementType且遵循系统原生的字节序,设计定型数组的目的就是提高与WebGL等原生库交换二进制数据的效率(定型数组的构造函数和实例都有一个BYTES_PER_ELEMENT属性,返回该类型数组中每个元素的大小)

Map

1、  作为ECMAScript 6的新增特性,Map是一种新的集合类型。与Object只能使用数值、字符串或符号作为键不同,Map可以使用任何JavaScript数据类型作为键(Map实例会维护键值对的插入顺序,因此可以根据插入顺序执行迭代操作)

Set

1、  Set会维护值插入时的顺序,因此支持按顺序迭代

【迭代与扩展操作】

1、有4种原生集合类型定义了默认迭代器(Array、定型数组、MapSet),扩展操作符在对可迭代对象执行浅复制时特别有用,只需简单的语法就可以复制整个对象(浅复制意味着只会复制对象引用)


7章迭代器与生成器

【迭代】

1、可迭代对象不一定是集合对象,也可以是仅仅具有类似数组行为的其他数据结构。迭代器(iterator)是按需创建的一次性对象。每个迭代器都会关联一个可迭代对象,迭代器无须了解与其关联的可迭代对象的结构,只需要知道如何取得连续的值

2、在ECMAScript中,这意味着必须暴露一个属性作为“默认迭代器”,而且这个属性必须使用特殊的Symbol.iterator作为键。这个默认迭代器属性必须引用一个迭代器工厂函数,调用这个工厂函数必须返回一个新迭代器。接收可迭代对象的原生语言特性包括:for-of、数组解构、扩展操作符、Array.from()、创建集合、创建映射,Promise.all()Promise.race()yield*操作符(这些原生语言结构会在后台调用提供的可迭代对象的这个工厂函数,从而创建一个迭代器)

3、迭代器API使用next()方法在可迭代对象中遍历数据。每次成功调用next(),都会返回一个IteratorResult对象,包含两个属性:donevalue

4Iterator(迭代器):干活的人,有 next()方法;Iterable(可迭代对象):能被遍历的容器,有 Symbol.iterator属性,调用返回interator(迭代器)

【生成器】

1、生成器的形式是一个函数,函数名称前面加一个星号(*)表示它是一个生成器,调用生成器函数会产生一个生成器对象,生成器对象一开始处于暂停执行(suspended)的状态,调用next()方法会让生成器开始或恢复执行。

2yield关键字可以让生成器停止和开始执行(yield关键字有点像函数的中间返回语句,它生成的值会出现在next()方法返回的对象里。通过yield关键字退出的生成器函数会处在done: false状态;通过return关键字退出的生成器函数会处于done: true状态。) yield关键字只能在生成器函数内部使用,yield关键字必须直接位于生成器函数定义中。

3、调用生成器函数返回的就是一个标准 Iterator 迭代器,自带 .next(),每调用一次 it.next(),代码执行到下一个 yield 就暂停

4、和普通函数最大区别:普通函数,一口气跑完,不能暂停;生成器函数,可暂停、可分步执行,yield = 暂停 + 返回值

5、总结:生成器函数 function* 自动帮你快速生成迭代器,不用手写 nextdone,极简实现迭代协议


posted on 2026-04-25 15:39 lfc 阅读(8) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。