javascript基础;
数据类型;
基本数据类型;Symbol;

操作符;
语句;

疑问:

  • 很多东西实现底层都是基于Symbol(迭代器、Array.contact、String.match),那么在ES6以前是怎么实现的呢?
  • weakMap中,“以私有成员的字典为值”,字典是什么意思?

    书摘&心得

    1 javascript的组成

  • ECMAScript,一种伪语言,提供核心语言功能。

  • 文档对象模型DOM,提供访问和操作网页内容的方法和接口。
  • 浏览器对象模型BOM,提供与浏览器交互的方法和接口。

    2 数据类型

  • 有6种简单的数据类型:boolean、string、null、number、undefined、Symbol(ES6新增),还有一种复杂数据类型object。

  • typeof返回值:boolean、string、object、number、undefined、function、symbol,其中null的返回值是object。

    2.1 undefined与null

  • 使用var声明变量但未初始化时,变量的值为undefined

  • 直接使用尚未定义的变量会报错,但是可以通过typeof检查其类型,为undefined
  • undefined的值是派生自null的:alert(undefined==null)为true,而alert(undefined===null)为false
  • 如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值,让null成为空对象指针。

    2.2布尔值的转换

    | 数据类型 | 转换为true | 转换为false | | —- | —- | —- | | Boolean | TRUE | FALSE | | String | 任何非空字符串 | “”(空字符串) | | Number | 任何非零数字 | 0和NAN | | Object | 任何对象 | null | | Undefined | 无 | undefined |

2.3数字类型

  • 十进制:直接输入
  • 八进制:以0开头,后跟八进制数字序列(0~7),若字面值超出范围,则数值被当做十进制解析。(在严格模式下无效)
  • 十六进制:以0x开头,后跟十六进制数字序列(0~9及A~F),大小写不限。
  • 浮点数值中必包含小数点。由于浮点数需要的内存空间是整数的两倍,ECMAScript会不失时机地将浮点数值转换为整数。
  • 极大或极小数值可以用e表示法。3.125e7等于31250000;3e-5等于0.00003
  • 浮点数值的计算精度远不及整数,因此永远不要测试某个特定的浮点数值。
  • ECMAScript能储存的最小值保存在Number.MIN_VALUE中,在大多数浏览器中这个值是5e-324;ECMAScript能储存的最大值保存在Number.MAX_VALUE中,在大多数浏览器中这个值是1.7976931348623157e+308
  • 超出范围的数会被转换为Infinity,使用isFinite()函数可以判断参数是否有穷。
  • NaN(Not a Number)是一个特殊的Number类型,0除以0会返回NaN,任何涉及NaN的操作都会返回NaN。
  • NaN与任何值都不相等,包括NaN本身
  • 任何不能被转换为数值的值都会导致isNaN()函数返回true
  • isNaN()也适用于对象,在基于对象调用isNaN时,会首先调用对象的valueOf(),然后确定返回值是否可以转换为数值。如果不能,则基于这个返回值再调用toString(),再测试返回值。

    2.3.1 数值转换

    有3个函数可以把非数值转换为数值:Number()、parseInt()、parseFloat()。Number()可用于任何数据类型。另外两个函数则专门用于把字符串转换成数值。
    1、Number()转换规则

  • Boolean:true和false将分别转换为1和0。

  • Number:只是简单的传入和返回。
  • null:返回0。
  • undefined:返回NaN。
  • String:字符串中只包含数字则转换为十进制数值;包含有效的浮点格式则转换为对应浮点数值;包含有效的十六进制格式则转换为对应十进制整数;空字符串转换为0;其它字符串转为NaN

2、parseInt()转换规则
忽略字符串前面的空格,直至找到第一个非空格字符,若该字符不是数字或负号则返回NaN。然后parseInt会继续解析第二个字符,直到遇到一个非数字字符。存在第二个参数,可以指定转换的进制。

  • 空字符串:返回NaN.
  • 浮点数:向下取整
  • 0开头字符串:解析为十进制(ES3解析为八进制)
  • 0x开头字符串:解析为十六进制

3、parsetFloat()转换规则
与parsetInt类似,存在以下差异:

  • 浮点数:能正常解析第一个小数点。
  • 0开头字符串:忽略前导零,只解析十进制数。
  • 0x开头字符串:0

4、一元加减符号
对非数值应用一元加减操作符时,会像Number()转型函数一样对该值执行转换。
【注】关系操作符中若涉及到数值转换,同样会像Number()转型函数一样对值执行转换

2.4 String类型

ECMAScript中的字符串不可变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。
1、toString()

  • Number、Boolean、Object、String都有toString()方法。但null和undefined没有这个方法。
  • 调用Number的toString方法时,可以传递一个参数,代表进制。

2、String()
在不知道转换的值是不是null或undefined的情况下使用转型函数String()

  • 如果值有toString()方法,则调用该方法并返回相应的结果。
  • 如果值是null,则返回”null”
  • 如果值是undefined,则返回”undefined”

    2.5 Symbol类型

  • 调用Symbol构造函数时传入的字符串为符号的描述,与符号定义、标识无关image.png

    • Symbol.prototype.description属性可以访问描述(只读)
      • image.png
  • 不能与new关键词连用
  • 重用符号

    • 在全局注册表中定义符号,使用Symbol.for
    • 必须使用字符串创建

      1. let fooGlobalSymbol = Symbol.for('foo');
      2. let otherGlobalSymbol = Symbol.for('foo');
      3. console.log(fooGlobalSymbol === otherGlobalSymbol); // true
    • 使用Symbol()定义的符号和全局注册表中定义的符号不同

      1. let fooGlobalSymbol = Symbol.for('foo');
      2. let localSymbol = Symbol('foo');
      3. console.log(localSymbol === fooglobalSymbol); // false
    • Symbol.KeyFor可以查询全局注册表

      1. // 创建全局符号
      2. let s = Symbol.for('foo');
      3. console.log(Symbol.keyFor(s)); // foo
      4. // 创建普通符号
      5. let s2 = Symbol('bar');
      6. console.log(Symbol.keyFor(s2)); // undefined

      常用内置符号

  • 在提到ECMAScript规范时,经常会引用符号在规范中的名称,前缀为@@。

    • 比如,@@iterator指的就是Symbol.iterator。
  • 使用时感知不到,在底层暗流涌动

    1、Symbol.asyncIterator

  • 表示实现异步迭代器API的函数

  • for await…of循环会利用这个函数执行异步迭代操作
  • 被该符号标识的原生函数只有异步生成器
  • 详见谈谈js异步流程管理与函数科里化附录A、第11章 期约与异步函数

    2、Symbol.hasInstance

  • 一个方法,该方法决定一个构造器对象是否认可一个对象是它的实例

  • 这个属性定义在Function的原型对象prototype上

    • 因此在所有函数和类上都可以调用
    • instanceof操作符会在原型链上寻找这个属性定义,一般会直接找到Funtion的原型对象上
    • 因此,可以自定义一个static方法覆盖原型对象上定义的Symbol.hasInstance,如下:
      1. class C { static [Symbol.hasInstance]() { return false; }}
      2. var c = new C();
      3. c instanceof C; // false

      3、Symbol.iterator

  • 标志对象的一个方法

  • 返回对象的迭代器(最常见)
  • 由Symbol.iterator函数生成的对象应该通过其next()方法陆续返回值

    其他

  • Symbol.isConcatSpreadable:一个布尔值,设置后会影响Array.prototype.contact()的行为

  • Symbol.match:一个正则表达式方法,由String.match使用
  • ……更多详见书本

    2.6 Object类型

    Object类型是所有它的实例的基础,Object类型所具有的任何属性和方法也同样存在于更具体的对象中。
    Object的每个实例都具有下列属性和方法:

  • constructor:保存着用于创建当前对象的函数

  • hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例(而不是实例的原型)中是否存在。
  • isPrototypeOf(object):用于检查传入的对象是否是传入对象的原型。
  • propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
  • toLocaleString():返回对象的字符串表示(与执行环节的地区对应)。
  • toString():返回对象的字符串表示。
  • valueOf():返回对象的字符串、数值或布尔值表示。

    3 操作符

    详见书本。
    值得一提的是相等操作符,==两侧操作数在对比前会发生类型转换,而===两侧操作数在对比前不会发生类型转换。

    4 语句

    详见书本。

  • 其中label语句和with语句好像已经不用了。

  • switch语句在比较值时使用的是全等操作符,因此不会发生类型转换。
  • 这样写就可以方便地在switch语句中使用关系操作符了:

    • image.png

      5 函数

  • 要么让函数始终都返回一个值,要么永远不要返回值。

  • ECMAScript函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。之所以会这样,是因为ECMAScript中的参数在内部是用一个数组表示的。在函数体内可以通过arguments对象来访问这个参数数组。
  • arguments对象和数组类似,一样具有length属性;但也存在不同,不具有Array所具有的方法。
  • 函数中命名的参数只是提供便利,但不是必须的。
  • arguments对象可以与命名参数一起使用。
  • arguments对象的长度是由传入的参数个数决定的,不是由定义函数时的命名参数的个数决定的。
  • 没有传递值的命名参数将自动被赋予undefined值。
  • 严格模式中重写arguments的值会导致语法错误。
  • ECMAScript中的所有参数传递的都是值,不可能通过引用传递参数(传递引用类型时传递的是参数在内存中的地址的值)。
  • 由于不存在函数签名(接收参数的类型和数量)的特性,ECMAScript函数不能重载,不过可以通过检查传入函数中参数的类型和数量作出不同的反应,从而模拟重载。

    6 基本类型与引用类型概述

    基本类型值指的是简单的数据段,引用类型值指那些可能由多个值构成的对象。

  • 基本类型值在复制变量时会在变量对象上创建一个新值,然后把该值赋值到为新变量分配的位置上。两个变量可以参与任何操作而不会相互影响。

  • 引用类型值在复制变量时,同样也将存储在变量对象中的值复制一份放到为新变量分配的空间中,不同的是该值的副本实际上是一个指针。因此改变其中一个变量就会影响到另一个变量。原理如下图:image.png

    6.1 传递参数

    访问变量有按值和按引用两种方式,而参数只能按值传递。在向参数传递基本类型的值时,被传递的值会被复制给一个局部变量(命名参数/arguments对象中的一个元素)。在向参数传递引用类型的值时,会把这个值在内存中的地址复制给一个局部变量,因此这个局部变量的变化会反映在函数的外部。

    6.2 检测类型

  • 检测基本数据类型typeof是非常得力的助手,但检测引用类型时用处不大。

  • ECMAScript提供了instanceof操作符用于检测引用类型是什么类型的对象。
  • 用法:result=variable instanceof constructor
  • 如果变量是给定引用类型的实例,那么instanceof操作符会返回true