写点什么

javascript 中的内置对象和数据结构

发布于: 2021 年 02 月 24 日

简介

基本上所有的程序员都使用过 javascript,我们在 web 中使用 javascript,我们在服务器端使用 nodejs,js 给大家的第一映像就是简单,但是可能并不是所有人都系统的了解过 js 中的内置对象和数据结构。


今天,一起来看看吧。


基础类型

js 是一种弱类型的动态语言,虽然是弱类型的,但是 js 本身定义了很多种数据类型。


js 中有 7 种基础类型:分别是 undefined,Boolean,Number,String,BigInt,Symbol 和 null。


undefined

undefined 会自动赋值给刚刚声明的变量。举个例子:


var x; //create a variable but assign it no value
console.log("x's value is", x) //logs "x's value is undefined"
复制代码

Boolean 和 Boolean 对象

Boolean 的值就是 true 或者 false。


除了基础类型的 Boolean 值外,还有一个 Boolean 对象,用来封装 boolean 值。


如果是用 new Boolean 来构造 Boolean 对象的话,下面的例子中 Boolean 的初始值都是 false:


var bNoParam = new Boolean();var bZero = new Boolean(0);var bNull = new Boolean(null);var bEmptyString = new Boolean('');var bfalse = new Boolean(false);
复制代码

下面 boolean 对象的初始值都是 true:


var btrue = new Boolean(true);var btrueString = new Boolean('true');var bfalseString = new Boolean('false');var bSuLin = new Boolean('Su Lin');var bArrayProto = new Boolean([]);var bObjProto = new Boolean({});
复制代码

注意,我们不要使用 Boolean 对象来进行 if 条件的判断,任何 Boolean 对象,即使是初始值是 false 的 Boolean 对象,if 条件判断,都是 true:


var x = new Boolean(false);if (x) {  // this code is executed}
var x = false;if (x) { // this code is not executed}
复制代码

如果非要使用 if 条件判断,我们可以使用 Boolean 函数或者!!如下所示:


var x = Boolean(expression);     // use this...var x = !!(expression);          // ...or thisvar x = new Boolean(expression); // don't use this!
复制代码

Number 和 BigInt

Number 和 BigInt 是 JS 中的两个数字类型,其中 Number 表示的双精度 64 位二进制格式,其范围是-(253 − 1) and 253 − 1.


除此之外,Number 还有三个值:+Infinity, -Infinity, 和 NaN。


前面两个表示的是正负最大值。NaN 表示的是 Not-A-Number。


我们可以通过 isNaN 来判断是否是一个 Number:


function sanitise(x) {  if (isNaN(x)) {    return NaN;  }  return x;}
console.log(sanitise('1'));// expected output: "1"
console.log(sanitise('NotANumber'));// expected output: NaN
复制代码

BigInt 表示任意精度的整数,使用 BigInt 可以进行超出 Number 精度整数的运算。


我们可以通过在整数后面加上 n 来表示 BigInt。


> const x = 2n ** 53n;9007199254740992n> const y = x + 1n; 9007199254740993n
复制代码

注意,和 Boolean 一样,Number 和 BitInt 也有 wrapper 对象类型。


看下 Number 的 wrapper:


Number('123')  // returns the number 123Number('123') === 123  // true
Number("unicorn") // NaNNumber(undefined) // NaN
复制代码

看下 BitInt 的 wrapper 类型:


const theBiggestInt = 9007199254740991n
const alsoHuge = BigInt(9007199254740991)// ↪ 9007199254740991n
const hugeString = BigInt("9007199254740991")// ↪ 9007199254740991n
const hugeHex = BigInt("0x1fffffffffffff")// ↪ 9007199254740991n
const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111")// ↪ 9007199254740991n
复制代码

String

js 中的 String 是不可变的,同样的 String 基础类型也有和它对应的 String wrapper 对象。


String 基础类型和不使用 new 的 String 函数是一致的:


const string1 = "A string primitive";const string2 = String('A string primitive');
复制代码

上面两个 String 是一致的。但是如果使用 new 来构造 String 对象,那么两者是不一样的:


let s_prim = 'foo'let s_obj = new String(s_prim)
console.log(typeof s_prim) // Logs "string"console.log(typeof s_obj) // Logs "object"
let s1 = '2 + 2' // creates a string primitivelet s2 = new String('2 + 2') // creates a String objectconsole.log(eval(s1)) // returns the number 4console.log(eval(s2)) // returns the string "2 + 2"
复制代码

我们可以通过 String 对象的 valueOf()方法,获得其 String 基础类型。


Symbol

Symbol 是一个唯一的不可变的基础类型,一般用在对象的 key 中。


// Here are two symbols with the same description:let Sym1 = Symbol("Sym")let Sym2 = Symbol("Sym")
console.log(Sym1 === Sym2) // returns "false"
复制代码

Symbol 是不支持 new 操作的:


let sym = new Symbol()  // TypeError
复制代码

如果你真的想创建 Symbol 对象,则可以使用 Object():


let sym = Symbol('foo')typeof sym      // "symbol" let symObj = Object(sym)typeof symObj   // "object"
复制代码

null

null 表示引用的是无效的 Object 对象或者地址。


虽然 null 可以看做是 primitive,但是 null 其实是一个 Object,所有的对象都来自 null:


typeof null === 'object' // true
复制代码

Object

Object 是 js 中的一种数据类型,几乎所有的对象都继承自 Object,它存储的是 key-value 形式的数据,我们可以通过使用 Ojbect()方法或者 new Object()或者 Object 字面量的方式来创建 Object。


let o = {}let o = {a: 'foo', b: 42, c: {}}
let a = 'foo', b = 42, c = {}let o = {a: a, b: b, c: c}
复制代码

注意使用 Object()或者 new Object()是一样的效果,都会得到一个 Object 对象。


在 ES2015 之后,我们还可以使用动态的对象属性:


let param = 'size'let config = {  [param]: 12,  ['mobile' + param.charAt(0).toUpperCase() + param.slice(1)]: 4}
console.log(config) // {size: 12, mobileSize: 4}
复制代码

Function

Function 也是一个 Object,JS 中的所有函数都是 Function 对象。


(function(){}).constructor === Function
复制代码

那么通过 Function 构造函数和 function 函数定义创建出来的函数有什么区别呢?


使用 new Function 创建的函数,其作用域范围是 global,我们看一下具体的例子:


var x = 10;
function createFunction1() { var x = 20; return new Function('return x;'); // this |x| refers global |x|}
function createFunction2() { var x = 20; function f() { return x; // this |x| refers local |x| above } return f;}
var f1 = createFunction1();console.log(f1()); // 10var f2 = createFunction2();console.log(f2()); // 20
复制代码

Date

Date 是 js 中用来操作时间的 Object。我们看下 Date 的常用例子:


let today = new Date()let birthday = new Date('December 17, 1995 03:24:00')let birthday = new Date('1995-12-17T03:24:00')let birthday = new Date(1995, 11, 17)            // the month is 0-indexedlet birthday = new Date(1995, 11, 17, 3, 24, 0)let birthday = new Date(628021800000)            // passing epoch timestamp
let [month, date, year] = ( new Date() ).toLocaleDateString().split("/")let [hour, minute, second] = ( new Date() ).toLocaleTimeString().slice(0,7).split(":")
复制代码

Array

JS 内置了很多种不同类型的 Array,最常用的就是 Array 字面量和 Array Object。


我们看下怎么创建一个 Array:


let fruits = ['Apple', 'Banana'];
console.log(fruits.length); // 2console.log(fruits[0]); // "Apple"
let fruits = new Array('Apple', 'Banana');
console.log(fruits.length); // 2console.log(fruits[0]); // "Apple"
复制代码

遍历 Array:


let fruits = ['Apple', 'Banana']fruits.forEach(function(item, index, array) {  console.log(item, index)})// Apple 0// Banana 1
复制代码

添加 Item 到 Array:


let newLength = fruits.push('Orange')// ["Apple", "Banana", "Orange"]
复制代码

从最后删除 item:


let last = fruits.pop() // remove Orange (from the end)// ["Apple", "Banana"]
复制代码

从前面删除 item:


let first = fruits.shift() // remove Apple from the front// ["Banana"]
复制代码

从前面添加 item:


let newLength = fruits.unshift('Strawberry') // add to the front// ["Strawberry", "Banana"]
复制代码

删除某个 index 的 item:


let removedItem = fruits.splice(pos, 1) // this is how to remove an item
// ["Strawberry", "Mango"]
复制代码

删除多个 item:


let vegetables = ['Cabbage', 'Turnip', 'Radish', 'Carrot']console.log(vegetables)// ["Cabbage", "Turnip", "Radish", "Carrot"]
let pos = 1let n = 2
let removedItems = vegetables.splice(pos, n)// this is how to remove items, n defines the number of items to be removed,// starting at the index position specified by pos and progressing toward the end of array.
console.log(vegetables)// ["Cabbage", "Carrot"] (the original array is changed)
console.log(removedItems)// ["Turnip", "Radish"]
复制代码

拷贝 array:


let shallowCopy = fruits.slice() // this is how to make a copy// ["Strawberry", "Mango"]
复制代码

除了 Array 之外,JS 还内置了特定类型的 Array:


  • Int8Array

  • Uint8Array

  • Uint8ClampedArray

  • Int16Array

  • Uint16Array

  • Int32Array

  • Uint32Array

  • Float32Array

  • Float64Array

  • BigInt64Array

  • BigUint64Array

这些特定类型的 Array 中只能存储特定类型的值。


Keyed collections

除了数组之外,JS 中还有 key-value 的集合,比如:Map,Set,WeakMap 和 WeakSet。


对 Map 来说,我们可以通过使用 set,get,has,delete 等犯法来对 Map 进行操作:


let contacts = new Map()contacts.set('Jessie', {phone: "213-555-1234", address: "123 N 1st Ave"})contacts.has('Jessie') // truecontacts.get('Hilary') // undefinedcontacts.set('Hilary', {phone: "617-555-4321", address: "321 S 2nd St"})contacts.get('Jessie') // {phone: "213-555-1234", address: "123 N 1st Ave"}contacts.delete('Raymond') // falsecontacts.delete('Jessie') // trueconsole.log(contacts.size) // 1
复制代码

遍历 Map:


let myMap = new Map()myMap.set(0, 'zero')myMap.set(1, 'one')
for (let [key, value] of myMap) { console.log(key + ' = ' + value)}// 0 = zero// 1 = one
for (let key of myMap.keys()) { console.log(key)}// 0// 1
for (let value of myMap.values()) { console.log(value)}// zero// one
for (let [key, value] of myMap.entries()) { console.log(key + ' = ' + value)}// 0 = zero// 1 = one
复制代码

使用 forEach 来遍历 map:


myMap.forEach(function(value, key) {  console.log(key + ' = ' + value)})// 0 = zero// 1 = one
复制代码

Set 中存储的是唯一的对象。


我们看下 Set 的操作:


let mySet = new Set()
mySet.add(1) // Set [ 1 ]mySet.add(5) // Set [ 1, 5 ]
mySet.has(1) // truemySet.delete(1) // removes 1 from the set
复制代码

set 的遍历:


// logs the items in the order: 1, "some text", {"a": 1, "b": 2}, {"a": 1, "b": 2} for (let item of mySet) console.log(item)
复制代码

WeakMap,WeakSet 和 Map 于 Set 的区别在于,WeakMap 的 key 只能是 Object 对象,不能是基本类型。


为什么会有 WeakMap 呢?


对于 JS 中的 Map 来说,通常需要维护两个数组,第一个数组中存储 key,第二个数组中存储 value。每次添加和删除 item 的时候,都需要同时操作两个数组。


这种实现有两个缺点,第一个缺点是每次查找的时候都需要遍历 key 的数组,然后找到对应的 index,再通过 index 来从第二个数组中查找 value。


第二个缺点就是 key 和 value 是强绑定的,即使 key 不再被使用了,也不会被垃圾回收。


所以引入了 WeakMap 的概念,在 WeakMap 中,key 和 value 没有这样的强绑定关系,key 如果不再被使用的话,可以被垃圾回收器回收。


因为引用关系是 weak 的,所以 weakMap 不支持 key 的遍历,如果你想遍历 key 的话,请使用 Map。


本文作者:flydean 程序那些事

本文链接:http://www.flydean.com/js-built-in-objects-structures/

本文来源:flydean 的博客

欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!


发布于: 2021 年 02 月 24 日阅读数: 15
用户头像

关注公众号:程序那些事,更多精彩等着你! 2020.06.07 加入

最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧,尽在公众号:程序那些事!

评论

发布
暂无评论
javascript中的内置对象和数据结构