你不知道的JS(九):类型和值

一、类型

  • 强制类型转换是JavaScript开发人员最头疼的问题之一,它常被诟病为语言设计的一个缺陷。
  • 全面掌握JavaScript的类型之后,我们旨在改变对强制类型转换的成见,看到它的好处并意识到它的缺点被过分夸大。

1. 内置类型

JavaScript有七种内置类型

  • 空值(null
  • 未定义(undefined
  • 布尔值(boolean
  • 数字(number
  • 字符串(string
  • 对象(object
  • 符号(symbol

(还有新增的BigInt,支持任意长度的整数,所以现在是八种基本类型。)

typeof查看类型

  • 我们可以通过typeof运算符来查看值的类型。
  • typeof查看null比较特殊
typeof null === "object"; // true
  • 正确的返回结果应该是“null”,但这个bug由来已久。
  • 因为这牵扯太多的Web系统,“修复”它会产生更过bug,令许多系统无法正常工作。
  • 我们需要使用复合条件来检测null值的类型
var a = null;
(! a && typeof a === "object"); // true

2. 值和类型

  • JavaScript 中的变量是没有类型的,只有值才有。变量可以随时劫持任何类型的值。
  • 也就是说,一个变量可以现在被赋值为字符串类型的值,随后又被赋值为数字类型的值。
var a = 42;
typeof a; // "number"
a = true;
typeof a; // "boolean"

undefinedundeclared

  • 已在作用域中声明但没有赋值的变量,是为undefined
  • 还没有在作用域中声明过的变量,是undeclared
  • 在浏览器中的报错信息不一样。
  • 但是用typeof判断是一样的,这是因为typeof安全防范机制

二、值

1. 数组

  • 与其他强类型的语言不同,在JavaScript中,数组可以容纳任何类型的值,可以是字符串、数字、对象(object),甚至其他数组。
  • 数组通过数字进行索引,但它们也是对象,所以也可以包含字符串键值和属性。

2. 类数组

  • 类数组是一个普通对象,而数组是Array类型。
  • 有时候需要通过数组工具函数(如ndexOf()concant()forEach())转换成数组。
  • 常见类数组:arguments

3. 字符串

  • JavaScript中字符串是不可变的。
  • 就是字符串的成员函数不会改变其原始值,而是创建并返回一个新的字符串。

4. 数字

  • JavaScript中的数字类型是基于IEEE 754标准来决定的,该标准通常也被称为“浮点数”。JavaScript使用的“双精度”格式。
  • toFixed() 可以指定小数部分的显示位数。
0.1 + 0.2 === 0.3; // false
  • 二进制浮点数中的0.1和0.2并不是十分精确,它们相加的结果是一个比较接近0.3的数字。

5. 特殊数值

  • null指空值
  • undefined指没有值

不是数字的数字

  • NaN指"不是一个数字",是一个警戒值,用于数字类型中的错误情况,即“执行运算没有成功”。
var a = 2 / "foo"; // NaN
typeof a === "number"; // true

可以通过isNaN()判断一个值是否是NaN

无穷数

计算结果一旦溢出为无穷数(Infinity)

var a = 1 / 0; // Infinity

零值

  • JavaScript有一个常规的0(也叫做+0),和一个-0。
  • 在有些程序中的数据需要以级数形式来表示(比如动画帧的移动速度),数字的符号位用来代表其他信息(比如移动的方向)。

6. 特殊等式

  • Object.is()判断两个值是否绝对相等,可以用来处理所有的特殊情况。(比如:NaN
  • 能使用=====时就尽量不要使用Object.is(),因为前者效率更高、更为通用。
  • Object.is()用来处理那些特殊的相等比较

7. 值和引用

  • JavaScript对值和引用的赋值/传递在语法上没有区别,结果完全根据值的类型来决定的。
  • 简单值(即标量基本类型值)总是通过值复制的方式来赋值/传递,包括nullundefined、字符串、数字、布尔值和符号。
  • 复合值,总是通过引用赋值的方式来传递的。
  • 由于引用指向的是值本身,并未变量,所以一个引用无法更改另一个引用的指向。

三、原生函数

  • 常用原生函数(也称内置函数)有:

  • String()Number()Boolean()Array()Object()Function()RegExp()Date()Error()Symbol()

  • 原生函数可以当作构造函数来使用。

var a = new String("abc");
typeof a; // 是"object",不是“String”
a instanceof String; // true
Object.prototype.toString.call(a); // "[object String]"
  • 通过构造函数创建出来的是封装了基本类型的值的封装对象

  • 例如:new String("abc"),创建的是字符串“abc”的封装对象,而非基本类型值“abc”。

1. 内部属性

  • 所有typeof返回值为“object”的对象都包含一个内部属性。这个属性无法直接访问,可以通过Object.prototype.toString(...)来查看。
Object.prototype.toString.call([1,2,3]); // "[object Array]"
  • 基本类型值被各自的封装对象自动包装,所以它们也能获取到内部属性。
Object.prototype.toString.call("abc"); // "[object String]"

封装对象包装

  • 由于基本类型没有lengthtoString()这样的属性和方法,需要通过封装对象才能访问。
  • 此时,JavaScript会自动为基本类型值包装一个封装对象。
var a = "abc";
a.length; // 3
a.toUpperCase() // "ABC"

拆封

如果想要得到分装对象中的基本类型值,可以使用valueOf()函数。

var a = new String("abc");
a.valueOf(); // "abc"

2. 原生函数作为构造函数

  • 应该尽量避免使用构造函数来创建对象,因为可能产生意想不到的结果。
  • 通常使用字面量的形式。

Array()

var a = new Array(1,2,3); // 构造函数
var b = Array(1,2,3); // 不带new
var c = [1, 2, 3]; // 字面量
  • 构造函数Array()可以不带new,会自动补上。
  • 问题:当构造函数Array()只有一个参数的时候,该参数会作为数组的预设长度,而不是元素。

Object()/Function()和RegExp()

  • 这几个尽量不要使用
  • 通过new Object()创建对象,无法像字面量形式那样一次设定多个属性,必须逐一设定属性

Date()和Error()

  • 这两个用处很大,并没有对应的字面量形式替代。
  • 创建日期对象,必须使用new Date()
    • 可以带参数,用来指定日期和时间
    • 不带参数,则使用当前的日期和时间
  • 构造函数Error()带不带new关键字都可。
  • 创建错误对象主要是为了获取当前运行栈的上下文。栈上下文信息包含函数调用栈信息和产生的错误代码,以便调试。
throw new Error("x wasn't provided");

Symbol()

  • 符号是具有唯一性的特殊值,用他来命名对象属性不容易导致重名。
  • 这个比较特殊,不带new
var a = Symbol("my own symbol");

3. 原生原型

  • 原生构造函数都有自己的原型对象。
  • 这些对象包含其对应子类型所特有的行为特征
  • 而且这些原生原型是能够进行修改的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值