Why can the basic type of string call methods directly

Here is Zhuo, who is suddenly diligent, and continues to update the documentation.

origin

When I was debugging the code on the console yesterday, I saw such a string of code.

let tool = {
    handleString (str) {
        return str.slice(0, 10)
    }
}

// 正常使用
tool.handleString('这里是Zhuoooo,点个关注不迷路~')
复制代码

string.png

At this time, I suddenly had a question, tool.handleStringin toolis an object, it can use .the operator to make a method call. However, strit is a basic type, so why can it be used like this? And it has always been used in this way, defining attribute types directly through literals, and there is no need to use newkeywords . The little head is filled with big doubts: does it also become an Stringobject ?

bujiandan.jpg

In fact, it also becomes an Stringobject .

string2.png

This behavior is also to make it more convenient to use. (Think about it, every time you use it, you have newto call it first, and then call it again when you get the value valueOf/ it toString's very troublesome.) Then, the characteristics of the language are not consistent with the behavior I think logically, indicating that It does something on its own behind the scenes.

It is output as a string, but has the behavior of an object when the .operator . Then, it may implicitly instantiate an Stringobject return the result of the calculation, and finally destroy the object.

bug? No, feature!

Later, I found the complete answer in Advanced Programming Language Design for JavaScript (4th Edition), see 5.3 Primitive Value Wrapper Types (page 113).

Original content:

为了方便操作原始值,ECMAScript 提供了3 种特殊的引用类型:Boolean、Number 和String。这些类型具有本章介绍的其他引用类型一样的特点,但也具有与各自原始类型对应的特殊行为。每当用到某个原始值的方法或属性时,后台都会创建一个相应原始包装类型的对象,从而暴露出操作原始值的各种方法。来看下面的例子:

let s1 = "some text";
let s2 = s1.substring(2);
复制代码

在这里,s1 是一个包含字符串的变量,它是一个原始值。第二行紧接着在s1 上调用了substring()方法,并把结果保存在s2 中。我们知道,原始值本身不是对象,因此逻辑上不应该有方法。而实际上这个例子又确实按照预期运行了。这是因为后台进行了很多处理,从而实现了上述操作。具体来说,当第二行访问s1 时,是以读模式访问的,也就是要从内存中读取变量保存的值。在以读模式访问字符串值的任何时候,后台都会执行以下3 步:

  1. 创建一个String 类型的实例;
  2. 调用实例上的特定方法;
  3. 销毁实例。

可以把这3 步想象成执行了如下3 行ECMAScript 代码:

let s1 = new String("some text");
let s2 = s1.substring(2);
s1 = null;
复制代码

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

let s1 = "some text";
s1.color = "red";
console.log(s1.color); // undefined
复制代码

s1The second line of code here attempts to add a colorproperty to the string . However, when the third line of code accesses the colorproperty, it is gone. The reason is that when the second line of code runs, an Stringobject is temporarily created, and when the third line of code executes, the object has been destroyed. In fact, the third line of code here creates its own Stringobject, but this object has no colorproperties. Primitive value wrapper objects can be created explicitly using the Boolean、Number 和Stringconstructor. However, this should be done only when it is really necessary, otherwise it is easy to confuse the developer, and it is not clear whether they are primitive values ​​or reference values. Calling on an instance of a primitive wrapper type typeofreturns "object", and all primitive wrapper objects are converted to booleans true. In addition, the Objectconstructor functions as a factory method, which can return an instance of the corresponding primitive value wrapper type according to the type of the passed value. for example:

let obj = new Object("some text");
console.log(obj instanceof String); // true
复制代码

If passed to Objectis a string, an Stringinstance of will be created. If numeric, Numberan instance of will be created. A boolean will get Booleanan instance of . **Note that using new to call a constructor of a primitive wrapped type is not the same as calling a cast function of the same name. **E.g:

let value = "25";
let number = Number(value); // 转型函数
console.log(typeof number); // "number"

let obj = new Number(value); // 构造函数
console.log(typeof obj); // "object"
复制代码

In this example, the variable numberholds a primitive value of 25, and the variable obj holds an Numberinstance of . Although explicitly creating instances of primitive value wrapper types is not recommended, they are important to the functionality of manipulating primitive values. Each primitive value wrapper type has a corresponding set of methods to facilitate data manipulation.

finally

This little knowledge may not be of much use to the actual coding. The author also thought it was interesting and thought of summarizing it. If you find it interesting, please give it a like. Thanks for watching~

end.gif

Guess you like

Origin juejin.im/post/7079677967529410596