前言
在当今数字时代,前端技术正日益成为塑造用户体验的关键。我们在开发中需要用到很多js的内置对象的一些属性来帮助我们更快速的进行开发。或许你是刚踏入前端领域的小白,或者是希望深入了解内置对象的开发者,不论你的经验如何,本篇博客都将给你详细的讲解js的内置对象。
🚀 作者简介:程序员小豪,全栈工程师,热爱编程,曾就职于蔚来、腾讯,现就职于某互联网大厂,技术栈:Vue、React、Python、Java
🎈 本文收录于小豪的前端系列专栏,后续还会更新前端入门以及前端面试的一些相关文章,手把手带你从零学习前端到面试找工作,并如果有想进入前端领域工作的同学,这个前端专栏会对你有所帮助,欢迎关注起来呀
🌼 本人也会持续的去关注AIGC以及人工智能领域的一些动向并总结到博客中,大家感兴趣的可以关注一下我的人工智能专栏
🌊 云原生的入门学习系列,大家有兴趣的可以看一看
全局属性 Infinity 是一个数值,表示无穷大。
Infinity 属性的属性特性
属性特性 | 布尔值 |
---|---|
writable | false |
enumerable | false |
configurable | false |
Infinity 大于任何值。该值和数学意义上的无穷大很像,例如任何正值乘以 Infinity 为 Infinity ,任何数值(除了 Infinity和 -Infinity )除以 Infinity 为 0。
🌰 代码示例:
console.log(Infinity); // Infinity console.log(Infinity + 1); // Infinity console.log(Math.pow(10, 1000)); // Infinity console.log(Math.log(0)); // Infinity console.log(1 / Infinity); // 0
全局属性 NaN 的值表示不是一个数字(Not-A-Number)。
属性特性 | 布尔值 |
---|---|
writable | false |
enumerable | false |
configurable | false |
返回 NaN 的情况总结:
不可使用等号运算符来判断一个值是否为 NaN。必须采用 Number.isNaN() 或 isNaN()函数进行判断。
在执行自比较中,NaN 是唯一与自身不全等的值。
NaN === NaN; // false Number.NaN === NaN; // false isNaN(NaN); // true; isNaN(Number.NaN); // true; function valueIsNaN(v) { return v !== v; } valueIsNaN(1); // false valueIsNaN(NaN); // true valueIsNaN(Number.NaN); // true
使用 isNaN() 前先检查一下这个值是否是数字类型,即可避免隐式类型转换的问题。
function detectIsNaN(value) { return typeof value === 'number' && isNaN(value); }
undefined 属性是一个特殊值。如果已声明了一个变量但还未进行初始化,则其值为 undefined。
该属性为 Global 对象的一个只读属性(准确地说,是一个常量)。所有主流浏览器均支持该属性。
如果一个变量未被初始化赋值,则其值为 undefined。如果一个函数没有返回值,则其返回值默认为 undefined。
eval() 函数用于计算并执行以字符串表示的 JavaScript 代码。eval() 函数使 JavaScript 可以动态执行 JavaScript 源代码。
eval() 函数属于 Global 对象,所有主流浏览器均支持该函数。
eval(code);
参数 | 类型 | 说明 |
---|---|---|
code | String 类型 | 包含有效 JavaScript 代码的字符串 |
⚠️ 注意: 参数code必须是原始字符串,不能是 String 对象形式。如果参数 code 不是原始字符串,则 eval() 函数不会执行代码,并且将其不作任何改变地返回。
如果参数 code 中的 JavaScript 代码不合法,将会引发异常。
eval() 函数的返回值是任意类型,其返回值由参数 code 中具体的 JavaScript 代码决定。
let x = 2, y = 39, z = '42'; eval('x + y + 1'); // 42 eval(z); // 42
isNaN() 函数用于判断指定数字是否是非数字值 NaN。
该函数属于Global对象,所有主流浏览器均支持该函数。
isNaN(number);
参数 | 类型 | 说明 |
---|---|---|
number | Number 类型 | 指定的数值 |
⚠️ 注意: 如果参数 number 不是 Number 类型,则 isNaN() 函数会将其强制转换为 Number 类型再进行判断。大多数其他类型的值无法强制转换为 Number 类型,则其转换结果为 NaN,即 isNaN() 函数返回 true。
isNaN()
函数的返回值是 Boolean 类型。
isNaN(NaN); // true isNaN(undefined); // true isNaN({}); // true isNaN(true); // false isNaN(null); // false isNaN(37); // false // strings isNaN('37'); // false: 可以被转换成数值37 isNaN('37.37'); // false: 可以被转换成数值37.37 isNaN(''); // false: 空字符串被转换成0 isNaN(' '); // false: 包含空格的字符串被转换成0 // dates isNaN(new Date()); // false isNaN(new Date().toString()); // true isNaN('blabla'); // true: "blabla"不能转换成数值
parseFloat()函数用于将字符串转换为浮点数并返回。
该函数属于 Global 对象,所有主流浏览器均支持该函数。
parseFloat(numberString);
参数 | 类型 | 说明 |
---|---|---|
numberString | String 类型 | 需要转换为浮点数的字符串。 |
返回转换后的浮点数,
number
类型,
parseFloat('3.14'); parseFloat('314e-2'); parseFloat('0.0314E+2'); parseFloat('3.14more non-digit characters'); // all return 3.14
parseFloat('MDN'); // NaN parseFloat(null); // NaN parseFloat([]); // NaN parseFloat({}); // NaN
parseInt() 函数用于 将字符串转换为整数并返回。该函数可以将字符串视作指定的进制形式表示。
该函数属于 Global 对象,所有主流浏览器均支持该函数。
parseInt( numString [, radix ] )
参数 | 类型 | 说明 |
---|---|---|
numString | String 类型 | 需要转换为整数的字符串 |
radix | Number 类型 | 可选,指定的进制基数(介于 [2, 36] 之间的数值。) |
例如:参数 radix 为 2,则将 numString 视作二进制;参数 radix 为 8,则视作八进制;参数 radix 为 16,则视作十六进制。
如果没有提供 radix 参数,则 parseInt() 函数将会根据参数 numString 的前缀来决定转换的进制基数。如果 numString 的前缀是 0x,则转换为十六进制;如果前缀是 0,则转换为八进制;其他情况均转换为十进制。
// Binary parseInt('1111', 2); // Octal parseInt('17', 8); parseInt(021, 8); // Decimal parseInt('015', 10); parseInt(15.99, 10); parseInt('15,123', 10); parseInt('15 * 3', 10); parseInt('15e2', 10); parseInt('15px', 10); parseInt('12', 13); // Hexadecimal parseInt('0xF', 16); parseInt('F', 16); parseInt('FXX123', 16);
parseInt('Hello', 8); // not a number parseInt('546', 2); // except 0 & 1,other number are not valid binary numbers
decodeURI() 函数用于对已编码的统一资源标识符(URI)进行解码,并返回其非编码形式。
该函数属于 Global 对象,所有主流浏览器均支持该函数。
decodeURI(encodedURIString);
参数 | 类型 | 说明 |
---|---|---|
encodedURIString | String 类型 | 已编码的 URI 字符串 |
decodeURI() 函数的返回值是 string 类型,返回一个已经解码的 URI。
将已编码 URI 中所有能识别的转义序列转换成原字符,但不能解码那些不会被 encodeURI 编码的内容(例如 #)。
let a = 'Hello JavaScript!'; let b = encodeURI(a); console.log(b); // return '%E4%BD%A0%E5%A5%BDJavascript!' let c = decodeURI(b); // return '你好Javascript!'
encodeURI() 函数可把 URI 字符串采用 UTF-8 编码格式转化成 escape 格式的字符串。
该函数属于 Global 对象,所有主流浏览器均支持该函数。
encodeURI(URIString);
参数 | 类型 | 说明 |
---|---|---|
URIString | String 类型 | 需要编码的 URI 字符串 |
该方法返回一个已经编码的 URI 字符串。
如果要对使用 encodeURI() 函数编码的 URI 字符串进行解码,请使用 decodeURI() 函数。
encodeURI() 函数不编码字符有 82 个 !、#、$、'、(、)、*、+、,、-、.、/、:、;、=、?、@、_、~、0-9、a-z、A-Z 。
如果你只是想编码一个带有特殊字符(比如中文)的 URI,这个 URI 用作请求地址,请使用本函数。
如果你想把 URI 当作请求参数传递,那么你可以使用 encodeURIComponent() 函数。encodeURIComponent() 函数会编码所有的字符。
// 原URI var ftpUri = 'ftp://192.168.0.100/共享文件夹'; // 编码URI var encodedFtpUri = encodeURI(ftpUri); console.log(encodedFtpUri); // ftp://192.168.0.100/%E5%85%B1%E4%BA%AB%E6%96%87%E4%BB%B6%E5%A4%B9 // 解码URI var decodedFtpUri = decodeURI(encodedFtpUri); console.log(decodedFtpUri); // ftp://192.168.0.100/共享文件夹
JavaScript 中的 Object 对象,是 JavaScript 中所有对象的基类,也就是说 JavaScript 中的所有对象都是由 Object 对象衍生的。Object 对象主要用于将任意数据封装成对象形式。
对象也可看做是属性的无序集合,每个属性都是一个名值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。
构造函数
new Object([value]);
对象类型转换函数
Object([value]);
参数 | 说明 | 类型 |
---|---|---|
value | 可选参数,需要包装为对象的值 | any |
Object.assign() 方法用于将所有可枚举自有 Property 的值从一个或多个源对象拷贝到目标对象。
Object.assign(target, ...sources);
参数 | 说明 | 类型 |
---|---|---|
target | 目标对象 | object |
sources | 源对象 | object |
返回目标对象。
如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。
Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。
该方法使用源对象的 [[Get]] 和目标对象的 [[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含 getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用 Object.getOwnPropertyDescriptor和 Object.defineProperty 。
const a = { a: 1 }; const b = Object.assign({}, a); console.log(b); // { a: 1 }
Object.create() 方法用于创建指定对象为原型对象的新对象。
语法:
Object.create(o: object | null): any; Object.create(o: object | null, properties: PropertyDescriptorMap & ThisType): any;
类型声明拓展:
interface PropertyDescriptor { configurable?: boolean; enumerable?: boolean; value?: any; writable?: boolean; get?(): any; set?(v: any): void; } interface PropertyDescriptorMap { [s: string]: PropertyDescriptor; } interface ThisType{}
参数说明:
参数 | 说明 | 类型 |
---|---|---|
o | 新创建对象指向的原型对象 | object |
properties | 可选参数。添加到新创建对象的可枚举属性(即自身定义的属性,而不是原型链上的枚举属性) | object |
⚠️ 注意:
// Shape = Super Class function Shape() { this.x = 0; this.y = 0; } // Super Class Methods Shape.prototype.move = function () { this.x += x; this.y += y; console.log('Shap moved'); }; // Retangle - Sub Class function Retangle() { Shape.all(this); // call super constructor } // 子类继承父类 Retangle.prototype = Object.create(Shape.prototype); Retangle.prototype.constructor = Retangle; const rect = new Retangle(); console.log(rect instanceof Retangle); // true console.log(rect instanceof Shape); // true
Object.defineProperties() 方法用于为一个对象定义 Properties 和/或修改已有的 Properties 的 Attributes。
Object.defineProperties(O, Properties);
参数 | 说明 | 类型 |
---|---|---|
O | 添加或修改 Properties 的目标对象 | object |
Properties | 要定义其可枚举属性或修改的属性描述符的对象 | object |
Attributes | 默认值 |
---|---|
configurable | false |
enumerable | false |
value | undefined |
writable | false |
get | undefined |
set | undefined |
返回变更后的对象。
const abc = { a: 1, b: 2, c: 3 }; Object.defineProperties(abc, { a: { value: 'One', writable: false, enumerable: false, configurable: false, }, e: { value: 4, }, f: { value: 5, }, }); console.log(abc); // { // b: "Two", // c: 3, // a: "One", // d: "Three", // e: 4, // f: 5, // } abc.a = 10; console.log(abc.a); // 'One'
Object.defineProperty() 方法用于为一个对象定义一个自有 Property 和/或修改已有 Property 的 Attributes。
Object.defineProperty(O, P, Attributes);
参数 | 说明 | 类型 |
---|---|---|
O | 定义或修改 Property 的目标对象 | object |
P | 需要定义的 Property 键名 | string |
Attributes | 被定义或修改的 Attributes | object |
返回变更后的对象。
const foo = {}; Object.defineProperty(foo, 'a', { value: 100, writable: true, enumerable: true, configurable: true }) console.log(foo); // { a: 100 } const bar; // 添加属性和存取描述符 Object.defineProperty(foo, 'b', { get: function(){ return foo }, set: function(newValue){ bar = newValue }, enumerable: true, configurable: true, }) foo.b = 99; console.log(foo.b); // 99
遍历劫持对象的所有属性
const data = { a: 'a', b: 'b', c: 'c' }; // 遍历对象,对其属性值进行劫持 Object.keys(data).forEach(function(key) { Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function() { console.log('GET') }, set: function(value) { // 当属性值发生变化时我们可以进行额外操作 console.log('SET') } }) })
⭐️ ES2017(ES8)新特性
Object.entries() 方法用于枚举指定对象并返回以键值对组成的数组为元素的二维数组。
语法:
Object.entries(obj);
类型声明:
interface ObjectConstructor { values(o: { [s: string]: T } | ArrayLike ): T[]; values(o: {}): any[]; }
参数说明:
参数 | 说明 | 类型 |
---|---|---|
obj | 用于枚举的对象 | object |
返回值:
返回给定对象自身可枚举 Property 的键值对数组。
给定对象自身可枚举属性的键值对数组,其排列与使用 for-in循环遍历该对象时返回的顺序一致,区别在于 for-in 循环也枚举原型链中的属性。
const a = { foo: 1, bar: 2 }; Object.entries(a); // [['foo', 1], ['bar', 2]] Object.entries('foo'); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ] const obj = { a: 5, b: 7, c: 9 }; for (const [key, value] of Object.entries(obj)) { console.log(`${key} ${value}`); // "a 5", "b 7", "c 9" } Object.entries(obj).forEach(([key, value]) => { console.log(`${key} ${value}`); // "a 5", "b 7", "c 9" });
⭐️ ES2017(ES8)新特性
Object.entries() 方法用于枚举指定对象并返回以键值对组成的数组为元素的二维数组。
语法:
Object.entries(obj);
类型声明:
interface ObjectConstructor { values(o: { [s: string]: T } | ArrayLike ): T[]; values(o: {}): any[]; }
参数说明:
参数 | 说明 | 类型 |
---|---|---|
obj | 用于枚举的对象 | object |
返回值:
返回给定对象自身可枚举 Property 的键值对数组。
给定对象自身可枚举属性的键值对数组,其排列与使用 for-in循环遍历该对象时返回的顺序一致,区别在于 for-in 循环也枚举原型链中的属性。
const a = { foo: 1, bar: 2 }; Object.entries(a); // [['foo', 1], ['bar', 2]] Object.entries('foo'); // [ ['0', 'f'], ['1', 'o'], ['2', 'o'] ] const obj = { a: 5, b: 7, c: 9 }; for (const [key, value] of Object.entries(obj)) { console.log(`${key} ${value}`); // "a 5", "b 7", "c 9" } Object.entries(obj).forEach(([key, value]) => { console.log(`${key} ${value}`); // "a 5", "b 7", "c 9" });
Object.getOwnPropertyDescriptor() 方法可以获取对象自有 Property 的某个 Attributes。
Object.getOwnPropertyDescriptor(O, Property);
参数 | 说明 | 类型 |
---|---|---|
O | 需要查找的目标对象 | object |
Property | 目标对象的 Property | string |
const foo = { a: 1 }; Object.getOwnPropertyDescriptor(foo, 'a'); // Object { // value: "a", // writable: true, // enumerable: true, // configurable: true, // }
⭐️ ES2017(ES8)新特性
Object.getOwnPropertyDescriptors() 方法用于获取一个对象的所有自身 Property 的 Attributes。
语法:
Object.getOwnPropertyDescriptors(obj);
类型声明:
interface ObjectConstructor { getOwnPropertyDescriptors( o: T ): { [P in keyof T]: TypedPropertyDescriptor } & { [x: string]: PropertyDescriptor }; } interface TypedPropertyDescriptor { enumerable?: boolean; configurable?: boolean; writable?: boolean; value?: T; get?: () => T; set?: (value: T) => void; } interface PropertyDescriptor { configurable?: boolean; enumerable?: boolean; value?: any; writable?: boolean; get?(): any; set?(v: any): void; }
参数说明:
参数 | 说明 | 类型 |
---|---|---|
obj | 用于获取 Property 的 Attributes 的对象 | object |
const a = { name: 'Ben', get age() { return '18'; }, }; Object.getOwnPropertyDescriptors(a);
Object.getPrototypeOf() 方法用于获取指定对象的原型(内部 [[Prototype]] 属性的值)。
Object.getPrototypeOf(O);
参数 | 说明 | 类型 |
---|---|---|
O | 目标对象 | object |
返回目标对象的原型对象。
const proto = {}; const foo = Object.create(proto); Object.getPrototypeOf(foo) === proto; // true const reg = /a/; Object.getPrototypeOf(reg) === Regexp.prototype; // true
const foo = new Object(); Object.getPropertyOf(Object); // f () { [native code] } Object.getPropertyOf(Function); // f () { [native code] } Object.getPropertyOf(Object) === Function.prototype; // true const bar = new Object(); Object.prototype === Object.getPrototypeOf(bar); // true Obejct.prototype === Object.getPrototypeOf({}); // true
Object.is() 方法用于判断两个值是否是相同的值。
Object.is(value1, value2);
参数 | 说明 | 类型 |
---|---|---|
value1 | 比较值 1 | any |
value2 | 比较值 2 | any |
返回判断表达式的结果。
判断下列任何一项成立,则两个值相同:
这种相等性判断逻辑和传统的 == 运算不同,== 运算符会对它两边的操作数做隐式类型转换,然后才进行相等性比较,(所以才会有类似 "" == false 等于 true 的现象),但 Object.is 不会做这种类型转换。
这与 === 运算符的判定方式也不一样。=== 运算符(和 == 运算符)将数字值 -0 和 +0 视为相等,并认为 Number.NaN 不等于 NaN。
Object.is(undefined, undefined); // true Object.is(null, null); // true Object.is(true, true); // true Object.is(100, 100); // true Object.is('foo', 'bar'); // false Object.is([], []); // false Object.is(0, -0); // false Object.is(-0, -0); // true Object.is(NaN, 0 / 0); // true
Object.keys() 方法用于获取指定对象自身可枚举 Property 组成的键名数组。
Object.keys(O);
参数 | 说明 | 类型 |
---|---|---|
O | 指定对象 | object |
返回对象所有可枚举 Property 的键名组成的数组。
获取到的数组中键名顺序与使用 for 系列循环语句获取到的键名顺序一致。
const foo = ['a', 'b', 'c']; console.log(Object.keys(foo)); // console: ['0', '1', '2']
const foo = { 0: 'a', 1: 'b', 2: 'c' }; console.log(Object.keys(foo)); // console: ['0', '1', '2']
// getBar is a property which isn't enumerable const foo = Object.create( {}, { getBar: { value: function() { return this.bar; }, }, } ); foo.bar = 1; console.log(Object.keys(foo)); // ['bar']
Object.setPrototypeOf() 方法用于设置一个指定的对象的原型 ( 即,内部 [[Prototype]] 属性)到另一个对象或 null。
Object.setPrototypeOf(O, proto);
参数 | 说明 | 类型 |
---|---|---|
O | 要设置其原型的对象 | object |
proto | 原型对象 | object |
返回设置原型后的对象。
const foo = Object.setPrototypeOf({}, null);
if (!Object.setPrototypeOf) { Object.setPrototypeOf = function() {}; }
⭐️ ES2017(ES8)新特性
Object.values() 方法用于指定对象自身的所有可枚举 Property 值的数组。
语法:
Object.values(obj);
类型声明:
interface ObjectConstructor { values(o: { [s: string]: T } | ArrayLike ): T[]; values(o: {}): any[]; }
参数说明:
参数 | 说明 | 类型 |
---|---|---|
obj | 指定对象 | object |
返回对象可枚举 Property 值的数组集合。
返回的数组中键值的顺序与使用循环语句获取的键值组合一致。
const obj = { a: '1', b: '2', c: '3', }; console.log(Object.values(obj)); // ['1', '2', '3']
Object.prototype.hasOwnProperty 方法用于检测指定对象自有 Properties 中是否具有指定的 Property。
O.prototype.hasOwnProperty(V);
参数 | 说明 | 类型 |
---|---|---|
V | 需要检测的 Property 字符串名称或者 Symbol | string/symbol |
返回该对象是否含有指定 Property 的 Boolean 值。
所有继承了 Object 的对象都会继承到 hasOwnProperty 方法。
这个方法可以用来检测一个对象是否含有特定的自身属性;和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
const foo = new Object(); foo.a = 'exist'; function change() { foo.b = foo.a; delete foo.a; } foo.hasOwnProperty('a'); // true change(); foo.hasOwnProperty('b'); // false
const foo = new Object(); foo.a = 'Hello world!'; foo.hasOwnProperty('a'); // true foo.hasOwnProperty('toString'); // false foo.hasOwnProperty('hasOwnProperty'); // false
Object.prototype.isPrototypeOf() 方法用于测试指定对象是否存在于目标对象的原型链上。
O.prototype.isPrototypeOf(V);
参数 | 说明 | 类型 |
---|---|---|
V | 目标对象(在该对象原型链上搜寻) | object |
返回指定对象是否位于目标对象原型链上的 Boolean 类型值。
function Foo() {} function Bar() {} function Baz() {} Bar.prototype = Object.create(Foo.prototype); Baz.prototype = Object.create(Bar.prototype); const baz = new Baz(); console.log(Baz.prototype.isPrototypeOf(baz)); // true console.log(Bar.prototype.isPrototypeOf(baz)); // true console.log(Foo.prototype.isPrototypeOf(baz)); // true console.log(Object.prototype.isPrototypeOf(baz)); // true
Object.prototype.prototypeIsEnumerable() 方法用于检测指定 Property 是否可枚举。
O.prototype.prototypeIsEnumerable(V);
参数 | 说明 | 类型 |
---|---|---|
V | 需要检测的 Property 键名 | string |
返回表示指定 Property 键名是否可枚举的 Boolean 类型值。
const foo = {}; const bar = []; foo.a = 'is enumerable'; bar[0] = 'is enumerable'; foo.propertyIsEnumerable('a'); // true bar.propertyIsEnumerable(0); // true
原型链上 的 Properties 不被 propertyIsEnumerable 考虑。
const a = []; a.propertyIsEnumerable('constructor'); function b() { this.property = 'b'; } b.prototype.firstMethod = function() {}; function c() { this.method = function method() { return 'c'; }; } c.prototype = new b(); c.prototype.constructor = c; const d = new c(); d.arbitraryProperty = 'd'; d.prototypeIsEnumerable('arbitraryProperty'); // true d.prototypeIsEnumerable('method'); // true d.prototypeIsEnumerable('property'); // false d.property = 'd'; d.prototypeIsEnumerable('property'); // true
Object.prototype.toString() 方法用于表示指定对象的字符串。
O.prototype.toString();
表示该对象的字符串。
所有经过标准内置对象创建的值均能通过 toString() 方法获取 String 类型值。
const foo = new Object(); foo.toString(); // [object Object]
需要使用 Function.prototype.call() 和 Function.prototype.apply() 的形式调用,输入需要检测的对象作为第一参数。
const toString = Object.prototype.toString(); toString.call(new Date()); // [object Date] toString.call(new String()); // [object String] toString.call(Math); // [object Math] // Since JavaScript 1.8.5 toString.call(undefined); // [object Undefined] toString.call(null); // [object Null]
Object.isExtensible() 方法用于检测指定对象是否可扩展。
Object.isExtensible(O);
参数 | 说明 | 类型 |
---|---|---|
O | 指定用于检测的对象 | object |
返回 Boolean 类型的值表示用于检测的对象是否可扩展。
默认情况下,对象是可扩展的:即可以为他们添加新的属性。
Object.preventExtensions、Object.seal或 Object.freeze方法都可以标记一个对象为不可扩展(non-extensible)。
let foo = { a: 1, }; console.log(Object.isExtensible(foo)); // true foo.b = 2; console.log(foo); // {a: 1, b: 2} console.log(Object.preventExtensions(foo)); // { a: 1, b: 2} // 由于对象 foo 禁止扩展,所以该赋值语句静默失败 foo.c = 3; console.log(Object.isExtensible(foo)); // false console.log(foo); // { a: 1, b: 2}
Function 构造函数通过 new 创建一个新的 Function 对象。 在 JavaScript 中,每个函数实际上都是一个 Function 对象。
构造函数
new Function ( [ argName1 [, argName1 [, argNameN... [, funcBody ]]]] )
函数类型转换函数
Function ( [ argName1 [, argName1 [, argNameN... [, funcBody ]]]] )
参数 | 说明 | 类型 |
---|---|---|
argName1 | 定义的第 1 个参数的名称 | string |
argName2 | 定义的第 2 个参数的名称 | string |
argNameN | 定义的第 N 个参数的名称,可以有任意多个 | string |
funcBody | 定义的函数主体,即函数内部的执行代码,默认为空字符串("") | string |
Function() 会把传入的最后一个参数作为函数定义的执行代码,之前的所有参数均依次作为函数定义的参数。
Function() 的返回值是 Function 类型,返回一个函数对象。
Function.prototype.apply 方法用于指定函数调用指向的 this 指针,并提供类数组类型的参数列表作为指定函数的参数。
语法:
apply(thisArg: any, argArray?: any): any;
参数:
参数 | 说明 | 类型 |
---|---|---|
thisArg | 可选参数。调用函数时指向的 this 指针。 | / |
argArray | 可选参数。调用函数参数列表。 | Array | TypedArray |
Function.prototype.apply 与 Function.prototype.call 非常相似,不同之处在于提供参数的方式,apply 使用参数数组而非一组参数列表。
你可以使用 arguments 对象作为 argArray 参数。arguments 是一个函数的局部变量,它可以被用作被调用对象的所有未指定的参数。这样,你在使用 apply 方法时就不需要知道被调用的对象的所有参数。你可以使用 arguments 来把所有的参数传递给被调用对象。 被调用对象接下来就负责处理这些参数。
使用 Array.prototype.push能将元素追加到数组中,并且,该方法可以接受可变数量的参数。
但是如果,我们需要传递一个数组追加到数组中,它实际上会将该数组作为单个元素添加,而不是单独添加元素,因此我们最终得到一个数组内的数组。
这种情况下,虽然可以通过 Array.prototype.concat实现我们想要的行为,但它实际上不是附加到原有数组中,而是创建并返回新的数组。
而我们可以通过 Function.prototype.apply 实现该需求。
const foo = []; const bar = [1, 2, 3, 4]; foo.push.apply(foo, bar); console.log(foo); // [1, 2, 3, 4]
可以使用 Function.prototype.apply 实现本来需要遍历数组变量的任务中使用内建的的函数。
以下例子使用 Math.max 和 Math.min 来找出一个数组中的最大 / 最小值。
const foo = [2, 4, 6, 8, 10]; const max = Math.max.apply(null, foo); const min = Math.min.apply(null, foo);
⚠️ 注意:使用上述方式调用 Function.prototype.apply,会有超出 JavaScript 引擎的参数长度限制的风险。当对一个函数传入非常多的参数(比如一万个)时,就非常有可能会导致越界问题,这个临界值是根据不同的 JavaScript 引擎而定的(JavaScript 核心中已经做了硬编码 参数个数限制在 65536),因为这个限制(实际上也是任何用到超大栈空间的行为的自然表现)是未指定的,有些引擎会抛出异常。更糟糕的是其他引擎会直接限制传入到方法的参数个数,导致参数丢失。
如果参数数组可能很大,可以使用以下策略处理:将参数数组切块后循环传入目标方法。
function minOfArray(arr) { var min = Infinity; var QUANTUM = 32768; for (var i = 0, len = arr.length; i < len; i += QUANTUM) { var submin = Math.min.apply(null, arr.slice(i, Math.min(i + QUANTUM, len))); min = Math.min(submin, min); } return min; } var min = minOfArray([5, 6, 2, 3, 7]);
Function.prototype.call 方法用于指定函数调用指向的 this 指针,并分别提供参数作为指定函数的参数。
语法:
call(thisArg: any, ...argArray: any[]): any;
参数
参数 | 说明 | 类型 |
---|---|---|
thisArg | 可选参数。调用函数时指向的 this 指针。 | |
args | 可选参数。调用函数参数列表。 |
function Product(name, price) { this.name = name; this.price = price; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } function Toy(name, price) { Product.call(this, name, price); this.category = 'toy'; } const cheese = new Food('cheese', 5); const robot = new Toy('robot', 40); console.log(cheese); // { // category: "food", // name: "cheese", // price: 5, // } console.log(robot); // { // category: "toy", // name: "robot", // price: 40, // }
Function.prototype.bind 方法创建一个新函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用。
语法:
bind(thisArg: any, ...argArray: any[]): any;
参数
参数 | 说明 | 类型 |
---|---|---|
thisArg | 可选参数。调用函数时指向的 this 指针。 | / |
arg1,arg2,… | 可选参数。当目标函数被调用时,被预置入绑定函数的参数列表中的参数。 | any |
Function.prototype.bind 函数会创建一个新 绑定函数(Bound Function,BF)。绑定函数是一个 Exotic Function Object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行 包装函数。
绑定函数具有以下内部属性:
当调用绑定函数时,它调用 [[BoundTargetFunction]] 上的内部方法 [[Call]],就像这样 Call(boundThis, args)。其中,boundThis 是 [[BoundThis]],args 是 [[BoundArguments]] 加上通过函数调用传入的参数列表。
绑定函数也可以使用 new 运算符构造,它会表现为目标函数已经被构建完毕。提供的 this 值会被忽略,但前置参数仍会提供给模拟函数。
Function.prototype.bind() 最简单的用法是创建一个函数,不论怎么调用,这个函数都有同样的 this 引用。JavaScript 新手经常犯的一个错误是将一个方法从对象中拿出来,然后再调用,期望方法中的 this 是原来的对象(比如在回调中传入这个方法)。如果不做特殊处理的话,一般会丢失原来的对象。基于这个函数,用原始的对象创建一个绑定函数,巧妙地解决了这个问题。
this.a = '100'; const foo = { a: '99', getA: function () { return this.a; }, }; foo.getA(); // '99' const retrieveA = foo.getA; retrieveA(); // '100' const boundGetA = retrieveA.bind(foo); boundGetA(); // '99'
Function.prototype.bind() 方法的另一个最简单的用法是使一个函数拥有预设的初始参数。只要将这些参数(如果有的话)作为 bind() 的参数写在 this 后面。当绑定函数被调用时,这些参数会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们后面。
const foo = function (a, b, c, d, e, f) { console.log(a, b, c, d, e, f); }; // 预设三个参数 1 2 3 -> 对应 foo 参数 a b c const bar = foo.bind(null, 1, 2, 3); bar(4, 5, 6); // 1 2 3 4 5 6
默认情况下,使用 window.setTimeout 时,this 关键字会指向 Window 对象。当类的方法中需要 this 指向类的实例时,你可能需要显式地把 this 绑定到回调函数,就不会丢失该实例的引用。
function LaterBloomer() { this.petalCount = Math.ceil(Math.random() * 12) + 1; } LaterBloomer.prototype.bloom = function () { window.setTimeout(this.declare.bind(this), 1000); }; LateBloomer.prototype.declare = function () { console.log('I am a beautiful flower with ' + this.petalCount + ' petals!'); }; const flower = new LateBloomer(); flower.bloom();
String 对象是一个用于 字符串 或一个 字符序列 的构造函数。
String 对象是文本字符串的对象形式。String 对象允许操作和格式化文本字符串以及确定和定位字符串中的子字符串。
构造函数
new String([value]);
字符串类型转换函数
String([value]);
参数 | 类型 | 说明 |
---|---|---|
value | 任意类型 | 任何可以被转换成字符串的值。 |
从 ECMAScript 2015 开始,字符串字面量也可以称为 模板字面量:
const w = 'world'`Hello ${w}!`;
静态 String.fromCharCode() 方法返回由指定的 UTF-16 代码单元序列创建的字符串。
String.fromCharCode(num1 [, num2 [, num3 ...[, numN]]]);
参数:
String.fromCharCode(65, 66, 67); // ABC String.fromCharCode(0x2014); // -
charAt() 方法从一个字符串中返回指定的字符。
str.charAt(index);
参数 | 说明 | 类型 |
---|---|---|
index | 一个介于 0 和字符串长度减 1 之间的整数。 (0~length-1)。如果没有提供索引,默认值为 0。 | number |
字符串中的字符从左向右索引:
const javascript = 'JAVASCRIPT'; javascript.charAt(); // J javascript.charAt(0); // J javascript.charAt(1); // A javascript.charAt(2); // V javascript.charAt(3); // A javascript.charAt(4); // S javascript.charAt(5); // C javascript.charAt(6); // R javascript.charAt(7); // I javascript.charAt(8); // P javascript.charAt(9); // T javascript.charAt(100); // ''
charCodeAt() 方法返回 0 到 65535 之间的整数,表示给定索引处的 UTF-16 代码单元(在 Unicode 编码单元表示一个单一的 UTF-16 编码单元的情况下,UTF-16 编码单元匹配 Unicode 编码单元。但在——例如 Unicode 编码单元 > 0x10000 的这种——不能被一个 UTF-16 编码单元单独表示的情况下,只能匹配 Unicode 代理对的第一个编码单元) 。如果你想要整个代码点的值,使用 codePointAt()。
str.charCodeAt(index);
参数 | 说明 | 类型 |
---|---|---|
index | 一个大于等于 0,小于字符串长度的整数。如果不是一个数值,则默认为 0。 | number |
返回值表示字符串对象指定索引处的字符的 Unicode 编码;如果索引超出范围,则返回 NaN。
Unicode 编码单元(code points)的范围从 0 到 1114111(0x10FFFF)。开头的 128 个 Unicode 编码单元和 ASCII 字符编码一样。
⚠️ 注意,charCodeAt 总是返回一个小于 65536 的值。这是因为高位编码单元(higher code point)使用一对(低位编码(lower valued))代理伪字符(“surrogate” pseudo-characters)来表示,从而构成一个真正的字符。因此,为了查看或复制(reproduce)65536 及以上编码字符的完整字符,需要在获取 charCodeAt(i) 的值的同时获取 charCodeAt(i+1) 的值,或者改为获取 codePointAt(i) 的值。
如果指定的 index 小于 0 或不小于字符串的长度,则 charCodeAt 返回 NaN。
下例介绍了不同索引情况下返回的 Unicode 值:
'ABC'.charCodeAt(0); // 65 'ABC'.charCodeAt(1); // 66 'ABC'.charCodeAt(2); // 67 'ABC'.charCodeAt(3); // NaN
concat() 函数用于将当前字符串与指定字符串进行拼接,并返回拼接后的字符串。
str.concat( string2, string3 [, ..., stringN] )
参数 | 说明 | 类型 |
---|---|---|
str2...strN | 和原字符串连接的多个字符串。 | string |
concat() 函数的返回值为 String 类型,其返回值为拼接后的字符串。
concat() 函数的作用等同于运算符 +,例如:str.concat(str1, str2) 等同于 str + str1 + str2。
concat 方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。 concat 方法并不影响原字符串。
下面的例子演示如何将多个字符串与原字符串合并为一个新字符串
var hello = 'Hello, '; hello.concat('Kevin', ' have a nice day.'); // Hello, Kevin have a nice day.
建议使用赋值操作符(+ 或 +=)代替字符串的 concat 方法。
var hello = 'Hello, '; hello += 'world'; console.log(hello); // Hello, world
endsWith() 用来判断当前字符串是否是以另外一个给定的子字符串 结尾 的,根据判断结果返回 true 或 false。
str.endsWith( searchString [, length] )
参数 | 说明 | 类型 |
---|---|---|
searchString | 要搜索的子字符串 | string |
length | 作为 str 的长度 | number |
这个方法帮助你确定一个字符串是否在另一个字符串的末尾。这个方法是大小写敏感的。
concat 方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回。 concat 方法并不影响原字符串。
const str = 'Hello world!'; console.log(str.endsWith('world!')); // true console.log(str.endsWith('abc')); // false
includes() 方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。
str.includes( searchString [, startIndex] )
参数 | 说明 | 类型 |
---|---|---|
searchString | 要在字符串中搜索的字符串 | string |
startIndex | 从当前字符串指定索引位置开发搜索子字符串,默认为 0,包含该索引 | number |
这个方法可以帮你判断一个字符串是否包含另外一个字符串。
这个方法搜索匹配的字符串是区分大小写的。
var str = 'To be, or not to be, that is the question.'; console.log(str.includes('To be')); // true console.log(str.includes('question')); // true console.log(str.includes('nonexistent')); // false console.log(str.includes('To be', 1)); // false console.log(str.includes('TO BE')); // false
indexOf() 函数用于查找子字符串在当前字符串中第一次出现的位置。
str.indexOf( searchValue[, startIndex])
参数 | 说明 | 类型 |
---|---|---|
searchValue | 需要查找的子字符串。 | string |
startIndex | 可选,在当前字符串中查找的起始索引,默认为 0。 | number |
indexOf() 方法的返回值为 Number 类型,返回子字符串在当前字符串中第一次查找到的起始位置(索引)。
字符串中的字符被从左向右索引。首字符的索引(index)为 0,字符串 stringName 的最后一个字符的索引是 stringName.length - 1。
'Blue Whale'.indexOf('Blue'); // 0 'Blue Whale'.indexOf('Blute'); // -1 'Blue Whale'.indexOf('Whale', 0); // 5 'Blue Whale'.indexOf('Whale', 5); // 5 'Blue Whale'.indexOf('', 9); // 9 'Blue Whale'.indexOf('', 10); // 10 'Blue Whale'.indexOf('', 11); // 10
下例定义了两个字符串变量。
两个变量包含相同的字符串,除了第二个字符串中的某些字符为大写。第一个 log 方法输出 19。但是由于 indexOf 方法 区分大小写,因此不会在 myCapString 中发现字符串 “cheddar",结果第二个 log 方法输出 -1。
var myString = 'brie, pepper jack, cheddar'; var myCapString = 'Brie, Pepper Jack, Cheddar'; console.log('myString.indexOf("cheddar") is ' + myString.indexOf('cheddar')); // 19 console.log('myCapString.indexOf("cheddar") is ' + myCapString.indexOf('cheddar')); // -1
使用 indexOf 统计一个字符串中某个字母出现的次数
在下例中,设置了 count 来记录字母 e 在字符串 str 中出现的次数:
let str = 'To be, or not to be, that is the question.'; let count = 0; let cur = str.indexOf('e'); // 当 cur 为 -1 时表示,字符串中已无检索子字符串 while (cur !== -1) { count++; cur = str.indexOf('e', cur + 1); } console.log(count); // displays 4
当检测某个字符串是否存在于另一个字符串中时,可使用下面的方法:
'Blue Whale'.indexOf('Blue') !== -1; // true 'Blue Whale'.indexOf('Bloe') !== -1; // false
match()函数用于使用指定的正则表达式模式在当前字符串中进行匹配查找,并返回数组形式的查找结果。
str.match(regexp);
参数 | 说明 | 类型 |
---|---|---|
regexp | 包含正则表达式模式的 RegExp 对象的实例。也可以是包含正则表达式模式的变量名或字符串。 | RegExo |
💡 如果参数 regExp 不是正则表达式对象(RegExp),而是字符串类型,则 match() 先将该字符串传递给 RegExp 的构造函数,将其转换为一个 RegExp 对象。
match()方法的返回值为 Array 类型,其返回数组的成员取决于指定的正则表达式模式是否设有全局标志 g。
在 IE 6 ~ IE 8 中,该数组还具有额外的 lastIndex 属性,用于存储匹配文本最后一个字符的下一个位置。
如果参数regExp设有全局标志g,则match()函数会查找所有的匹配,返回的数组不再有index和input属性,其中的数组元素就是所有匹配到的子字符串,形如:
match() 函数如果没有查找到任何匹配,则返回 null。
在下例中,使用 match 查找 "Hello world!" 紧跟着 1 个或多个数值字符,再紧跟着一个小数点和数值字符 0 次或多次。正则表达式包含 i 标志,因此大小写会被忽略。
var str = 'Hello world!'; str.match(); // ["", index: 0, input: "Hello world!", groups: undefined] str.match(/\b\w/); // ["H", "w"] str.match(/\w(?=r)/g); // null str.match(/\w[^\w]/g); // ["o", "d!"]
下例展示了 match() 使用 global 和 ignore case 标志。A-E、a-e 的所有字母将会作为一个数组的元素返回。
var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; var regexp = /[A-E]/gi; var matchArray = str.match(regexp); console.log(matchArray); // ['A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e']
var str = 'Nothing will come of nothing.'; str.match(); // [""]
const isWeixin = function() { const ua = naviagtor.userAgent.toLowerCase(); if (ua.match(/MicroMessenger/i) === 'micromessenger') { return true } else { return false; } }
replace() 函数用于使用指定字符串替换当前字符串中匹配指定正则表达式模式的子字符串,并返回完成替换后的字符串。
str.replace(pattern, replacement);
参数 | 说明 | 类型 |
---|---|---|
pattern | 指定的正则表达式模式的 RegExp 对象的实例。也可以是字符串。 | string / RegExp |
replacement | 用于替换的字符串,或返回替换字符串的函数。 | string / function |
一个部分或全部匹配由替代模式所取代的新的字符串。
字符 | 描述 |
---|---|
$n | 假如第一个参数是 RegExp 对象,并且 n 是个小于 100 的非负整数,那么插入第 n 个括号匹配的字符串。 |
$& | 插入匹配的子串。 |
`$`` | 插入当前匹配的子串左边的内容。 |
$' | 插入当前匹配的子串右边的内容。 |
$$ | 插入一个 $。 |
在进行全局的搜索替换时,正则表达式需包含 g 标志。
你可以指定一个函数作为第二个参数。在这种情况下,当匹配执行后, 该函数就会执行。 函数的返回值作为替换字符串。(注意: 上面提到的特殊替换参数在这里不能被使用。) 另外要注意的是, 如果第一个参数是正则表达式, 并且其为全局匹配模式, 那么这个方法将被多次调用, 每次匹配都会被调用。
下面是该函数的参数: