基本类型

JavaScript 中基本数据类型

本部分主要是针对于 JavaScript 中常用的数据结构类型进行分析说明。JavaScript 中内置了Object, Array, Date, String, Number, or Boolean这几个数据类型。

typeof Object === "function"
typeof {} ==== "object"
typeof Boolean === "function"
const boolean = new Boolean()
typeof boolean === "object"
typeof undefined ==== 'undefined'

typeof null ==== 'object'

JavaScript 中数据类型可以分为两类:

  • 原始数据类型(Primitive Type ):Undefined、Null、Boolean、Number、String
  • 引用类型(Reference Type ):Object、Array、Function、Date

我们在声明变量时会有不同的内存分配:

  • 原始值:存储在栈(stack )中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。这是因为这些原始类型占据的空间是固定的,所以可将他们存储在较小的内存区域 – 栈中。这样存储便于迅速查寻变量的值。
  • 引用值:存储在堆(heap )中的对象,也就是说,存储在变量处的值是一个指针(point ),指向存储对象的内存地址。这是因为:引用值的大小会改变,所以不能把它放在栈中,否则会降低变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存储在栈中对变量性能无任何负面影响。

不同的内存分配机制也带来了不同的访问机制在 javascript 中是不允许直接访问保存在堆内存中的对象的,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值,这就是传说中的按引用访问。而原始类型的值则是可以直接访问到的。复制变量时的不同原始值:在将一个保存着原始值的变量复制给另一个变量时,会将原始值的副本赋值给新变量,此后这两个变量是完全独立的,他们只是拥有相同的 value 而已。引用值:在将一个保存着对象内存地址的变量复制给另一个变量时,会把这个内存地址赋值给新变量,也就是说这两个变量都指向了堆内存中的同一个对象,他们中任何一个作出的改变都会反映在另一个身上。(这里要理解的一点就是,复制对象时并不会在堆内存中新生成一个一模一样的对象,只是多了一个保存指向这个对象指针的变量罢了)参数传递的不同首先我们应该明确一点:ECMAScript 中所有函数的参数都是按值来传递的。但是为什么涉及到原始类型与引用类型的值时仍然有区别呢,还不就是因为内存分配时的差别。(我对比了一下,这里和复制变量时遵循的机制完全一样的嘛,你可以简单地理解为传递参数的时候,就是把实参复制给形参的过程)原始值:只是把变量里的值传递给参数,之后参数和这个变量互不影响。引用值:对象变量它里面的值是这个对象在堆内存中的内存地址,这一点你要时刻铭记在心!因此它传递的值也就是这个内存地址,这也就是为什么函数内部对这个参数的修改会体现在外部的原因了,因为它们都指向同一个对象呀。

数值类型

科学计算

取整

JavaScript 中 Math 对象提供了三种取整的方法:

  • round,四舍五入取与最接近的整数
  • floor, 对一个数进行下舍入,执行向下取整计算,返回小于或等于函数调用参数的并且与之最接近的值。
  • ceil, 对一个数进行上舍入,执行的是向上取整计算,返回大于或者等于函数参数,并且与之最接近的整数。

pow(x, y) 返回 x 的 y 次幂的值。x,y 都是必须的且必须是数字。如果由于指数过大而引起浮点溢出,则该方法将返回 Infinity。

console.log(Math.pow(2, 10)); //1024
console.log(Math.pow(99, 9999)); //Infinity
console.log(Math.pow(1024, 0.1)); //2
console.log(Math.pow(0, 0)); //1
console.log(Math.pow(0, 1)); //0
console.log(Math.pow(2, -3)); //0.125
console.log(Math.pow(-2, 3)); //-8

随机数

random() 方法可返回介于 0 ~ 1 之间的一个随机数。

<script type="text/javascript">
  document.write(Math.random());
</script>

类型转换

JavaScript 中将字符串或者其他类型转化为数字,主要利用 parseInt、parseFloat、Number 与 JavaScript 变量弱类型转换这几种。

parseInt & parseFloat

JavaScript 提供了 parseInt() 和 parseFloat() 两个转换函数。前者把值转换成整数,后者把值转换成浮点数。只有对 String 类型调用这些方法,这两个函数才能正确运行;对其他类型返回的都是 NaN(Not a Number)。parseInt() 方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。基是由 parseInt() 方法的第二个参数指定的。parseFloat() 方法与 parseInt() 方法的处理方式相似。使用 parseFloat() 方法的另一不同之处在于,字符串必须以十进制形式表示浮点数,parseFloat() 没有基模式。

console.log(parseInt("1245red")); //1245
console.log(parseFloat("1245red")); //1245
console.log(parseInt("1245.5red")); //1245
console.log(parseFloat("1245.555red")); //1245.555
console.log(parseInt("red")); //NaN
console.log(parseInt("0xA")); //10

console.log(parseInt("AF", 16)); //175   10*16+15
console.log(parseInt("10", 2)); //2
console.log(parseInt("10", 8)); //8
console.log(parseInt("10", 10)); //10

//如果十进制数包含前导0,那么最好采用基数10,这样才不会意外地得到八进制的值
console.log(parseInt("010"));
console.log(parseInt("010", 8)); //8
console.log(parseInt("010", 10)); //10

console.log(parseFloat("1234red")); //1234
console.log(parseFloat("0xA")); //0
console.log(parseFloat("22.5")); //22.5
console.log(parseFloat("22.35.5")); //22.35
console.log(parseFloat("0908")); //908
console.log(parseFloat("blue")); //NaN

Number

使用 Number 函数,可以将任意类型的值转化成数字。

  • 数值:转换后还是原来的值。
  • 字符串:如果可以被解析为数值,则转换为相应的数值,否则得到 NaN。空字符串转为 0。
  • 布尔值:true 转成 1,false 转成 0。
  • undefined:转成 NaN。
  • null:转成 0。

Number 函数将字符串转为数值,要比 parseInt 函数严格很多。基本上,只要有一个字符无法转成数值,整个字符串就会被转为 NaN。

parseInt("011"); // 9
parseInt("42 cats"); // 42
parseInt("0xcafebabe"); // 3405691582

Number("011"); // 11
Number("42 cats"); // NaN
Number("0xcafebabe"); // 3405691582

如果 Number 传入的参数是一个对象,那么转换规则会相对复杂一点,具体而言描述如下:

  1. 先调用对象自身的 valueOf 方法,如果该方法返回原始类型的值(数值、字符串和布尔值),则直接对该值使用 Number 方法,不再进行后续步骤。
  2. 如果 valueOf 方法返回复合类型的值,再调用对象自身的 toString 方法,如果 toString 方法返回原始类型的值,则对该值使用 Number 方法,不再进行后续步骤。
  3. 如果 toString 方法返回的是复合类型的值,则报错。
        //Number()的强制类型转换与parseInt()和parseFloat()方法的处理方式相似,只是它转换的是整个值,而不是部分值。
        console.log(Number(false));     //0
        console.log(Number(true));      //1
        console.log(Number(undefined)); //NaN
        console.log(Number(null));      //0
        console.log(Number("5.5"));     //5.5
        console.log(Number("5.6.7"));   //NaN
        console.log(Number("5red"));    //NaN
        console.log(Number(new Object()));  //NaN
        console.log(Number(100));       //100
        console.log(Number(a));         //NaN

JavaScript 弱类型转换

       const str="012.345";
        const x = str-1;
        console.log(x); //11.345

        const str2 = "012.3456red";
        const x = str2-2;
        console.log(x);     //NaN

格式化显示

这里用的是numeraljs,格式化显示的效果如下所示:

  • Number
Number Format String
10000 ‘0,0.0000’ 10,000.0000
10000.23 ‘0,0’ 10,000
10000.23 ‘+0,0’ +10,000
  • Currency
Number Format String
1000.234 ‘$0,0.00’ $1,000.23
1000.2 ‘0,0[.]00 $’ 1,000.20 $
  • Bytes
Number Format String
100 ‘0b’ 100B
2048 ‘0 b’ 2 KB
  • Percentages
Number Format String
1 ‘0%’ 100%
0.974878234 ‘0.000%’ 97.488%
  • Time
Number Format String
25 ‘00:00:00’ 0:00:25
238 ‘00:00:00’ 0:03:58

布尔类型

布尔值代表 “ 真 ” 和 “ 假 ” 两个状态。“ 真 ” 用关键字 true 表示,“ 假 ” 用关键字 false 表示。布尔值只有这两个值。如果 JavaScript 预期某个位置应该是布尔值,会将该位置上现有的值自动转为布尔值。转换规则是除了下面六个值被转为 false,其他值都视为 true。

  • undefined
  • null
  • false
  • 0
  • NaN
  • "" (空字符串)

类型转换

所有对象的布尔值都是 true,甚至连 false 对应的布尔对象也是 true。

Boolean(new Boolean(false))
// true

空类型

JavaScript 中常见的空类型为 undefined 与 null,不过typeof undefined === ‘undefined’typeof null === ‘object’

null 表示 " 没有对象 “,即该处不应该有值。典型用法是:

  • 作为函数的参数,表示该函数的参数是对象。
  • 作为对象原型链的终点。

undefined 表示 " 缺少值 “,就是此处应该有一个值,但是还未定义。典型用法是:

  • 变量被声明了,但没有赋值时,就等于 undefined。
  • 调用函数时,应该提供的参数没有提供,该参数等于 undefined。
  • 对象没有赋值的属性,该属性的值为 undefined。
  • 函数没有返回值时,默认返回 undefined。

Symbols

Symbols 是 JavaScript 的第七种原始类型,它代指一个全局唯一的不可变对象。如果需要创建一个 Symbol 对象,则需要调用 Symbol 函数:

const sym1 = Symbol();
const sym2 = Symbol("foo");
const sym3 = Symbol("foo");

如上的代码会创建三个新的符号,注意,虽然 Symbol 使用了 ”foo” 这个字符串作为输入对象,但是每次会创建一个新的符号:

Symbol("foo") === Symbol("foo"); // false

确切地说,symbol 与其它类型并不完全相像。symbol 被创建后就不可变更,你不能为它设置属性(在严格模式下尝试设置属性会得到 TypeError 的错误)。他们可以用作属性名称,这些性质与字符串类似。

另一方面,每一个 symbol 都独一无二,不与其它 symbol 等同,即使二者有相同的描述也不相等;你可以轻松地创建一个新的 symbol。这些性质与对象类似。

ES6 中的 symbol 与 Lisp 和 Ruby 这些语言中更传统的 symbol类似,但不像它们集成得那么紧密。在 Lisp 中,所有的标识符都是 symbol;在 JS 中,标识符和大多数的属性键仍然是字符串,symbol 只是一个额外的选项。

关于 symbol 的忠告:symbol 不能被自动转换为字符串,这和语言中的其它类型不同。尝试拼接 symbol 与字符串将得到 TypeError 错误。

> const sym = Symbol("<3");
> "your symbol is " + sym
// TypeError: can't convert symbol to string
> `your symbol is ${sym}`
// TypeError: can't convert symbol to string

有三种获取 symbol 的方法。

  • **调用 Symbol()。**正如我们上文中所讨论的,这种方式每次调用都会返回一个新的唯一 symbol。
  • **调用 Symbol.for(string)。**这种方式会访问 symbol 注册表,其中存储了已经存在的一系列 symbol。这种方式与通过Symbol()定义的独立 symbol 不同,symbol 注册表中的 symbol 是共享的。如果你连续三十次调用Symbol.for("cat"),每次都会返回相同的 symbol。注册表非常有用,在多个 web 页面或同一个 web 页面的多个模块中经常需要共享一个 symbol。
  • **使用标准定义的 symbol,例如:Symbol.iterator。**标准根据一些特殊用途定义了少许的几个 symbol。

Symbol

const obj = Object.create(null);
obj[Symbol.toPrimitive] = function (hint) {
  console.log(hint);
  return "";
};

console.log(String(obj));
console.log(obj + "");
console.log(+obj);
const smb =Symbol('hello');


console.log(smb);
console.log(''+smb);
console.log(1+smb);
console.log(String(smb));


// Uncaught TypeError: Cannot convert a Symbol value to a string
下一页