What is a type? Simply put, a type is to assign a certain meaning to a binary sequence in memory. For example, the binary sequence 0100 0000 0111 0000 0001 0101 0100 1011 1100 0110 1010 0111 1110 1111 1001 1110 is 4643234631018606494 if viewed as a 64-bit unsigned integer type. 54 rules for binary representation of floating point numbers (see Appendix 1) double precision The floating point type is 257.331.
Most computer languages use variables to store and represent data. Some languages specify a type for variables. This type cannot be changed throughout the program (whether at compile time or run time). In contrast, variables in JavaScript and some other languages can store any type, and they use untyped variables. Whether the variable type exists has nothing to do with syntax. For example, C# also provides variables of type var. However, the following statement will cause an error in C#:
var a=1;
a="string";
The reason is that C#'s var keyword only omits the variable type declaration, and automatically infers the variable type based on the initialization expression, so C#'s var variable still has a type. In JavaScript, you can assign any value to a specific variable at any time, so JavaScript variables are untyped.
According to the design method of computer language type system, it can be divided into two types: strong type and weak type. The difference between the two lies in whether implicit conversion between different types can be transparent to the user during calculation. From a user's perspective, if a language can implicitly convert all its types, then when its variables, expressions, etc. are involved in operations, even if the type is incorrect, they can still get the correct type through implicit conversion. To the user, it is as if all types can perform all operations, so such a language is called weakly typed. In contrast, there may not necessarily be implicit conversions between types in a strongly typed language (for example, C++ is a strongly typed language, but double and int can be converted to each other in C++, but a cast is required between double and any type of pointer. )
Types can help programmers write correct programs, and they act as constraints in the actual process of writing programs. The general rule is that the stronger the constraint, the less error-prone it is, but the more troublesome it is to write the program. Strongly typed languages with variables that have types have the strongest constraints, and the typical representative is C++. Weakly typed languages that have untyped variables have the weakest constraints, with JavaScript being the typical representative. In JavaScript, because constraints are relatively weak, this error is prone to occur:
var a =200;
var b="1";
var c= a + b;
You might expect c to be 201, but in fact it is "2001", an error that never occurs in strongly typed languages. However, precisely because JavaScript does not have these constraints, it can easily concatenate numeric and string types. Therefore, constraints and flexibility are always a set of features that need to be balanced for language designers.
A type is a constraint that works through type checking. In different languages, type checking works at different stages, which can be divided into compile-time checking and run-time checking. For interpreted languages like JavaScript, there are stages that are similar to the compilation process, namely lexical analysis and syntax analysis. If the type checking of interpreted languages is completed during syntax analysis or the previous stage, it can also be considered similar to compile-time checking. So a more reasonable statement is static type checking and dynamic type checking.
Interestingly, although many languages check types at compile time, their type information can still be obtained at runtime. For example, C# uses metadata to save type information. During the runtime, users can obtain and use types through reflection. information.
JavaScript prioritizes flexibility in every aspect of its design, so it uses dynamic type checking and does not actively check types except when performing very few specific operations. You can obtain the type information of any variable or expression at runtime and check its correctness through program logic.
There are 9 types specified in the JavaScript standard: Undefined Null Boolean String Number Object Reference List Completion
Among them, the three types of Reference List Completion are only used during language parsing runtime and cannot be directly accessed from the program. They will not be introduced here. Below we can learn about these six types:
The Undefined type has only one value, undefined, which is the value when the variable is not assigned a value. In JS, the global object has an undefined property that represents undefined. In fact, undefined is not a keyword in JavaScript. You can assign a value to the global undefined property to change its value. .
The Null type also has only one value, null, but JavaScript provides it with a keyword null to represent this unique value. The semantics of the Null type is "an empty object reference".
Boolean has two values: true and false
The formal interpretation of the String type is a sequence of 16-bit unsigned integer types, which is actually used to represent text information encoded in UTF-16.
JavaScript's Number has a total of 18437736874454810627 (that is, 264-253 +3) values. JavaScript's Number is stored in double-precision floating point type, except that 9007199254740990 represents NaN, which complies with IEEE 754 (see Appendix 1) and occupies 64 bits and 8 bytes.
The most complex type in JavaScript is Object, which is an unordered collection of a series of properties. Function is an Object that implements the private property [[call]]. The JavaScript host can also provide some special objects.
I talked about the types specified in the JS standard before. However, an issue that cannot be ignored is that the JS standard is written for JS implementers. For JS users, types do not necessarily have to be defined according to the standard. For example, because JS is When performing . operation, non-Object types will be automatically converted into corresponding objects, so "str".length is actually equivalent to (new String("str")).length. From this perspective, it is considered It’s not a bad idea for both to be of the same type. We use some language features in JS to perform runtime type discrimination, but the results of these methods are different. You need to decide which one is better or worse.
Typeof is an operator in JS language. From its literal point of view, it is obviously used to obtain the type. According to the JavaScript standard, typeof obtains the string representation of the variable type name. There are 6 possible results. : string, bool, number, undefined, object, function, and the JavaScript standard allows its implementers to customize the typeof value of some objects.
There is such a description list in the JS standard:
Type | Result |
Undefined | "undefined" |
Null | "object" |
Boolean | "boolean" |
Number | "number" |
String | "string" |
Object (native and doesn't implement [[call]]) | "object" |
Object (native and implements [[call]]) | "function" |
Object(host) | Implementation-dependent |
The following example comes from Rimifon of 51js, which shows the situation where the result of typeof in IE produces "date" and "unknown":
var xml=document.createElement("xml");
var rs=xml.recordset;
rs.Fields.Append("date", 7, 1);
rs.Fields.Append("bin", 205, 1);
rs.Open();
rs.AddNew();
rs.Fields.Item("date").Value = 0;
rs.Fields.Item("bin").Value = 21704;
rs.Update();
var date = rs.Fields.Item("date").Value;
var bin = rs.Fields.Item("bin").Value;
rs.Close();
alert(date);
alert(bin);
alert([typeof date, typeof bin]);
try{alert(date.getDate())}catch(err){alert(err.message)}
There are actually many criticisms about this judgment method that is closest to "type" semantics. One of them is that it cannot distinguish different objects. New String ("abc") and new Number (123) cannot be distinguished using typeof. Because In JS programming, a large number of various objects are often used, and typeof can only give a vague result "object" for all objects, which greatly reduces its practicality.
The meaning of instanceof is translated into Chinese as "is an instance of...". Literally understood, it is a term based on class-based object-oriented programming, and JS does not actually provide support for class-based programming at the language level. Although the JavaScript standard does not mention a word, in fact, the design of some built-in objects and operator settings all hint at an "official" way to implement classes, that is, from using functions as classes, when the new operator acts on the function, The prototype attribute of the function is set to the prototype of the newly constructed object, and the function itself is used as the constructor.
Therefore, objects constructed from the new operation of the same function are considered instances of a class. What these objects have in common is: 1. They have the same prototype and 2. They are processed by the same constructor. And instanceof is an operator that checks "whether an instance belongs to a class" in conjunction with this way of implementing a class. You can also guess that it is very difficult to check whether an object has been processed by a constructor, but it is much easier to check what its prototype is. Therefore, the implementation of instanceof is understood from the perspective of prototype, which is to check the [ [prototype]] attribute is consistent with the prototype of a specific function. Note that [[prototype]] here is a private property, which can be accessed using __proto__ in SpiderMonkey (which is Firefox's JS engine).
The prototype is only meaningful for the Object type described by the standard, so instanceof will get false for all non-Object objects, and instanceof can only determine whether it belongs to a certain type, but cannot get the type. However, the advantage of instanceof is also obvious. It can distinguish itself. An object constructed from a defined "class".
In fact, instanceof can be deceived. Although the private attribute [[prototype]] of the object it uses cannot be changed, the prototype of the function is a public attribute. The following code shows how to deceive instanceof.
function ClassA(){};
function ClassB(){};
var o = new ClassA();//Construct an object of class A
ClassB.prototype = ClassA.prototype; //Replace ClassB.prototype
alert(o instanceof ClassB)//true deception successful - -!
Object.prototype.toString is originally difficult to call. All JavaScript built-in classes cover the toString method. For objects constructed by non-built-in classes, Object.prototype.toString can only get the meaningless [object Object ] This kind of result. Therefore, for quite a long time, the magical effect of this function has not been discovered.
In the standard, the description of Object.prototype.toString is only 3 sentences
1. Get the [[class]] attribute of this object
2. Calculate a string by concatenating the three strings "[object ", result(1), and "]"
3. Return the result (2).
Obviously, Object.prototype.toString actually just gets the [[class]] attribute of the object, but I don’t know if it is intentional. All JS built-in function objects String Number Array RegExp... will all be used when using new to construct objects. Set the [[class]] attribute so that the [[class]] attribute can be used as a good basis for judging the type.
Because Object.prototype.toString takes the property of this object, you can specify this object and then get the type by using Object.prototype.toString.call or Object.prototype.toString.apply.
Although Object.prototype.toString is clever, it cannot obtain the type of object constructed by the custom function, because the custom function does not set [[class]], and this private property cannot be accessed in the program. The biggest advantage of Object.prototype.toString is that it can make 1 and new Number(1) the same type of object. Most of the time, the two are used in the same way.
However, it is worth noting that when new Boolean(false) participates in bool operations, the result is exactly the opposite of false. If the two are regarded as the same type at this time, it will easily lead to errors that are difficult to check.
In order to compare the above three types of judgment methods, I made a table so that everyone can have an overall comparison of several methods. In order to facilitate comparison, I have unified the results obtained by several judgment methods:
object | typeof | instanceof | Object.prototype.toString | standard |
"abc" | String | —— | String | String |
new String("abc") | Object | String | String | Object |
function hello(){} | Function | Function | Function | Object |
123 | Number | —— | Number | Number |
newNumber(123) | Object | Number | Number | Object |
new Array(1,2,3) | Object | Array | Array | Object |
newMyType() | Object | MyType | Object | Object |
null | Object | —— | Object | Null |
undefined | Undefined | —— | Object | Undefined |
In fact, it is difficult to say which of the above methods is more reasonable. Even the provisions in the standard only reflect the runtime mechanism of JS rather than the best usage practices. My personal opinion is to downplay the concept of "type" and focus more on the constraints of "how do I want to use this object". Using typeof and instanceof to check can achieve the same effect as a strongly typed language where needed.
sign bit: used to represent positive and negative signs
exponent: used to represent power numbers
mantissa (mantissa): used to indicate accuracy