书香隽秀 - 5.标准库
type: channel
link: https://www.huangshuxiu.com/stdlib/
description: 5.标准库
items: JSON 对象
items: RegExp 对象
items: Date 对象
items: Math 对象
items: String 对象
items: Number 对象
items: Boolean 对象
items: 包装对象
items: Array 对象
items: 属性描述对象

JSON 对象
type: item
date: 2022-12-09T00:14:00+08:00
description: JSON 对象JSON 格式JSON 格式（JavaScript Object Notation 的缩写）是一种用于数据交换的文本格式，2001年由 Douglas Crockford 提出，目的是取代繁琐笨重的 XML 格式。相比 XML 格式，JSON 格式有两个显著的优点：书写简单，一目了然；符合 JavaScript 原生语法，可以由解释引擎直接处理，不用另外添加解析代码。所以，JSON 迅速被接受，已经成为各大网站交换数据的标准格式，并被写入标准。每个 JSON 对象就是一个值，可能是一个数组或对象，也可能是一个原始类型的值。总之，只能是一个值，不能是两个或更多的值。JSON 对值的类型和格式有严格的规定。复合类型的值只能是数组或对象，不能是函数、正则表达式对象、日期对象。原始类型的值只有四种：字符串、数值（必须以十进制表示）、布尔值和null（不能使用NaN, Infinity, -Infinity和undefined）。字符串必须使用双引号表示，不能使用单引号。对象的键名必须放在双引号里面。数组或对象最后一个成员的后面，不能加逗号。以下都是合法的 JSON。["one", "two", "three"] { "one": 1, "two": 2, "three": 3 } {"names": ["张三", "李四"] } [ { "name": "张三"}, {"name": "李四"} ]以下都是不合法的 JSON。{ name: "张三", 'age': 32 } // 属性名必须使用双引号 [32, 64, 128, 0xFFF] // 不能使用十六进制值 { "name": "张三", "age": undefined } // 不能使用 undefined { "name": "张三", "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'), "getName": function () { return this.name; } } // 属性值不能使用函数和日期对象注意，null、空数组和空对象都是合法的 JSON 值。JSON 对象JSON对象是 JavaScript 的原生对象，用来处理 JSON 格式数据。它有两个静态方法：JSON.stringify()和JSON.parse()。JSON.stringify()基本用法JSON.stringify()方法用于将一个值转为 JSON 字符串。该字符串符合 JSON 格式，并且可以被JSON.parse()方法还原。JSON.stringify('abc') // ""abc"" JSON.stringify(1) // "1" JSON.stringify(false) // "false" JSON.stringify([]) // "[]" JSON.stringify({}) // "{}" JSON.stringify([1, "false", false]) // '[1,"false",false]' JSON.stringify({ name: "张三" }) // '{"name":"张三"}'上面代码将各种类型的值，转成 JSON 字符串。注意，对于原始类型的字符串，转换结果会带双引号。JSON.stringify('foo') === "foo" // false JSON.stringify('foo') === "\"foo\"" // true上面代码中，字符串foo，被转成了"\"foo\""。这是因为将来还原的时候，内层双引号可以让 JavaScript 引擎知道，这是一个字符串，而不是其他类型的值。JSON.stringify(false) // "false" JSON.stringify('false') // "\"false\""上面代码中，如果不是内层的双引号，将来还原的时候，引擎就无法知道原始值是布尔值还是字符串。如果对象的属性是undefined、函数或 XML 对象，该属性会被JSON.stringify()过滤。var obj = { a: undefined, b: function () {} }; JSON.stringify(obj) // "{}"上面代码中，对象obj的a属性是undefined，而b属性是一个函数，结果都被JSON.stringify过滤。如果数组的成员是undefined、函数或 XML 对象，则这些值被转成null。var arr = [undefined, function () {}]; JSON.stringify(arr) // "[null,null]"上面代码中，数组arr的成员是undefin…

RegExp 对象
type: item
date: 2022-12-08T15:09:00+08:00
description: RegExp 对象RegExp对象提供正则表达式的功能。概述正则表达式（regular expression）是一种表达文本模式（即字符串结构）的方法，有点像字符串的模板，常常用来按照“给定模式”匹配文本。比如，正则表达式给出一个 Email 地址的模式，然后用它来确定一个字符串是否为 Email 地址。JavaScript 的正则表达式体系是参照 Perl 5 建立的。新建正则表达式有两种方法。一种是使用字面量，以斜杠表示开始和结束。var regex = /xyz/;另一种是使用RegExp构造函数。var regex = new RegExp('xyz');上面两种写法是等价的，都新建了一个内容为xyz的正则表达式对象。它们的主要区别是，第一种方法在引擎编译代码时，就会新建正则表达式，第二种方法在运行时新建正则表达式，所以前者的效率较高。而且，前者比较便利和直观，所以实际应用中，基本上都采用字面量定义正则表达式。RegExp构造函数还可以接受第二个参数，表示修饰符（详细解释见下文）。var regex = new RegExp('xyz', 'i'); // 等价于 var regex = /xyz/i;上面代码中，正则表达式/xyz/有一个修饰符i。实例属性正则对象的实例属性分成两类。一类是修饰符相关，用于了解设置了什么修饰符。RegExp.prototype.ignoreCase：返回一个布尔值，表示是否设置了i修饰符。RegExp.prototype.global：返回一个布尔值，表示是否设置了g修饰符。RegExp.prototype.multiline：返回一个布尔值，表示是否设置了m修饰符。RegExp.prototype.flags：返回一个字符串，包含了已经设置的所有修饰符，按字母排序。上面四个属性都是只读的。var r = /abc/igm; r.ignoreCase // true r.global // true r.multiline // true r.flags // 'gim'另一类是与修饰符无关的属性，主要是下面两个。RegExp.prototype.lastIndex：返回一个整数，表示下一次开始搜索的位置。该属性可读写，但是只在进行连续搜索时有意义，详细介绍请看后文。RegExp.prototype.source：返回正则表达式的字符串形式（不包括反斜杠），该属性只读。var r = /abc/igm; r.lastIndex // 0 r.source // "abc"实例方法RegExp.prototype.test()正则实例对象的test方法返回一个布尔值，表示当前模式是否能匹配参数字符串。/cat/.test('cats and dogs') // true上面代码验证参数字符串之中是否包含cat，结果返回true。如果正则表达式带有g修饰符，则每一次test方法都从上一次结束的位置开始向后匹配。var r = /x/g; var s = '_x_x'; r.lastIndex // 0 r.test(s) // true r.lastIndex // 2 r.test(s) // true r.lastIndex // 4 r.test(s) // false上面代码的正则表达式使用了g修饰符，表示是全局搜索，会有多个结果。接着，三次使用test方法，每一次开始搜索的位置都是上一次匹配的后一个位置。带有g修饰符时，可以通过正则对象的lastIndex属性指定开始搜索的位置。var r = /x/g; var s = '_x_x'; r.lastIndex = 4; r.test(s) // false r.lastIndex // 0 r.test(s) // true上面代码指定从字符串的第五个位置开始搜索，这个位置为空，所以返回false。同时，lastIndex属性重置为0，所以第二次执行r.test(s)会返回true。注意，带有g修饰符时，正则表达式内部会记住上一次的lastIndex属性，这时不应该更换所要匹配的字符串，否则会有一些难以察觉的错误。var r = /bb/g; r.test('bb') // true r.test('-bb-') // false上面代码中，由于正则表达式r是从上一次的lastIndex位置开始匹配，导致第二次执行test方法时出现预期以外的结果。lastIndex属性只对同一个正则表达式有效，所以下面这样写是错误的。var count = 0; while (/a/g.test('babaa')) count++;上面代码会导致无限循环，因为while循环的每次匹配条件都是一个新的正则表达式，导致lastIndex属性总是等于…

Date 对象
type: item
date: 2022-12-08T11:21:59+08:00
description: Date 对象Date对象是 JavaScript 原生的时间库。它以国际标准时间（UTC）1970年1月1日00:00:00作为时间的零点，可以表示的时间范围是前后各1亿天（单位为毫秒）。普通函数的用法Date对象可以作为普通函数直接调用，返回一个代表当前时间的字符串。Date() // "Tue Dec 01 2015 09:34:43 GMT+0800 (CST)"注意，即使带有参数，Date作为普通函数使用时，返回的还是当前时间。Date(2000, 1, 1) // "Tue Dec 01 2015 09:34:43 GMT+0800 (CST)"上面代码说明，无论有没有参数，直接调用Date总是返回当前时间。构造函数的用法Date还可以当作构造函数使用。对它使用new命令，会返回一个Date对象的实例。如果不加参数，实例代表的就是当前时间。var today = new Date();Date实例有一个独特的地方。其他对象求值的时候，都是默认调用.valueOf()方法，但是Date实例求值的时候，默认调用的是toString()方法。这导致对Date实例求值，返回的是一个字符串，代表该实例对应的时间。var today = new Date(); today // "Tue Dec 01 2015 09:34:43 GMT+0800 (CST)" // 等同于 today.toString() // "Tue Dec 01 2015 09:34:43 GMT+0800 (CST)"上面代码中，today是Date的实例，直接求值等同于调用toString方法。作为构造函数时，Date对象可以接受多种格式的参数，返回一个该参数对应的时间实例。// 参数为时间零点开始计算的毫秒数 new Date(1378218728000) // Tue Sep 03 2013 22:32:08 GMT+0800 (CST) // 参数为日期字符串 new Date('January 6, 2013'); // Sun Jan 06 2013 00:00:00 GMT+0800 (CST) // 参数为多个整数， // 代表年、月、日、小时、分钟、秒、毫秒 new Date(2013, 0, 1, 0, 0, 0, 0) // Tue Jan 01 2013 00:00:00 GMT+0800 (CST)关于Date构造函数的参数，有几点说明。第一点，参数可以是负整数，代表1970年元旦之前的时间。new Date(-1378218728000) // Fri Apr 30 1926 17:27:52 GMT+0800 (CST)第二点，只要是能被Date.parse()方法解析的字符串，都可以当作参数。new Date('2013-2-15') new Date('2013/2/15') new Date('02/15/2013') new Date('2013-FEB-15') new Date('FEB, 15, 2013') new Date('FEB 15, 2013') new Date('February, 15, 2013') new Date('February 15, 2013') new Date('15 Feb 2013') new Date('15, February, 2013') // Fri Feb 15 2013 00:00:00 GMT+0800 (CST)上面多种日期字符串的写法，返回的都是同一个时间。第三，参数为年、月、日等多个整数时，年和月是不能省略的，其他参数都可以省略的。也就是说，这时至少需要两个参数，因为如果只使用“年”这一个参数，Date会将其解释为毫秒数。new Date(2013) // Thu Jan 01 1970 08:00:02 GMT+0800 (CST)上面代码中，2013被解释为毫秒数，而不是年份。new Date(2013, 0) // Tue Jan 01 2013 00:00:00 GMT+0800 (CST) new Date(2013, 0, 1) // Tue Jan 01 2013 00:00:00 GMT+0800 (CST) new Date(2013, 0, 1, 0) // Tue Jan 01 2013 00:00:00 GMT+0800 (CST) new Date(2013, 0, 1, 0, 0, 0, 0) // Tue Jan 01 2013 00:00:00 GMT+0800 (CST)上面代码中，不管有几个参数，返回的都是2013年1月1日零点。最后，各个参数的取值范围如下。年：使用四位数年份，比如2000。如果写成两位数或个…

Math 对象
type: item
date: 2022-12-08T10:33:07+08:00
description: Math 对象Math是 JavaScript 的原生对象，提供各种数学功能。该对象不是构造函数，不能生成实例，所有的属性和方法都必须在Math对象上调用。静态属性Math对象的静态属性，提供以下一些数学常数。Math.E：常数e。Math.LN2：2 的自然对数。Math.LN10：10 的自然对数。Math.LOG2E：以 2 为底的e的对数。Math.LOG10E：以 10 为底的e的对数。Math.PI：常数π。Math.SQRT1_2：0.5 的平方根。Math.SQRT2：2 的平方根。Math.E // 2.718281828459045 Math.LN2 // 0.6931471805599453 Math.LN10 // 2.302585092994046 Math.LOG2E // 1.4426950408889634 Math.LOG10E // 0.4342944819032518 Math.PI // 3.141592653589793 Math.SQRT1_2 // 0.7071067811865476 Math.SQRT2 // 1.4142135623730951这些属性都是只读的，不能修改。静态方法Math对象提供以下一些静态方法。Math.abs()：绝对值Math.ceil()：向上取整Math.floor()：向下取整Math.max()：最大值Math.min()：最小值Math.pow()：幂运算Math.sqrt()：平方根Math.log()：自然对数Math.exp()：e的指数Math.round()：四舍五入Math.random()：随机数Math.abs()Math.abs方法返回参数值的绝对值。Math.abs(1) // 1 Math.abs(-1) // 1Math.max()，Math.min()Math.max方法返回参数之中最大的那个值，Math.min返回最小的那个值。如果参数为空, Math.min返回Infinity, Math.max返回-Infinity。Math.max(2, -1, 5) // 5 Math.min(2, -1, 5) // -1 Math.min() // Infinity Math.max() // -InfinityMath.floor()，Math.ceil()Math.floor方法返回小于或等于参数值的最大整数（地板值）。Math.floor(3.2) // 3 Math.floor(-3.2) // -4Math.ceil方法返回大于或等于参数值的最小整数（天花板值）。Math.ceil(3.2) // 4 Math.ceil(-3.2) // -3这两个方法可以结合起来，实现一个总是返回数值的整数部分的函数。function ToInteger(x) { x = Number(x); return x < 0 ? Math.ceil(x) : Math.floor(x); } ToInteger(3.2) // 3 ToInteger(3.5) // 3 ToInteger(3.8) // 3 ToInteger(-3.2) // -3 ToInteger(-3.5) // -3 ToInteger(-3.8) // -3上面代码中，不管正数或负数，ToInteger函数总是返回一个数值的整数部分。Math.round()Math.round方法用于四舍五入。Math.round(0.1) // 0 Math.round(0.5) // 1 Math.round(0.6) // 1 // 等同于 Math.floor(x + 0.5)注意，它对负数的处理（主要是对0.5的处理）。Math.round(-1.1) // -1 Math.round(-1.5) // -1 Math.round(-1.6) // -2Math.pow()Math.pow方法返回以第一个参数为底数、第二个参数为指数的幂运算值。// 等同于 2 ** 2 Math.pow(2, 2) // 4 // 等同于 2 ** 3 Math.pow(2, 3) // 8下面是计算圆面积的方法。var radius = 20; var area = Math.PI * Math.pow(radius, 2);Math.sqrt()Math.sqrt方法返回参数值的平方根。如果参数是一个负值，则返回NaN。Math.sqrt(4) // 2 Math.sqrt(-4) // NaNMath.log()Math.log方法返回以e为底的自然对数值。Math.log(Math.E) // 1 Math.log(10) // 2.30258509299404…

String 对象
type: item
date: 2022-12-07T17:20:00+08:00
description: String 对象概述String对象是 JavaScript 原生提供的三个包装对象之一，用来生成字符串对象。var s1 = 'abc'; var s2 = new String('abc'); typeof s1 // "string" typeof s2 // "object" s2.valueOf() // "abc"上面代码中，变量s1是字符串，s2是对象。由于s2是字符串对象，s2.valueOf方法返回的就是它所对应的原始字符串。字符串对象是一个类似数组的对象（很像数组，但不是数组）。new String('abc') // String {0: "a", 1: "b", 2: "c", length: 3} (new String('abc'))[1] // "b"上面代码中，字符串abc对应的字符串对象，有数值键（0、1、2）和length属性，所以可以像数组那样取值。除了用作构造函数，String对象还可以当作工具方法使用，将任意类型的值转为字符串。String(true) // "true" String(5) // "5"上面代码将布尔值true和数值5，分别转换为字符串。静态方法String.fromCharCode()String对象提供的静态方法（即定义在对象本身，而不是定义在对象实例的方法），主要是String.fromCharCode()。该方法的参数是一个或多个数值，代表 Unicode 码点，返回值是这些码点组成的字符串。String.fromCharCode() // "" String.fromCharCode(97) // "a" String.fromCharCode(104, 101, 108, 108, 111) // "hello"上面代码中，String.fromCharCode方法的参数为空，就返回空字符串；否则，返回参数对应的 Unicode 字符串。注意，该方法不支持 Unicode 码点大于0xFFFF的字符，即传入的参数不能大于0xFFFF（即十进制的 65535）。String.fromCharCode(0x20BB7) // "ஷ" String.fromCharCode(0x20BB7) === String.fromCharCode(0x0BB7) // true上面代码中，String.fromCharCode参数0x20BB7大于0xFFFF，导致返回结果出错。0x20BB7对应的字符是汉字告，但是返回结果却是另一个字符（码点0x0BB7）。这是因为String.fromCharCode发现参数值大于0xFFFF，就会忽略多出的位（即忽略0x20BB7里面的2）。这种现象的根本原因在于，码点大于0xFFFF的字符占用四个字节，而 JavaScript 默认支持两个字节的字符。这种情况下，必须把0x20BB7拆成两个字符表示。String.fromCharCode(0xD842, 0xDFB7) // "告"上面代码中，0x20BB7拆成两个字符0xD842和0xDFB7（即两个两字节字符，合成一个四字节字符），就能得到正确的结果。码点大于0xFFFF的字符的四字节表示法，由 UTF-16 编码方法决定。实例属性String.prototype.length字符串实例的length属性返回字符串的长度。'abc'.length // 3实例方法String.prototype.charAt()charAt方法返回指定位置的字符，参数是从0开始编号的位置。var s = new String('abc'); s.charAt(1) // "b" s.charAt(s.length - 1) // "c"这个方法完全可以用数组下标替代。'abc'.charAt(1) // "b" 'abc'[1] // "b"如果参数为负数，或大于等于字符串的长度，charAt返回空字符串。'abc'.charAt(-1) // "" 'abc'.charAt(3) // ""String.prototype.charCodeAt()charCodeAt()方法返回字符串指定位置的 Unicode 码点（十进制表示），相当于String.fromCharCode()的逆操作。'abc'.charCodeAt(1) // 98上面代码中，abc的1号位置的字符是b，它的 Unicode 码点是98。如果没有任何参数，charCodeAt返回首字符的 Unicode 码点。'abc'.charCodeAt() // 97如果参数为负数，或大于等于字符串的长度，charCodeAt返回NaN。'abc'.charCodeAt(-1) // NaN 'abc'.charCodeA…

Number 对象
type: item
date: 2022-12-07T16:26:18+08:00
description: Number 对象概述Number对象是数值对应的包装对象，可以作为构造函数使用，也可以作为工具函数使用。作为构造函数时，它用于生成值为数值的对象。var n = new Number(1); typeof n // "object"上面代码中，Number对象作为构造函数使用，返回一个值为1的对象。作为工具函数时，它可以将任何类型的值转为数值。Number(true) // 1上面代码将布尔值true转为数值1。Number作为工具函数的用法，详见《数据类型转换》一章。静态属性Number对象拥有以下一些静态属性（即直接定义在Number对象上的属性，而不是定义在实例上的属性）。Number.POSITIVE_INFINITY：正的无限，指向Infinity。Number.NEGATIVE_INFINITY：负的无限，指向-Infinity。Number.NaN：表示非数值，指向NaN。Number.MIN_VALUE：表示最小的正数（即最接近0的正数，在64位浮点数体系中为5e-324），相应的，最接近0的负数为-Number.MIN_VALUE。Number.MAX_SAFE_INTEGER：表示能够精确表示的最大整数，即9007199254740991。Number.MIN_SAFE_INTEGER：表示能够精确表示的最小整数，即-9007199254740991。Number.POSITIVE_INFINITY // Infinity Number.NEGATIVE_INFINITY // -Infinity Number.NaN // NaN Number.MAX_VALUE // 1.7976931348623157e+308 Number.MAX_VALUE < Infinity // true Number.MIN_VALUE // 5e-324 Number.MIN_VALUE > 0 // true Number.MAX_SAFE_INTEGER // 9007199254740991 Number.MIN_SAFE_INTEGER // -9007199254740991实例方法Number对象有4个实例方法，都跟将数值转换成指定格式有关。Number.prototype.toString()Number对象部署了自己的toString方法，用来将一个数值转为字符串形式。(10).toString() // "10"toString方法可以接受一个参数，表示输出的进制。如果省略这个参数，默认将数值先转为十进制，再输出字符串；否则，就根据参数指定的进制，将一个数字转化成某个进制的字符串。(10).toString(2) // "1010" (10).toString(8) // "12" (10).toString(16) // "a"上面代码中，10一定要放在括号里，这样表明后面的点表示调用对象属性。如果不加括号，这个点会被 JavaScript 引擎解释成小数点，从而报错。10.toString(2) // SyntaxError: Unexpected token ILLEGAL只要能够让 JavaScript 引擎不混淆小数点和对象的点运算符，各种写法都能用。除了为10加上括号，还可以在10后面加两个点，JavaScript 会把第一个点理解成小数点（即10.0），把第二个点理解成调用对象属性，从而得到正确结果。10..toString(2) // "1010" // 其他方法还包括 10 .toString(2) // "1010" 10.0.toString(2) // "1010"这实际上意味着，可以直接对一个小数使用toString方法。10.5.toString() // "10.5" 10.5.toString(2) // "1010.1" 10.5.toString(8) // "12.4" 10.5.toString(16) // "a.8"通过方括号运算符也可以调用toString方法。10['toString'](2) // "1010"toString方法只能将十进制的数，转为其他进制的字符串。如果要将其他进制的数，转回十进制，需要使用parseInt方法。Number.prototype.toFixed()toFixed()方法先将一个数转为指定位数的小数，然后返回这个小数对应的字符串。(10).toFixed(2) // "10.00" 10.005.toFixed(2) // "10.01"上面代码中，10和10.005先转成2位小数，然后转成字符串。其中10必须放在括号里，否则后面的点会被处理成小数点。toFixed()方法的参数为小数位数，有效范围为0到100，超出…

Boolean 对象
type: item
date: 2022-12-07T15:27:08+08:00
description: Boolean 对象概述Boolean对象是 JavaScript 的三个包装对象之一。作为构造函数，它主要用于生成布尔值的包装对象实例。var b = new Boolean(true); typeof b // "object" b.valueOf() // true上面代码的变量b是一个Boolean对象的实例，它的类型是对象，值为布尔值true。注意，false对应的包装对象实例，布尔运算结果也是true。if (new Boolean(false)) { console.log('true'); } // true if (new Boolean(false).valueOf()) { console.log('true'); } // 无输出上面代码的第一个例子之所以得到true，是因为false对应的包装对象实例是一个对象，进行逻辑运算时，被自动转化成布尔值true（因为所有对象对应的布尔值都是true）。而实例的valueOf方法，则返回实例对应的原始值，本例为false。Boolean 函数的类型转换作用Boolean对象除了可以作为构造函数，还可以单独使用，将任意值转为布尔值。这时Boolean就是一个单纯的工具方法。Boolean(undefined) // false Boolean(null) // false Boolean(0) // false Boolean('') // false Boolean(NaN) // false Boolean(1) // true Boolean('false') // true Boolean([]) // true Boolean({}) // true Boolean(function () {}) // true Boolean(/foo/) // true上面代码中几种得到true的情况，都值得认真记住。顺便提一下，使用双重的否运算符（!）也可以将任意值转为对应的布尔值。!!undefined // false !!null // false !!0 // false !!'' // false !!NaN // false !!1 // true !!'false' // true !![] // true !!{} // true !!function(){} // true !!/foo/ // true最后，对于一些特殊值，Boolean对象前面加不加new，会得到完全相反的结果，必须小心。if (Boolean(false)) { console.log('true'); } // 无输出 if (new Boolean(false)) { console.log('true'); } // true if (Boolean(null)) { console.log('true'); } // 无输出 if (new Boolean(null)) { console.log('true'); } // true

包装对象
type: item
date: 2022-12-07T15:03:35+08:00
description: 包装对象定义对象是 JavaScript 语言最主要的数据类型，三种原始类型的值——数值、字符串、布尔值——在一定条件下，也会自动转为对象，也就是原始类型的“包装对象”（wrapper）。所谓“包装对象”，指的是与数值、字符串、布尔值分别相对应的Number、String、Boolean三个原生对象。这三个原生对象可以把原始类型的值变成（包装成）对象。var v1 = new Number(123); var v2 = new String('abc'); var v3 = new Boolean(true); typeof v1 // "object" typeof v2 // "object" typeof v3 // "object" v1 === 123 // false v2 === 'abc' // false v3 === true // false上面代码中，基于原始类型的值，生成了三个对应的包装对象。可以看到，v1、v2、v3都是对象，且与对应的简单类型值不相等。包装对象的设计目的，首先是使得“对象”这种类型可以覆盖 JavaScript 所有的值，整门语言有一个通用的数据模型，其次是使得原始类型的值也有办法调用自己的方法。Number、String和Boolean这三个原生对象，如果不作为构造函数调用（即调用时不加new），而是作为普通函数调用，常常用于将任意类型的值转为数值、字符串和布尔值。// 字符串转为数值 Number('123') // 123 // 数值转为字符串 String(123) // "123" // 数值转为布尔值 Boolean(123) // true上面这种数据类型的转换，详见《数据类型转换》一节。总结一下，这三个对象作为构造函数使用（带有new）时，可以将原始类型的值转为对象；作为普通函数使用时（不带有new），可以将任意类型的值，转为原始类型的值。实例方法三种包装对象各自提供了许多实例方法，详见后文。这里介绍两种它们共同具有、从Object对象继承的方法：valueOf()和toString()。valueOf()valueOf()方法返回包装对象实例对应的原始类型的值。new Number(123).valueOf() // 123 new String('abc').valueOf() // "abc" new Boolean(true).valueOf() // truetoString()toString()方法返回对应的字符串形式。new Number(123).toString() // "123" new String('abc').toString() // "abc" new Boolean(true).toString() // "true"原始类型与实例对象的自动转换某些场合，原始类型的值会自动当作包装对象调用，即调用包装对象的属性和方法。这时，JavaScript 引擎会自动将原始类型的值转为包装对象实例，并在使用后立刻销毁实例。比如，字符串可以调用length属性，返回字符串的长度。'abc'.length // 3上面代码中，abc是一个字符串，本身不是对象，不能调用length属性。JavaScript 引擎自动将其转为包装对象，在这个对象上调用length属性。调用结束后，这个临时对象就会被销毁。这就叫原始类型与实例对象的自动转换。var str = 'abc'; str.length // 3 // 等同于 var strObj = new String(str) // String { // 0: "a", 1: "b", 2: "c", length: 3, PrimitiveValue: "abc" // } strObj.length // 3上面代码中，字符串abc的包装对象提供了多个属性，length只是其中之一。自动转换生成的包装对象是只读的，无法修改。所以，字符串无法添加新属性。var s = 'Hello World'; s.x = 123; s.x // undefined上面代码为字符串s添加了一个x属性，结果无效，总是返回undefined。另一方面，调用结束后，包装对象实例会自动销毁。这意味着，下一次调用字符串的属性时，实际是调用一个新生成的对象，而不是上一次调用时生成的那个对象，所以取不到赋值在上一个对象的属性。如果要为字符串添加属性，只有在它的原型对象String.prototype上定义（参见《面向对象编程》章节）。自定义方法除了原生的实例方法，包装对象还可以自定义方法和属性，供原始类型的值直接调用。比如，我们可以新增一个double方法，使得字符串和数字翻倍。String.prototype.dou…

Array 对象
type: item
date: 2022-12-07T08:57:04+08:00
description: Array 对象构造函数Array是 JavaScript 的原生对象，同时也是一个构造函数，可以用它生成新的数组。var arr = new Array(2); arr.length // 2 arr // [ empty x 2 ]上面代码中，Array()构造函数的参数2，表示生成一个两个成员的数组，每个位置都是空值。如果没有使用new关键字，运行结果也是一样的。var arr = Array(2); // 等同于 var arr = new Array(2);考虑到语义性，以及与其他构造函数用法保持一致，建议总是加上new。Array()构造函数有一个很大的缺陷，不同的参数个数会导致不一致的行为。// 无参数时，返回一个空数组 new Array() // [] // 单个正整数参数，表示返回的新数组的长度 new Array(1) // [ empty ] new Array(2) // [ empty x 2 ] // 非正整数的数值作为参数，会报错 new Array(3.2) // RangeError: Invalid array length new Array(-3) // RangeError: Invalid array length // 单个非数值（比如字符串、布尔值、对象等）作为参数， // 则该参数是返回的新数组的成员 new Array('abc') // ['abc'] new Array([1]) // [Array[1]] // 多参数时，所有参数都是返回的新数组的成员 new Array(1, 2) // [1, 2] new Array('a', 'b', 'c') // ['a', 'b', 'c']可以看到，Array()作为构造函数，行为很不一致。因此，不建议使用它生成新数组，直接使用数组字面量是更好的做法。// bad var arr = new Array(1, 2); // good var arr = [1, 2];注意，如果参数是一个正整数，返回数组的成员都是空位。虽然读取的时候返回undefined，但实际上该位置没有任何值。虽然这时可以读取到length属性，但是取不到键名。var a = new Array(3); var b = [undefined, undefined, undefined]; a.length // 3 b.length // 3 a[0] // undefined b[0] // undefined 0 in a // false 0 in b // true上面代码中，a是Array()生成的一个长度为3的空数组，b是一个三个成员都是undefined的数组，这两个数组是不一样的。读取键值的时候，a和b都返回undefined，但是a的键名（成员的序号）都是空的，b的键名是有值的。静态方法Array.isArray()Array.isArray方法返回一个布尔值，表示参数是否为数组。它可以弥补typeof运算符的不足。var arr = [1, 2, 3]; typeof arr // "object" Array.isArray(arr) // true上面代码中，typeof运算符只能显示数组的类型是Object，而Array.isArray方法可以识别数组。实例方法valueOf()，toString()valueOf方法是一个所有对象都拥有的方法，表示对该对象求值。不同对象的valueOf方法不尽一致，数组的valueOf方法返回数组本身。var arr = [1, 2, 3]; arr.valueOf() // [1, 2, 3]toString方法也是对象的通用方法，数组的toString方法返回数组的字符串形式。var arr = [1, 2, 3]; arr.toString() // "1,2,3" var arr = [1, 2, 3, [4, 5, 6]]; arr.toString() // "1,2,3,4,5,6"push()，pop()push方法用于在数组的末端添加一个或多个元素，并返回添加新元素后的数组长度。注意，该方法会改变原数组。var arr = []; arr.push(1) // 1 arr.push('a') // 2 arr.push(true, {}) // 4 arr // [1, 'a', true, {}]上面代码使用push方法，往数组中添加了四个成员。pop方法用于删除数组的最后一个元素，并返回该元素。注意，该方法会改变原数组。var arr = ['a', 'b', 'c']; arr.pop() // 'c' arr // ['a', 'b']对空数组使用pop方法，不…

属性描述对象
type: item
date: 2022-12-06T10:48:14+08:00
description: 属性描述对象概述JavaScript 提供了一个内部数据结构，用来描述对象的属性，控制它的行为，比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”（attributes object）。每个属性都有自己对应的属性描述对象，保存该属性的一些元信息。下面是属性描述对象的一个例子。{ value: 123, writable: false, enumerable: true, configurable: false, get: undefined, set: undefined }属性描述对象提供6个元属性。（1）valuevalue是该属性的属性值，默认为undefined。（2）writablewritable是一个布尔值，表示属性值（value）是否可改变（即是否可写），默认为true。（3）enumerableenumerable是一个布尔值，表示该属性是否可遍历，默认为true。如果设为false，会使得某些操作（比如for...in循环、Object.keys()）跳过该属性。（4）configurableconfigurable是一个布尔值，表示属性的可配置性，默认为true。如果设为false，将阻止某些操作改写属性描述对象，比如无法删除该属性，也不得改变各种元属性（value属性除外）。也就是说，configurable属性控制了属性描述对象的可写性。（5）getget是一个函数，表示该属性的取值函数（getter），默认为undefined。（6）setset是一个函数，表示该属性的存值函数（setter），默认为undefined。Object.getOwnPropertyDescriptor()Object.getOwnPropertyDescriptor()方法可以获取属性描述对象。它的第一个参数是目标对象，第二个参数是一个字符串，对应目标对象的某个属性名。var obj = { p: 'a' }; Object.getOwnPropertyDescriptor(obj, 'p') // Object { value: "a", // writable: true, // enumerable: true, // configurable: true // }上面代码中，Object.getOwnPropertyDescriptor()方法获取obj.p的属性描述对象。注意，Object.getOwnPropertyDescriptor()方法只能用于对象自身的属性，不能用于继承的属性。var obj = { p: 'a' }; Object.getOwnPropertyDescriptor(obj, 'toString') // undefined上面代码中，toString是obj对象继承的属性，Object.getOwnPropertyDescriptor()无法获取。Object.getOwnPropertyNames()Object.getOwnPropertyNames方法返回一个数组，成员是参数对象自身的全部属性的属性名，不管该属性是否可遍历。var obj = Object.defineProperties({}, { p1: { value: 1, enumerable: true }, p2: { value: 2, enumerable: false } }); Object.getOwnPropertyNames(obj) // ["p1", "p2"]上面代码中，obj.p1是可遍历的，obj.p2是不可遍历的。Object.getOwnPropertyNames会将它们都返回。这跟Object.keys的行为不同，Object.keys只返回对象自身的可遍历属性的全部属性名。Object.keys([]) // [] Object.getOwnPropertyNames([]) // [ 'length' ] Object.keys(Object.prototype) // [] Object.getOwnPropertyNames(Object.prototype) // ['hasOwnProperty', // 'valueOf', // 'constructor', // 'toLocaleString', // 'isPrototypeOf', // 'propertyIsEnumerable', // 'toString']上面代码中，数组自身的length属性是不可遍历的，Object.keys不会返回该属性。第二个例子的Object.prototype也是一个对象，所有实例对象都会继承它，它自身的属性都是不可遍历的。Object.definePr…