原生函数
原生函数指的是JS
内置的一些函数,因为涉及的内容比较常见,相关资料很多,这里就不再重读赘述,所以本文只对该书作者描述内容做简单总结.
常见的原生函数
下面是一些常见的原生函数:
String()
Number()
Boolean()
Function()
Object()
Array()
Date()
RegExp()
Error()
Symbol()
不难发现他们好像对应了js中的一些数据类型
这些函数可以作为构造函数来调用,对于基本类型的数据而言,原生函数构造出一个封装了基本类型值的封装对象
const strObj = new String("abc")
typeof strObj // object
至于strObj
这个封装对象和基本类型值有什么区别,将在封装和拆封一节中说明
内部属性[[class]]
所有typeof
返回object
的对象都包含一个内部属性[[Class]]
,这个属性只能通过Object.prototype.toString()
来查看
Object.prototype.toString.call([1, 2, 3]) //[object Array]
Object.prototype.toString.call({a:1}) //[object Object]
有意思的是对基本数据类型使用这个方法,也能返回内部的[[Class]]
属性:
两个比较特殊的:Null和Undefined
Object.prototype.toString.call(null) //[object Null]
Object.prototype.toString.call(undefined) //[object Undefined]
虽然null和undefined对应的原生构造函数不存在但内部的[[Class]]属性值仍然是null和undefined
其他基本类型:
Object.prototype.toString.call("string") // [object String]
很奇怪,typeof对基本数据类型返回的并不是object,为什么还是能访问[[Class]]
属性呢?这是因为其类型被各自封装了一层,将在拆封和封装一节中详细说明
封装和拆封
先思考一个问题,对于基本类型值来说,自身是没有.length
,.toString
方法的,可是在我们日常使用中经常会通过基本类型值来直接访问其没有
的属性,如:
const str = 'abc'
console.log(str.length) // 3,即使str没有length属性,也同样能访问,这是为什么呢?
这是因为:
在访问属性之前,js会隐式的
通过其对应的原生函数将基本类型值包装成一个封装对象,可以这样理解:
1.const str = 'abc';
2.将str包装成封装对象: new String('abc'),str变成了这个对象
3.console.log(str.length) 这里就正常访问了
4.销毁掉封装对象
既然有封装,那么就会有拆封: 有时候我们想得到封装对象中的基本数据类型值,可以使用valueOf()
方法进行拆封:
const a = new String('abc');
console.log(a) // {0:'a',1:'b',2:'c',length:3}
console.log(a.valueOf()) // abc
在一些请情况下,js会隐式的进行拆封:
const a = new String('abc')
const b = a + ''
console.log(b) // abc
console.log(typeof a) //object
console.log(typeof b) //string
具体过程涉及js的强制类型转换,将在下一章节中详细讨论
原生函数or字面量
既然原生函数可以作为构造函数,那么在定义变量的时候,应该使用那种方式呢?其中Symbol
比较特殊,直接调用来生成符号,其他数据类型,除了Date,Error
之外,优先使用字面量的方式定义变量,可以避免很多误解,比如:
const bool = new Boolean(false)
if(!bool){ // 这里的代码永远都不会执行}
使用Boolean()封装了false之后,typeof bool返回object是一个真值,永远返回true