你需要知道的 JavaScript 原生函数的内容

简介: 你需要知道的 JavaScript 原生函数的内容

常用原生函数:

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

原生函数可以被当作构造函数来使用,但其构造出来的对象可能会和我们设想的有所出入:

var str = new String('Hello');
typeof str; // 'object' 不是 'string'

str instanceof String; // true
Object.prototype.toString.call(str); // '[object String]'

通过构造函数(如 new String("abc") )创建出来的是封装了基本类型值(如 "Hello" )的封装对象。

内部属性 [[Class]]

所有 typeof 返回值为 "object" 的对象(如数组)都包含一个内部属性 [[Class]] (可以把它看作一个内部的分类,而非传统的面向对象意义上的类)。这个属性无法直接访问,一般通过 Object.prototype.toString() 来查看。

Object.prototype.toString.call([]); // '[object Array]'
Object.prototype.toString.call({}); // '[object Object]'
Object.prototype.toString.call(function(){}); // '[object Function]'
Object.prototype.toString.call(/\d+/); // '[object RegExp]'
Object.prototype.toString.call(new Date()); // '[object Date]'
Object.prototype.toString.call(new Error()); // '[object Error]'
Object.prototype.toString.call(Symbol()); // '[object Symbol]'

多数情况下,对象的内部 [[Class]] 属性和创建该对象的内建原生构造函数相对应,但并非总是如此。

// 虽然 Null() 和 Undefined() 这样的原生构造函数并不存在
// 但是内部 [[Class]] 属性值仍然是 "Null" 和"Undefined" 
Object.prototype.toString.call(null); // '[object Null]'
Object.prototype.toString.call(undefined); // '[object Undefined]'

封装对象包装

封装对象(object wrapper)扮演着十分重要的角色。由于基本类型值没有 .length.toString() 这样的属性和方法,需要通过封装对象才能访问,此时 JavaScript 会自动为基本类型值包装 (box 或者 wrap)一个封装对象:

var str = 'Hello';
str.length; // 5
str.toUpperCase(); // 'HELLO'

一般情况下,不需要直接使用封装对象。最好的办法是让 JavaScript 引擎自己决定什么时候应该使用封装对象。换句话说,就是应该优先考虑使用 "abc" 和 42 这样的基本类型值,而非 new String("abc")new Number(42)

需要注意的地方

为 false 创建了一个封装对象,然而该对象是真值。

var b = new Boolean(false);

if (!b) {
  console.log('false'); // 无法执行到这里
}

如果想要自行封装基本类型值,可以使用 Object() 函数(不带 new 关键字):

var a = 'abc';
var b = new String('abc');
var c = Object('abc');

typeof a; // 'string'
typeof b; // 'object'
typeof c; // 'object'

b instanceof String; // true
c instanceof String; // true

Object.prototype.toString.call(b); // '[object String]'
Object.prototype.toString.call(c); // '[object String]'

拆封

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

var a = new String('abc');
var b = new Number(123);
var c = new Boolean(true);

a.valueOf(); // 'abc'
b.valueOf(); // 123
c.valueOf(); // true

在需要用到封装对象中的基本类型值的地方会发生隐式拆封。

var a = new String('abc');
var b = a + ''; // 'abc'

typeof a; // 'object'
typeof b; // 'string'

原生函数作为构造函数

Array()

Array 构造函数只带一个数字参数的时候,该参数会被作为数组的预设长度(length),而非只充当数组中的一个元素。

数组并没有预设长度这个概念,这样创建出来的只是一个空数组,只不过它的 length 属性被设置成了指定的值。

var a = new Array(1, 2, 3);
a; // [1, 2, 3]

var b = [1, 2, 3];
b; // [1, 2, 3]

:::tip
构造函数 Array() 不要求必须带 new 关键字。不带时,它会被自动补上。
:::

Object()、Function() 和 RegExp()

除非万不得已,否则尽量不要使用 Object()Function()RegExp()

在实际情况中没有必要使用 new Object() 来创建对象,因为这样就无法像常量形式那样一次设定多个属性,而必须逐一设定。

构造函数 Function 只在极少数情况下很有用,比如动态定义函数参数和函数体的时候。不要把 Function() 当作 eval() 的替代品,基本上不会通过这种方式来定义函数。

建议使用常量形式(如 /^a*b+/g )来定义正则表达式,这样不仅语法简单,执行效率也更高,因为 JavaScript 引擎在代码执行前会对它们进行预编译和缓存。RegExp() 有时还是很有用的,比如动态定义正则表达式时:

var name = 'Kyle';
var namePattern = new RegExp('\\b(?:' + name + ')+\\b', 'ig');

var matches = someText.match(namePattern);

Date() 和 Error()

Date()Error() 的用处要大很多,因为没有对应的常量形式来作为它们的替代。

创建日期对象必须使用 new Date()Date() 可以带参数,用来指定日期和时间,而不带参数的话则使用当前的日期和时间。

构造函数 Error() (与 Array() 类似)带不带 new 关键字都可。

创建错误对象(error object)主要是为了获得当前运行栈的上下文(大部分 JavaScript 引擎通过只读属性 .stack 来访问)。栈上下文信息包括函数调用栈信息和产生错误的代码行号,以便于调试(debug)。

Symbol()

Symbol 是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。该类型的引入主要源于 ES6 的一些特殊构造,此外 Symbol 也可以自行定义。

Symbol 可以用作属性名,但无论是在代码还是开发控制台中都无法查看和访问它的值,只会显示为诸如 Symbol(Symbol.create) 这样的值。

可以使用 Symbol() 原生构造函数来自定义符号。但它比较特殊,不能带 new 关键字,否则会出错:

var s = Symbol('my symbol');
s; // Symbol(my symbol)
s.toString(); // 'Symbol(my symbol)'
typeof s; // 'symbol'

var a = {};
a[s] = 'value';

Object.getOwnPropertySymbols(a); // [Symbol(my symbol)]

原生类型

原生构造函数有自己的 .prototype 对象,如 Array.prototypeString.prototype 等。这些对象包含其对应子类型所特有的行为特征。

如,将字符串值封装为字符串对象之后,就能访问 String.prototype 中定义的方法。

相关文章
|
3月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
144 19
|
5月前
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索
|
7月前
|
JavaScript 前端开发
JavaWeb JavaScript ③ JS的流程控制和函数
通过本文的详细介绍,您可以深入理解JavaScript的流程控制和函数的使用,进而编写出高效、可维护的代码。
164 32
|
6月前
|
JavaScript 前端开发 Java
详解js柯里化原理及用法,探究柯里化在Redux Selector 的场景模拟、构建复杂的数据流管道、优化深度嵌套函数中的精妙应用
柯里化是一种强大的函数式编程技术,它通过将函数分解为单参数形式,实现了灵活性与可复用性的统一。无论是参数复用、延迟执行,还是函数组合,柯里化都为现代编程提供了极大的便利。 从 Redux 的选择器优化到复杂的数据流处理,再到深度嵌套的函数优化,柯里化在实际开发中展现出了非凡的价值。如果你希望编写更简洁、更优雅的代码,柯里化无疑是一个值得深入学习和实践的工具。从简单的实现到复杂的应用,希望这篇博客能为你揭开柯里化的奥秘,助力你的开发之旅! 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一
|
8月前
|
JavaScript 前端开发 测试技术
盘点原生JavaScript中直接触发事件的方式
本文全面探讨了原生JavaScript中触发事件的多种方式,包括`dispatchEvent`、`Event`构造函数、`CustomEvent`构造器、直接调用事件处理器以及过时的`createEvent`和`initEvent`方法。通过技术案例分析,如模拟点击事件、派发自定义数据加载事件和实现提示框系统,帮助开发者掌握这些方法在实际开发中的应用,提升灵活性与兼容性。
249 3
|
10月前
|
前端开发 JavaScript 开发者
除了 Generator 函数,还有哪些 JavaScript 异步编程解决方案?
【10月更文挑战第30天】开发者可以根据具体的项目情况选择合适的方式来处理异步操作,以实现高效、可读和易于维护的代码。
|
11月前
|
JavaScript 前端开发
JavaScript 函数语法
JavaScript 函数是使用 `function` 关键词定义的代码块,可在调用时执行特定任务。函数可以无参或带参,参数用于传递值并在函数内部使用。函数调用可在事件触发时进行,如用户点击按钮。JavaScript 对大小写敏感,函数名和关键词必须严格匹配。示例中展示了如何通过不同参数调用函数以生成不同的输出。
|
11月前
|
存储 JavaScript 前端开发
JS函数提升 变量提升
【10月更文挑战第6天】函数提升和变量提升是 JavaScript 语言的重要特性,但它们也可能带来一些困惑和潜在的问题。通过深入理解和掌握它们的原理和表现,开发者可以更好地编写和维护 JavaScript 代码,避免因不了解这些机制而导致的错误和不一致。同时,不断提高对执行上下文等相关概念的认识,将有助于提升对 JavaScript 语言的整体理解和运用能力。
|
11月前
|
JavaScript 前端开发
js教程——函数
js教程——函数
235 4
|
11月前
|
存储 JavaScript 前端开发
js中函数、方法、对象的区别
js中函数、方法、对象的区别
198 2