资讯专栏INFORMATION COLUMN

最全Javascript数据类型解析

Rango / 3382人阅读

摘要:数据类型最新的标准定义了种数据类型种原型数据类型变量未定义时的属性。布尔值,和表示数字,例如或者。函数,可以将其他类型的值转换为布尔类型。值可以显式转为字符串布尔值,但是不能转为数值。首先是动态数据类型的语言,很多类型检查是不必要的。

数据类型

最新的 ECMAScript 标准定义了 7 种数据类型:

6种原型数据类型(primitive type):

undefined. 变量未定义时的属性。

null. 一个表明 null 值的特殊关键字。 JavaScript 是大小写敏感的,因此 null 与 Null、NULL或其他变量完全不同。

Boolean. 布尔值,true 和 false.

Number. 表示数字,例如: 42 或者 3.14159。

String. 表示字符串,例如:"Howdy"

Symbol ( 在 ECMAScript 6 中新添加的类型).。一种数据类型,它的实例是唯一且不可改变的。

以及 Object 对象。(complex type 复杂类型)

undefined 类型

Undefined类型只有一个值undefined,表示"缺少值",就是此处应该有一个值,但是还没有定义。主要的用法:

(1)变量被声明了,但没有赋值时,就等于undefined。
(2) 调用函数时,应该提供的参数没有提供,该参数等于undefined。
(3)对象没有赋值的属性,该属性的值为undefined。
(4)函数没有返回值时,默认返回undefined。
PS: 值 undefined 并不同于未定义的值。但是,typeof 运算符并不真正区分这两种值。
var i;
console.log(i) ; // undefined

function f(x){console.log(x)}
f();  // undefined

var  o = new Object();
console.log(o.p);  // undefined

var func = f();
console.log(func);  // undefined

console.log(typeof y); //"undefined"
null 类型

null类型的默认值是null,从逻辑角度讲,是表示一个空对象指针,表示"没有对象",即该处不应该有值。主要用法:

(1) 作为函数的参数,表示该函数的参数不是对象。
(2) 作为对象原型链的终点。
Object.getPrototypeOf(Object.prototype)  // null

区别undefined:

当一个变量声明后,未初始化,则该值为undefined,如果这个值是为了保存对象,则修改其默认初始化的值,改为null。 所以当检测其类型时,会显示类型为object。
typeof null        // object (历史原因,不是"null")
typeof undefined   // "undefined"
null === undefined // false
null  == undefined // true
null === null // true
null == null // true
!null // true
Number(null) // 0
Number(undefined) // NaN
isNaN(1 + null) // false
isNaN(1 + undefined) // true
Boolean 类型

布尔类型,该类型有两个值:true false。Bloolean()函数,可以将其他类型的值转换为布尔类型。同时也存在隐式类型转换。

这里区分一下Truthy类型和Falsy类型值。
Falsy类型值包括:"", 0, null, undefined, NaN, false
除了Falsy类型值以外的都被称为Truthy类型值,它们会被转换为 true
Boolean(null)         // false
Boolean("hello")      // true 
Boolean("0")          // true 
Boolean(" ")          // true 
Boolean([])           // true 
Boolean(function(){}) // true
Number 类型

根据 ECMAScript 标准,JavaScript 中只有一种数字类型:基于 IEEE 754 标准的双精度 64 位二进制格式的值(-(263 -1) 到 263 -1)。它并没有为整数给出一种特定的类型。除了能够表示浮点数外,还有一些带符号的值:+Infinity,-Infinity 和 NaN (非数值,Not-a-Number)。
整数可以用十进制(基数为10)、十六进制(基数为16)、八进制(基数为8)以及二进制(基数为2)的字面值来表示。

0, 117 and -345 (十进制, 基数为10)
015, 0001 and -0o77 (八进制, 基数为8) 
0x1123, 0x00111 and -0xF1A7 (十六进制, 基数为16或"hex")
0b11, 0b0011 and -0b11 (二进制, 基数为2)

浮点数(有趣的一点是,在计算前其存储为字符串)所占据的内存空间是整数的两倍。
语法:[(+|-)][digits][.digits][(E|e)[(+|-)]digits]

3.14      
-.2345789 // -0.23456789
-3.12e+12  // -3.12*1012
.1e-23    // 0.1*10-23=10-24=1e-24

NaN:
1、即非数值,是一个特殊的值,这个数值用于表示一个本来要返回数值的操作数,未返回数值的情况。比如任何数值除以0,本是不符合规范的,js里,这样的操作返回NaN(但是实际上,只有0除以0时返回NaN,其他则无穷值)。

2、NaN有两个不同寻常的特点:任何涉及NaN的操作都会返回NaNNaN值与任何值都不相等,包括本身。
3、isNaN()函数,这个函数可以判断,传递的参数是否“不是数值”这里涉及数值转换的问题,例如“10”这个字符串就可以转换为10,但是“blue”这个字符串则无法转换为数字,所以isNaN("blue")==true

+0 === -0  //true
42 / +0; // Infinity
42 / -0; // -Infinity
NaN == NaN //false

+Infinity,-Infinity:
要检查值是否大于或小于 +/-Infinity,你可以使用常量 Number.MAX_VALUENumber.MIN_VALUE。另外在 ECMAScript 6 中,你也可以通过 Number.isSafeInteger() 方法还有 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 来检查值是否在双精度浮点数的取值范围内。 超出这个范围,JavaScript 中的数字不再安全了,也就是只有 second mathematical interger 可以在 JavaScript 数字类型中正确表现。

String 类型

这个算是比较熟悉的了这里引用一下MDN的描述。
JavaScript的字符串类型用于表示文本数据。它是一组16位的无符号整数值的“元素”。在字符串中的每个元素占据了字符串的位置。第一个元素的索引为0,下一个是索引1,依此类推。字符串的长度是它的元素的数量。
不同于类 C 语言,JavaScript 字符串是不可更改的。这意味着字符串一旦被创建,就不能被修改。但是,可以基于对原始字符串的操作来创建新的字符串。
主要强调一下ES2015的模板字符串:

// Basic literal string creation
`In JavaScript "
" is a line-feed.`

// Multiline strings
`In JavaScript this is
 not legal.`

// String interpolation
var name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

// Construct an HTTP request prefix is used to interpret the replacements and construction
POST`http://foo.org/bar?a=${a}&b=${b}
     Content-Type: application/json
     X-Credentials: ${credentials}
     { "foo": ${foo},
       "bar": ${bar}}`(myOnReadyStateChangeHandler);
       
String()函数可以将任何类型的值转换为字符串,包括null转换为"null"undefined转换为"undefined"
Symbol 类型

语法:Symbol([description])
1、每个从Symbol()返回的symbol值都是唯一的。
直接使用Symbol()创建新的symbol类型,并用一个字符串(可省略)作为其描述。以下代码创建了三个新的symbol类型。 字符串 “foo” 的作用仅为描述,它每次都会创建一个新的 symbol类型:

var sym1 = Symbol();
var sym2 = Symbol("foo");
var sym3 = Symbol("foo");
Symbol("foo") === Symbol("foo"); // false

还可以使用Symbol.for方法创建新的symbol类型,和前者区别Symbol.for()会把symbol值以一个key值登记到全局环境中,Symbol()就不会。Symbol.for()不会每次调用就返回一个新的 Symbol 类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。比如,如果你调用Symbol.for("cat")30 次,每次都会返回同一个 Symbol 值,但是调用Symbol("cat")30 次,会返回 30 个不同的 Symbol 值。查看登记的Symbol值可以使用Symbol.keyFor方法,该方法返回一个已登记的 Symbol 类型值的key。

let sym1 = Symbol("foo");
let sym2 = Symbol("foo");
let sym3 = Symbol.for("foo");
let sym4 = Symbol.for("foo");
sym1 === sym2  //false
sym3 === sym4  //true
Symbol.keyFor(sym1) //undefined
Symbol.keyFor(sym3) //"foo"

2、 不再支持new 运算符的语法:

var sym = new Symbol(); // TypeError

这会阻止创建一个显式的 Symbol 包装器对象而不是一个 Symbol 值。围绕原始数据类型创建一个显式包装器对象从 ECMAScript 6 开始不再被支持。 然而,现有的原始包装器对象,如 new Boolean、new String以及new Number因为遗留原因仍可被创建。

3、特殊的类型转换
Symbol 值不能与其他类型的值进行运算。
Symbol 值可以显式转为字符串、布尔值,但是不能转为数值。

4、用于对象属性名(主要)
Symbol 值作为对象属性名时,不能用点运算符。一般通过方括号结构和Object.defineProperty,将对象的属性名指定为一个 Symbol 值。

let sym1 = Symbol();
let sym2 = Symbol();
let sym3 = Symbol();

let a = {
  [sym1]: "Symbol1";
};
a[sym2] = "Symbol2";
Object.defineProperty(a, sym3, { value: "Symbol3" });

a.sym1 = "Hello!";
a[sym1] // "Symbol1"
a["sym1"] // "Hello!"

Symbol 作为属性名,该属性不会出现在for...infor...of循环中,也不会被Object.keys()Object.getOwnPropertyNames()JSON.stringify()返回。但是,它也不是私有属性,有一个Object.getOwnPropertySymbols方法,返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

更多的Symbol相关内容参考这篇文章——传送门
对象

在计算机科学中, 对象是指内存中的可以被标识符引用的一块区域。
对象属于复杂数据类型,也可以说是引用类型(逻辑上等价于class/类)。相对于原始数据类型的直接存取(栈内存),复杂数据类型的存储方式为引用(堆内存,栈内存保存对应的指针)。

Object 对象

ECMAScript 中的所有对象都由这个对象继承而来,Object 对象中的所有属性和方法都会出现在其他对象中,所以理解了 Object 对象,就可以更好地理解其他对象。
本文主要介绍以下几点:

Object()作为函数以及Object()构造函数

Object静态方法

Object实例方法

1、Object()与new Object()
Object函数可以把任意值转换为对象;new Object()则是生成新对象,可以简写为{}。除语义上的不同外,两者的用法相同,以下以Object()为例:

var obj = Object();
var obj = Object(undefined);
var obj = Object(null);
//以上语句等效,返回空对象
obj instanceof Object // true

var obj = Object(1);
obj instanceof Object // true
obj instanceof Number // true

var obj = Object("foo");
obj instanceof Object // true
obj instanceof String // true

var obj = Object(true);
obj instanceof Object // true
obj instanceof Boolean // true

如果参数本来就是一个对象便不需要转换,直接返回该对象:

var arr = [];
var obj = Object(arr); // 返回原数组
obj === arr // true

var value = {};
var obj = Object(value) // 返回原对象
obj === value // true

var fn = function () {};
var obj = Object(fn); // 返回原函数
obj === fn // true

2、Object静态方法
所谓“静态方法”,是指部署在Object对象自身的方法。例如:Object.key = value{key:value}
一般使用Object.keys方法和Object.getOwnPropertyNames方法来遍历对象的属性。区别在于后者可以列举不可枚举的属性名,例如数组的length

var a = ["Hello", "World"];

Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]

其他静态方法:(传送门)
1)对象属性模型的相关方法

Object.getOwnPropertyDescriptor():获取某个属性的描述对象。

Object.defineProperty():通过描述对象,定义某个属性。定义key为Symbol的属性的方法之一。

Object.defineProperties():通过描述对象,定义多个属性。

2)控制对象状态的方法

Object.preventExtensions():防止对象扩展。

Object.isExtensible():判断对象是否可扩展。

Object.seal():禁止对象配置。

Object.isSealed():判断一个对象是否可配置。

Object.freeze():冻结一个对象。

Object.isFrozen():判断一个对象是否被冻结。

3)原型链相关方法

Object.assign(target, ...sources):用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

Object.create():该方法可以指定原型对象和属性,返回一个新的对象。

Object.getPrototypeOf():获取对象的Prototype对象。

3、Object实例方法
定义在Object.prototype的·对象称为实例方法,所有Object的实例对象都继承了这些方法。
Object实例对象的方法,主要有以下六个。

Object.prototype.valueOf():返回当前对象对应的值。

Object.prototype.toString():返回当前对象对应的字符串形式。检测对象类型。

Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。

Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。

Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。

Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。

数据类型判断

之所以会说到这个判断问题,主要原因是typeof是不太靠谱的。首先JavaScript是动态数据类型的语言,很多类型检查是不必要的。在具体实现上的问题,在实际的项目应用中,typeof也只有两个用途,就是检测一个元素是否为undefined,或者是否为function。由下面的表格可见一斑:

Value               function   typeof
-------------------------------------
"foo"               String     string
new String("foo")   String     object
1.2                 Number     number
new Number(1.2)     Number     object
true                Boolean    boolean
new Boolean(true)   Boolean    object
new Date()          Date       object
new Error()         Error      object
[1,2,3]             Array      object
new Array(1, 2, 3)  Array      object
new Function("")    Function   function
/abc/g              RegExp     object
new RegExp("meow")  RegExp     object
{}                  Object     object
new Object()        Object     object 

如果还是要判断的话,公认的靠谱解法是 Object.prototype.toString.call(x) === "[object type]"。具体实现可以参考jQuery.type()源码。另外通过构造函数创建的对象都可以用 instanceof 检查。

参考

http://www.ruanyifeng.com/blo...

https://zhuanlan.zhihu.com/p/...

https://developer.mozilla.org...

https://developer.mozilla.org...

https://javascript.ruanyifeng...

https://segmentfault.com/q/10...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93386.html

相关文章

  • 【进阶3-1期】JavaScript深入之史上最全--5种this绑定全面解析

    摘要:在严格模式下调用函数则不影响默认绑定。回调函数丢失绑定是非常常见的。因为直接指定的绑定对象,称之为显示绑定。调用时强制把的绑定到上显示绑定无法解决丢失绑定问题。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第三期,本周的主题是this全面解析,今天是第9天。 本计划一共28期,每期重点攻克一个面试重...

    xavier 评论0 收藏0
  • 最全的前端模块化方案

    摘要:模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。将一个复杂的系统分解为多个模块以方便编码。顺手写一个省略省略实现此时的对应的形式解析省略执行兼容,模块化语法。 模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。将一个复杂的系统分解为多个模块以方便编码。 会讲述以下内容 CommonJS AMD 及 核心原理实现 CMD 及 核心原理实现 UMD 及 源码解析 ES6...

    antz 评论0 收藏0
  • 阿里 2021 版最全 Java 并发编程笔记,看完我才懂了“内卷”的真正意义

    摘要:纯分享直接上干货操作系统并发支持进程管理内存管理文件系统系统进程间通信网络通信阻塞队列数组有界队列链表无界队列优先级有限无界队列延时无界队列同步队列队列内存模型线程通信机制内存共享消息传递内存模型顺序一致性指令重排序原则内存语义线程 纯分享 , 直接上干货! 操作系统并发支持 进程管理内存管...

    不知名网友 评论0 收藏0
  • 正在暑假中的《课多周刊》(第1期)

    摘要:正在暑假中的课多周刊第期我们的微信公众号,更多精彩内容皆在微信公众号,欢迎关注。若有帮助,请把课多周刊推荐给你的朋友,你的支持是我们最大的动力。原理微信热更新方案涨知识了,热更新是以后的标配。 正在暑假中的《课多周刊》(第1期) 我们的微信公众号:fed-talk,更多精彩内容皆在微信公众号,欢迎关注。 若有帮助,请把 课多周刊 推荐给你的朋友,你的支持是我们最大的动力。 远上寒山石径...

    liukai90 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<