什么是原生函数?就是为基本数据类型值提供了封装对象,就叫原生函数。这些函数为基本数据类型值提供了该子类型特有的方法和类型(我认为就类似于内置对象吧,只是这个是函数形式 )
常用的有这么几种:
◦ String()
◦ Number()
◦ Boolean()
◦ Array()
◦ Object()
◦ Function()
◦ RegExp()
◦ Date()
◦ Error()
◦ Symbol()
这些原生函数可以当成构造函数来使用,也可以对值进行类型转换
var str=String("2");
console.log(typeof str);//string
console.log(str instanceof String);//false
console.log(Object.prototype.toString.call(str));//[object String]
var num=Number("2");
console.log(typeof num);//number
console.log(num instanceof Number);//false
console.log(Object.prototype.toString.call(num));//[object Number]
//=============================
var str2=new String("2");
console.log(typeof str2);//object
console.log(str2 instanceof String);//true
console.log(Object.prototype.toString.call(str2));//[object String]
第一种使用方式会在下一篇进行详细讲述,这篇主要讲讲第二种方式,当成构造函数来使用
通过构造函数创建出来的是封装了基本类型值的封装对象
就是说new String("2")创建出来的是字符串"2",不是基本类型值"2"
所有typeof返回值为"object"(function这个特例也在内)的对象都会有一个内部属性[[class]],与创建该对象的内建原生构造函数大部分相对应
这个[[class]]没法直接访问,但是可以通过Object.prototype.toString.call()来查看
那么为什么说[[class]]与创建该对象的构造函数大部分相对应呢?就是null和undefined不同,因为没有Null()和Undefined()构造函数,但仍然指向了Null和Undefined
console.log(Object.prototype.toString.call(null));//[object Null]
console.log(Object.prototype.toString.call(undefined));//[object Undefined]
可能还会想,Object.prototype.toString.call()不是用来检测对象的吗?怎么能直接来检测基本类型值呢?
这就是“包装”了。在需要的时候,JS会自动给基本类型值包装一个对应的封装对象
所以当你执行下面这些语句时仍然会有效
console.log(Object.prototype.toString.call(true));//[object Boolean]
console.log(Object.prototype.toString.call(2));//[object Number]
console.log(Object.prototype.toString.call("odbc"));//[object String]
var str="abc";
console.log(str.length);//3
console.log(str.toUpperCase());//ABC
多数情况下我们并不需要自己去封装,直接使用基本类型值不好嘛,反正引擎会在需要的时候会自动包装。如果自己去手动包装反而有可能降低执行效率(有待验证)
如果非要自行封装基本类型值,可以使用Object()方法,会自动的将基本类型值包装为对应的封装对象
var str="abc";
var b=new String(str);
var c=Object(str);
console.log(typeof str);//string
console.log(typeof b);//object
console.log(typeof c);//object
console.log(str instanceof String);//false
console.log(b instanceof String);//true
console.log(c instanceof String);//true
console.log(Object.prototype.toString.call(str));//[object String]
console.log(Object.prototype.toString.call(b));//[object String]
console.log(Object.prototype.toString.call(c));//[object String]
有包装,肯定有拆封,这就是valueof()方法,可以直接获取封装对象中的基本类型值
var str=new String("abc");
var num=new Number(2);
var bol=new Boolean(false);
console.log(str.valueOf());//abc
console.log(num.valueOf());//2
console.log(bol.valueOf());//false
现在简单说说原生函数作为构造函数
Array()
貌似不带new也可以,效果一样
var arr=Array(1,2,3);
console.log(typeof arr);//object
console.log(arr instanceof Array);//true
对于这个构造函数,当只带一个数字参数时,这个参数会被设置为所创建数组的长度,这就有点容易误解了,因为这样创建出来的数组光有长度而没有内容
var arr=Array(6);
console.log(arr.length);//6
console.log(arr);
//在谷歌下输出arr
(6) [empty × 6]
//在火狐下输出arr
Array(6) [ undefined, undefined, undefined, undefined, undefined, undefined ]
//在eg下输出arr
[object Array]: [, , , , , ]
再来看看这个数组
var noarr=[undefined,undefined,undefined,undefined,undefined,undefined];
console.log(noarr.length);//6
console.log(noarr);
//在谷歌下输出noarr
(6) [undefined, undefined, undefined, undefined, undefined, undefined]
//在火狐下输出noarr
Array(6) [ undefined, undefined, undefined, undefined, undefined, undefined ]
//在eg下输出noarr
[object Array]: [undefined, undefined, undefined, undefined, undefined, undefined]
是不是有点相似,输出内容都很容易让人误解,更奇怪的是在火狐中居然输出相同?
再看看看这俩个数组的行为是不是有区别呢?
//这个例子在各个浏览器下输出都一致
console.log(arr.join("-"));//-----
console.log(noarr.join("-"));//-----
//这个例子在不同浏览器下输出有差异
console.log(arr.map( (el,index) => {
return index;
}));
//谷歌
(6) [empty × 6]
//火狐
Array(6) [ undefined, undefined, undefined, undefined, undefined, undefined ]
//eg
[object Array]: [, , , , , ]
console.log(noarr.map( (el,index) => {
return index;
}));
//都输出[0, 1, 2, 3, 4, 5]
可以看出这俩个数组在join()方法中表现一致,而在map()方法中又不同
其实,写这么多干嘛呢?不干嘛,凑字数,哈哈哈。就是想说,最好不要通过构造函数来创建空数组,容易误解,可以使用第二种数组来代替第一种数组,如果觉得第二种数组创建起来很麻烦,可以使用下面这种简写方式
var arr=Array.apply(null,{length:6});
console.log(arr);
//(6) [undefined, undefined, undefined, undefined, undefined, undefined]
为什么能这么写?看MDN文档的解释
从 ECMAScript 第5版开始,可以使用任何种类的类数组对象,就是说只要有一个
length 属性和(0..length-1)范围的整数属性。例如现在可以使用 NodeList
或一个自己定义的类似 {'length': 2, '0': 'eat', '1': 'bananas'}
形式的对象
好了,反正就是要尽量避免创建和使用空数组就行
Object() Function() RegExp()
对于这三个构造函数,能不使用就尽量不要使用,因为很麻烦。直接使用字面量方式来创建不是很好吗?简单又高效
当然,在动态设定函数参数和函数体的时候使用构造函数会很方便,使用动态定义正则表达式的时候也要使用构造函数方式
Date()和Error()
对于这两个,只能当成构造函数来使用了。毕竟没有对应的常量形式来替代
对于Date(),参数可加可不加,加了就是返回参数所设置的日期,不加就返回当前日期
var time=new Date();
console.log(time);
//Fri Oct 25 2019 13:38:59 GMT+0800 (中国标准时间)
还有就是,也可以不带new关键字,返回值相同
而Error()带不带new关键字也都一样。创建一个错误对象。当运行时错误产生时,Error的实例对象会被抛出。Error对象也可用于用户自定义的异常的基础对象
目前,error对象只有俩个属性,一个是name,一个是message,还有一个Error.prototype.toString()方法
var err=new Error("it's here");
console.log(err.name);//Error
console.log(err.message);//it's here
console.log(err.toString());//Error: it's here
Symbol()
这里先简单讲讲,后面会有专门介绍
不能使用new关键字来创建,否则会报错
每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符,这是该数据类型仅有的目的
可以传入参数来自定义符号
var sym=Symbol();
var sym1=Symbol("a");
var sym2=Symbol("a");
console.log(sym);//Symbol()
console.log(sym.toString());//Symbol()
console.log(typeof sym);//symbol
console.log(Object.prototype.toString.call(sym));//[object Symbol]
console.log(sym1);//Symbol(a)
console.log(sym2);//Symbol(a)
console.log(sym1 === sym2);//false
emmmm,其实这一篇我也不晓得讲了点什么
就知道了基本类型值会在需要的时候被引擎包装一个对应的封装对象
如何包装和拆封对象
也简单了解了几个函数的使用
没了