你不知道的JS(中卷)第三章

第三章 原生函数

内建函数又叫原生函数,如String、Number、Boolean、Array、Object、Function

    var a = new String('abc);
    typeof a; // object  不是string
    a instanceof String;//true
    Object.prototype.toString.call(a);//[Object String]

使用new String(“a”)创建出来的是字符串“a”的封装对象,而非基本类型值

1.内部属性[[Class]]

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

 Object.prototype.toString.call([1,2,3]);// "[Object Array]"
 Object.prototype.toString.call(/regex-literal/i);//"[Object RegExp]"

基本类型
虽然诸如Null(0和Undefined()这样的原生构造函数函数并不存在,但是他们内部的[[class]]属性依然是“Null”和“Undefined”
其他基本类型(如字符串、数字和布尔值)情况有所不同,通常称为“包装”,基本类型值被各自的封装对象自动包装,他们内部[[class]]属性分别为“String”、“Number”、“Boolean”

 Object.prototype.toString.call(11);// "[Object Number]"
 Object.prototype.toString.call("21");// "[Object String]"
 Object.prototype.toString.call(true);// "[Object Boolean]"

总而言之:基本类型的[[class]]属性值为其自身,复杂数据类型的[[class]]属性值与创建该对象的内建原生构造函数相对应

2. 封装对象包装

封装对象扮演者非常重要的角色。由于基本类型值没有.length和.toString()这样的操作,需要通过封装对象才能访问,此时js会自动为基本类型包装一个封装对象:

var a = "abc";
a.length;// 3
a.toUpperCase();//"ABC"

一般情况下,我们不需要直接使用封装对象。最好的办法是让JS引擎自己决定什么时候应该封装对象。

3.拆封

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

var a = new String("a");
var b = new Number(22);
var c = new Boolean(true);
a.valueOf();//a
b.valueOf();//22
c.valueOf();//true

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

4.原生函数作为构造函数

关于数组、对象、函数和正则表达式,我们通常喜欢以常量的形式创建,实际上使用常量和使用构造函数的效果一样。应该尽量避免使用构造函数,否则会产生意想不到的结果
(1) Array
构造函数Array不要求必须带new关键字,不带时会被自动补上。
Array构造函数只带一个关键字时,该参数会被作为数组的预设长度,而非只充当数组中一个元素。数组并没有预设长度这个概念,这样创建出来的只是一个空数组,只不过他的length被设置成了指定的值。我们将包含至少一个“空单元”的数组叫做稀疏数组。

var a = new Array(3);
var b = [undefined,undefined,undefined];
var c = [];
c.length = 3
a;//[empty x 3]
b;//[undefined,undefined,undefined]
c;//[empty x 3]
a.join('-');//"--"
b.join('-');//"--"
a.map(function(v,i){return i});// [empty × 3]
b.map(function(v,i){return i});// [0, 1, 2]

上例中a,b的行为有时相同,有时不同。
a.map之所以失败因为数组中不存在任何单元,所以map无从遍历,join不一样.join的实现先假定数组不为空,然后通过length遍历其中元素,map不做这样的假定因此结果超出预期

function fakeJoin(arr,connector){
    var str = "";
    for(var i = 0;i < arr.length;i++){
        if(i > 0){
            str += connector;
        }
        if(arr[i] !== undefined){
            str += arr[i];
        }
    }
   // return str;
   console.log(str)
}
var a = [1,2,3];
fakeJoin(a,"-");

我们可以使用下述方式创建包含undefined单元的数组:

var a = Array.apply(null,{length:3});
a;// [undefined,undefined,undefined]
永远不要创建和使用空单元数组。

(2)Object(..)、Function(..)、RegExp(..)
除非万不得已,不要使用Object(..)、Function(..)、RegExp(..)创建对象
RegExp(..)有时还是很有用的,比如动态定义正则表达式。
(3)Date(..)和Error(..)
相比于其他原生构造函数,这两个的用处大得多,因为没有对应的常量形式作为他们的代替。
创建日期对象那个必须使用new Date(),可以带参数,用来指定日期和时间,不带参数使用当前日期和时间。
Date()主要用来获得当前时间戳,该值可以通过日期对象中的getTime()获得。ES5引入一个更简单的方法,Date.now()

(new Date.now()).getTime()与Date.now()效果相同

构造函数Error带不带new关键字都行。创建错误对象注意主要是为了获得运行栈的上下文,方便调试。
(4)Symbol
ES6的基本数据类型——符号(Symbol),具有唯一性的特殊值,用来命名对象不容易导致重名。
可以用Symbol()原生构造函数自定义符号。但是不能带new关键字

var sym = Symbol("my symbol");
sym;// Symbol(my symbol)
typrof(sym);//"symbol"

(5)原生原型
原生构造函数都有自己的.prototype对象,如Array.prototype、String prototype等。这些对象包含其对应子类型所特有的行为特征。例如将字符串值封装为字符串对象后,就能访问String.prototype中定义的方法。

根据文档规定String.prototype.XYZ简写为String#XYZ,对其他prototype也是如此。

  • String#indexOf(..)
    在字符串中找到子字符串的位置
  • String#charAt(..)
    获得字符串指定位置上的字符
  • String#substr(..)、String#substring(..)和String#slice(..)
    获得字符串的指定部分
  • String#toUpperCase()和String#toLowerCase()
    将字符串转换为大写或小写
  • String#trim()
    去掉字符串前后的空格,返回新的字符串。
    以上方法并不改变原字符串的值,而是返回一个新的字符串。
    其他构造函数的原型包含他们各自类型所特有的行为特征,比如Number#tofixed(..)(将数字转换为指定长度的整数字符串)和Array#concat(..)(合并数组)。所有的函数都可以调用Function.prototype中的apply(..)、call(..)、bind(..)。
typeof Function.prototype;//“function”
Function.prototype(); //空函数

我们甚至可以修改这些函数,不仅仅是增加属性。
Function.prototype是一个函数,RegExp.prototype是一个正则表达式,Array.prototype是一个数组。

js为基本数据类型提供了封装对象,成为原生函数(String、Number、Boolean等)。他们为基本数据类型值提供了该子类型所特有的方法和属性。
对于简单标量基本类型值,如“abc”,如果要访问length属性或String.prototype属性,js引擎会自动对该值进行封装(用相应类型的封装对象来包装它)来实现对这些属性和方法的访问。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容