js引擎处理基本类型值时背地里干的那些勾当

让我看先来看一段代码

    123.toString();

您觉得这行代码从词法分析的角度合理吗?


我们先来分析一下这条语句:

. 是js访问对象的属性或者方法时的运算符,所以这句语句的意思是123访问了它的toString方法并且通过函数调用运算符 () 调用了这个方法 , 表面看好像没毛病。没事 让我们在深入分析一下。先看下面代码

   //in操作符会在通过对象能够访问给定属性时返回true,无论该属性存在于实例中还是原型中
   console.log('toString' in 123);// Uncaught TypeError: Cannot use 'in' operator to search for 'toString' in 123

浏览器一运行上面的代码直接给报错了 为什么?因为123就是个数字值字面量,它本身是一个右值,并不是一个对象,它根本没有任何属性方法

    console.log(typeof 123); // number

既然不是对象那自然就不能通过 . 运算符去访问方法和属性了,所以123.toString(); 这行代码就是不合法不合理不合法的吗?让我们先来看下这行代码的运行结构在做定论吧!

console.log(25.toString()); // Uncaught SyntaxError: Invalid or unexpected token

浏览器真的报错了,但是我们换一种形式来一看看

  console.log((25).toString());  //25
  console.log(23.2.toString());  //23.2

一个数值可以为整数也可以为小数,123.toString(); 这样的写法会让js解析器认为你是写了一个不合法的小数而报错,换成这种写法浏览器又能正常解释执行了。那么这么一来上面的分析不就全错了吗?其实并不是,我们只是以我们能看到的东西进行分析,缺忽略了js引擎在解释这段代码的时候真正做了些什么事情。好吧,那让我们来看看js引擎这家伙背地里干了些肾摸事

js在解释(123).toString() 时后台进行了很多处理,从而实现了上述操作。具体来说,后台都会执行以下3步:
(1)创建一个临时的Number类型的实例对象。
(2)调用实例上的特定方法。
(3)销毁实例。
可以把这3步想象成执行了如下3行ECMAScript代码:

    let tmpObj=new Number(123);
    tmpObj.toString();
    tmpObj=null;

这种行为可以让原始值拥有对象的行为。对布尔值和字符串类型而言,以上3步也会在后台发生,只不过使用的是BooleanString包装类型而已。引用类型与原始值包装类型的主要区别在于对象的生命周期。在通过new实例化引用类型后,得到的实例会在离开作用域时被销毁,而自动创建的原始值包装对象则只存在于访问它的那行代码执行期间。这意味着不能在运行时给原始值添加属性和方法。比如下面的例子:

    let num=123;
    num.color="red";
    console.log(num.color);// undefined

这里的第二行代码尝试给数值num添加了一个color属性。可是,第三行代码访问color属性时,它却不见了。原因就是第二行代码运行时会临时创建一个Number对象,而当第三行代码执行时,这个对象已经被销毁了。实际上,第三行代码在这里创建了自己的Number对象,但这个对象没有color属性。

讲到这里就能把(123).toString();这种既合理又不合理的语法给解释通了.


你可能感兴趣的:(javascript)