美文网首页
你不知道的JS(中卷)第三章

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

作者: Chasingcar_501 | 来源:发表于2018-12-03 22:37 被阅读0次

    第三章 原生函数

    内建函数又叫原生函数,如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引擎会自动对该值进行封装(用相应类型的封装对象来包装它)来实现对这些属性和方法的访问。

    相关文章

      网友评论

          本文标题:你不知道的JS(中卷)第三章

          本文链接:https://www.haomeiwen.com/subject/ofgtpftx.html