《你不知道的Javascript--中卷 学习总结》(原生函数、强制类型转换)

本文深入探讨JavaScript中的类型转换,包括常见的原生函数、强制类型转换、字符串与数字间的转换、布尔值转换及特殊类型的处理。文章详细解释了类型转换的规则,如ToNumber、ToString、ToBoolean,并讨论了在不同场景下类型转换的应用,如相等比较、算术运算等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原生函数

1、常见的原生函数有:

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol() --- ES6中新加入的

2、所有typeof返回值为"object"的对象(如数组)都包含一个内部属性[Class]。我们可以通过Object.prototype.toString()来查看。(对象的内部[[Class]]属性和创建该对象的内建原生构造函数相对应)

    Object.prototype.toString.call([1,2,3]) // "[object Array]"
    
    Object.prototype.toString.call(null) // "[object Null]"
    
    Object.prototype.toString.call(undefined) // "[object Undefined]"
复制代码

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

    var a = "abc";
    var b = new String(a);
    var c = Object(a);
    
    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]"
复制代码

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

    var a = new String('abc');
    var b = new Number(42);
    var c = new Boolean(true);
    var d = a + ""; // 隐式拆封
    a.valueOf() // "abc"
    b.valueOf() // 42
    c.valueOf(); // true
    
    typeof d // "string"
复制代码

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

    var a = new Array(1,2,3)
    
    a // [1,2,3]
复制代码

6、我们将包含至少一个"空单元"的数组称为稀疏数组

7、创建数组的不同的方式会有所区别

    var a = new Array(3);
    var b = [undefined,undefined,undefined]
    
    a.join("-"); // "--"
    b.join("-"); // "--"
    
    a.map(function(v,i){return i});  // [undefined * 3]
    b.map(function(v,i){return i});  // [0,1,2]
    
    
    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;
    }
复制代码

8、new Object() 可以创建对象,但是无法像常量形式那样一次设定多个属性。new Function() 比如动态定义函数参数函数体的时候可以创建函数。 new RegExp() 可以动态定义正则表达式

    var c = new Object();
    
    var e = new Function("a","return a*2;") // 相当于var f = function(a){return a * 2}
    
    var name = 'xxx'
    var namePattern = new RegExp("\\b(?:"+name+")+\\b","ig");
    
    var matches = someText.match(namePattern)
    
复制代码

9、Symbol

  • 符号是具有唯一性的特殊值(并非绝对),用它来命名对象属性不容易导致重名。
  • ES6中有一些预定义符号,以Symbol的静态属性形式出现,如Symbol.createSymbol.iterator
    // 可以自定义对象的迭代器,for..of可以遍历值
    obj[Symbol.iterator] = function(){}
复制代码
    var mysym = Symbol('symbol')
    mysym // Symbol(symbol)
    mysym.toString() //"Symbol(symbol)"
    typeof mysym // "symbol"
    
    var a = {}
    a[mysym] = 'foobar'
    
    Object.getOwnPropertySymbols(a) // [Symbol(symbol)]
复制代码

强制类型转换

值类型转换

1、将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况;隐式的情况称为强制类型转换

2、Javascript中的强制类型转换总是返回标量基本类型值,如字符串、数字和布尔值,不会返回对象和函数。

3、类型转换发生在静态类型语言的编译阶段,而强制类型转换发生在动态类型语言的运行时(runtime)

ToString

1、抽象操作ToString,它负责处理非字符串到字符串的强制类型转换。null转换为"null",undefined转换为"undefined",true转换为"true"。

2、对普通对象来说,除非自行定义,否则toString()返回内部属性[[class]]的值,如"[object Object]"

3、如果对象有自己的toString()方法,字符串化时就会调用该方法并使用其返回值。

4、数组的默认toString()方法经过了重新定义,将所有单元字符串化以后在用,连接起来

    var a = [1,2,3]
    
    a.toString(); // "1,2,3"
复制代码
JSON字符串化

1、JSON字符串化(JSON.stringify)并非严格意义上的强制类型转换。安全的JSON值都可以使用JSON.stringify字符串化。安全的JSON值是指能够呈现为有效的JSON格式的值。

2、不安全的JSON值:

  • undefined
  • symbol
  • function
  • 包含循环引用(对象之间相互引用,形成一个无限循环)的对象。

3、JSON.stringify()在对象中遇到undefined、function和symbol时会自动将其忽略。在数组中则会返回null(以保证单元位置不变)。对包含循环引用的对象执行JSON.stringify()会出错。

    JSON.stringify(undefined);// undefined
    JSON.stringify(function(){}); // undefined
    JSON.stringify([1,undefined,function(){},4]) // "[1,null,null,4]"
    JSON.stringify({a:2,b:function(){}}) // "{"a":2}"
复制代码

4、如果对象中定义了toJSON()方法,JSON字符串化时会首先调用该方法,然后用它的返回值来进行序列化。(如果含有非法JSON值的对象做字符串化,或者对象中的某些值无法序列化时,就需要定义toJSON()方法来返回一个安全的JSON值

    var o = {}
    var a = {
        b:41,
        c:o,
        d:function(){}
    }
    
    // 循环引用
    o.e = a;
    
    JSON.stringify(a) // 产生错误
    
    a.toJSON = function(){
        // 序列化仅包含b
        return {b:this.b}
    }
    
    JSON.stringify(a) // "{"b":42}"
复制代码

5、toJSON() 返回的应该是一个适当的值,可以是任何类型,然后在由JSON.stringify()对其进行字符串化。(也就是说返回一个能够被字符串化的安全的JSON值,而不是返回一个JSON字符串

    var a = {
        val:[1,2,3],
        toJSON:function(){
            return this.val.slice(1);    
        }
    }
    
    JSON.stringify(a); // "[2,3]"
复制代码

6、可以向JSON.stringify()传递一个可选参数replacer,它可以是数组或者函数。用来指定对象序列化过程中哪些属性应该会处理,哪些应该被排除,和toJSON很像。

  • 如果replacer是一个数组,它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称
  • 如果replacer是一个函数,它会对对象本身调用一次,然后对对象中的每个属各调用一次,每次传递两个参数,。如果要忽略某个键就返回undefined,否则返回指定的值。
    var a = {
        b:42,
        c:"42",
        d:[1,2,3]
    }
    JSON.stringify(a,["b","c"]) // "["b":42,"c":"42"]"
    
    JSON.stringify(a,function(k,v){
        if(k!=="c") return v
    })
    // "{"b":42,"d":[1,2,3]}"
复制代码
  • JSON.stringify还有一个可选参数space(第三个参数),用来指定输出的缩进格式。space为正整数时是指定每一级缩进的字符数,还可以是字符串,此时最前面的十个字符被用于每一级的缩进。(感觉没啥大用)
ToNumber

1、true转换为1,false转换为0。undefined转换为NaN,Null转换为0。

2、对象(包含数组)转换为基本的类型值,会按照如下规则:

  • 检查该值是否有valueOf的方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。
  • 如果没有的话就使用toString的返回值(如果存在)来进行强制类型转换。
  • 如果上面两个均不返回基本类型值,会产生TypeError错误。

3、使用Object.create(null)创建的对象[[Prototype]]属性为null,并且没有valueOf和toString方法,因此无法进行强制类型转换

ToBoolean

1、以下这些是假值:

  • undefined
  • null
  • false
  • +0、-0和NaN
  • ""

2、假值对象(了解以下吧)

document.all

显示强制类型转换

字符串和数字之间的转换

1、字符串=>数字

  • Number()
  • +(一元运算符)

2、数字=>字符串

  • String()
  • toString()
    var a = 42;
    var b = a.toString()
    
    var c = "3.14"
    var d = +c;
    
    b // "42"
    d // 3.14
复制代码

3、一元运算符+的另一个常见用途是将日期(Date)对象强制类型转换为数字,返回结果为Unix时间戳,以毫秒为单位。

    var d = +new Date()
    d // 1560354322864
    
    // 别的方式获取时间戳
    
    var timestamp = new Date().getTime()
    
    // Date.now
    if(!Date.now){
        Date.now = function(){
            return +new Date();
        }
    }
复制代码
~运算符(非)
  • ~x == -(x+1) (记住这一个就行了)
  • 使用场景,if(~a.indexOf(..)),如果if判断的结果为false,证明不存在,否则就是存在。
显示解析数字字符串

1、parseInt解析允许字符串中含有非数字字符,解析从左到右的顺序,如果遇到非数字字符就停止。而转换不允许出现非数字字符,否则会失败并返回NaN。(解析浮点数可以使用parseFloat())

    var a = "42"
    var b = "42px"
    Number(a) // 42
    parseInt(b) // 42
复制代码

2、早期版本的parseInt()有一个问题,如果没有第二个参数来指定的基数,parseInt会根据字符串的第一个字符来自行决定基数。如果第一个字符是x或X,则转换为十六进制数字。如果是0,则转换为八进制数字。(注意ES5之后默认转换为十进制数。如果第二个参数不传或者false值,按照十进制处理。)

显示转换为布尔值

1、一元运算符 ! 显式地将值强制类型转换为布尔值。但是它同时还将 真值反转为假值(或者将假值反转为真值)。所以显式强制类型转换为布尔值最常用的方法是 !!,因为第二个 ! 会将结果反转回原值。

隐式强制类型转换

字符串和数字之间的隐式强制类型转换

1、根据 ES5 规范 11.6.1节,如果某个操作数是字符串或者能够通过以下步骤转换为字符串 的话,+ 将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用 ToPrimitive 抽象操作(规范 9.1 节),该抽象操作再调用 [[DefaultValue]](规范 8.12.8 节),以数字作为上下文。 2、如果 + 的其中一个操作数是字符串(或者通过以上步骤可以得到字符串), 则执行字符串拼接;否则执行数字加法。

     var a = [1,2];
     var b = [3,4];
    a + b; // "1,23,4"
复制代码

3、我们可以将数字空字符串 ""相 + 来将其转换为字符串

    var a = 42;
    var b = a + "";
    b; // "42"
复制代码

4、a + ""(隐式)和前面的String(a)(显式)之间有一个细微的差别需要注意。根据 ToPrimitive抽象操作规则,a + ""会对a调用valueOf()方法,然后通过ToString抽象 操作将返回值转换为字符串。而 String(a) 则是直接调用 ToString()

     var a = {
         valueOf: function() { return 42; },
         toString: function() { return 4; }
     };
     a + "";         // "42"
     String( a );    // "4"
复制代码

5、-是数字减法运算符,因此a - 0会将a强制类型转换为数字。也可以使用a * 1和a / 1。

    var a = "3.14";
    var b = a - 0;
    b; // 3.14
    
    var a = [3];
    var b = [1];
    a - b; // 2
复制代码
布尔值到数字的隐式强制类型转换

1、可以使用!!来将值转换为布尔值,再通过 Number(..) 显式强制类型转换为 0 或 1。

隐式强制类型转换为布尔值

1、下面的情况会发生 布尔值隐式强制类型转换:

  • if (..)语句中的条件判断表达式。
  • for ( .. ; .. ; .. )语句中的条件判断表达式(第二个)。
  • while (..) 和 do..while(..) 循环中的条件判断表达式。
  • ? :中的条件判断表达式。
  • 逻辑运算符 ||(逻辑或)和 &&(逻辑与)左边的操作数(作为条件判断表达式)。
|| 和 &&

1、&& 和 || 运算符的返回值并不一定是布尔类型,而是两个操作数其中一个的值。 2、使用|| 和 &&注意以下几点:

  • || 和 && 首先会对第一个操作数(a 和 c)执行条件判断,如果其不是布尔值(如上例)就 先进行 ToBoolean 强制类型转换,然后再执行条件判断。
  • 对于 || 来说,如果条件判断结果为 true 就返回第一个操作数(a 和 c)的值,如果为 false 就返回第二个操作数(b)的值。
  • && 则相反,如果条件判断结果为 true 就返回第二个操作数(b)的值,如果为 false 就返 回第一个操作数(a 和 c)的值。
     var a = 42;
     var b = "abc";
     var c = null;
    a || b; a && b;
    c || b; c && b;
    // 42
    // "abc"
    // "abc"
    // null
复制代码
符号的强制类型转换

1、ES6 允许 从符号到字符串的显式强制类型转换,然而隐式强制类型转换会产生错误。 2、符号不能够被强制类型转换为数字(显式和隐式都会产生错误),但可以被强制类型转换 为布尔值(显式和隐式结果都是 true)

    var s1 = Symbol( "cool" );
    String( s1 );     // "Symbol(cool)"
    var s2 = Symbol( "not cool" );
    s2 + "";      // TypeError
复制代码

宽松相等和严格相等

1、常见的误区是“== 检查值是否相等,=== 检查值和类型是否相等”。正确的解释是:“== 允许在相等比较中进行强制类型转换,而 === 不允许。”

抽象相等(挺重要的!!)

1、字符串数字之间的相等比较

ES5 规范 11.9.3.4-5 这样定义:

  • 如果 Type(x) 是数字,Type(y) 是字符串,则返回 x == ToNumber(y) 的结果。
  • 如果 Type(x) 是字符串,Type(y) 是数字,则返回 ToNumber(x) == y 的结果。
    var a = 42;
    var b = "42";
    a === b;    // false  不进行强制类型转换比较
    a == b;     // true   进行强制转换后进行比较
复制代码

2、其他类型和布尔类型之间的相等比较

ES5 规范 11.9.3.6-7 这样定义:

  • 如果 Type(x) 是布尔类型,则返回 ToNumber(x) == y 的结果。
  • 如果 Type(y) 是布尔类型,则返回 x == ToNumber(y) 的结果。
    var a = "42";
    var b = true;
    a == b; // false
复制代码

3、null 和 undefined 之间的相等比较

ES5 规范 11.9.3.2-3 这样定义:

  • 如果 x 为 null,y 为 undefined,则结果为 true。
  • 如果 x 为 undefined,y 为 null,则结果为 true。

在 == 中 null 和 undefined 相等(它们也与其自身相等),除此之外其他值都不存在这种 情况

    var a = null;
     var b;
     a == b;     // true
     a == null;  // true
     b == null;  // true
     
     a == false; // false
     b == false; // false
     a == ""; // false
    b == "";// false
    a == 0;// false
    b == 0;// false
    
复制代码

4、对象和非对象之间的相等比较

ES5 规范 11.9.3.8-9 这样定义:

  • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == ToPrimitive(y) 的结果;
  • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 ToPromitive(x) == y 的结果。
    var a = 42;
    var b = [ 42 ];
    a == b; // true
    
    
    var a = 'abc'
    var b = Object(a)
    
    a===b // false
    a==b // true
复制代码

5、极端情况

    [] == ![] // true
复制代码

让我们看看 ! 运算符都做了些什么?根据 ToBoolean 规则,它会进行布尔 值的显式强制类型转换(同时反转奇偶校验位)。所以[] == ![]变成了[] == false。 []=>''=>0,而false=>0 ,所以两边自然就相等了。

抽象关系比较

ES5 规范 11.8.5 节定义:

  • “抽象关系比较”(abstract relational comparison),分为两个部 分:比较双方都是字符串(后半部分)和其他情况(前半部分)。

1、比较双方首先调用 ToPrimitive,如果结果出现非字符串,就根据 ToNumber 规则将双方强 制类型转换为数字来进行比较。(感觉这个有点问题)

    var a = [ 42 ];
    var b = [ "43" ];
    
    a < b;  // true
    b < a;  // false
复制代码

2、如果比较双方都是字符串,则按字母顺序来进行比较

     var a = [ "42" ];
     var b = [ "043" ];
    a < b; // false
复制代码

3、下面的例子有点奇怪

     var a = { b: 42 };
     var b = { b: 43 };
     a < b;  // false
     a == b; // false   对象比较 值不同直接是false
     a > b;  // false
     a <= b; // true
     a >= b; // true
复制代码

规范规定,<= 应该是“小于或者等于”。实际上 JavaScript 中 <= 是 “不大于”的意思(即 !(a > b),处理为 !(b < a))。同理 a >= b 处理为 b <= a

转载于:https://juejin.im/post/5cf92755f265da1b614fe8f0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值