This is an infrastructure problem, a complete JavaScript includes: ECMAScript, Document Object Model (DOM), Browser Object Model (BOM), this chapter explains ECMAScript

ECMAScript specifies that the language consists of the following:

  1. grammar
  2. Variables and data types
  3. Keywords and reserved words
  4. operator
  5. statement
  6. object

That is to say, these six modules make up the language

Among these six pillars, "syntax", "variables" and "data types", "keywords" and "reserved words", "operators", and "statements" are all well understood, except for "objects". Complex, the next section will explain it, here we look at the "data type"

type of data

JavaScript data types are divided into "primitive types" and "reference types"

Primitive types are called differently in different books (tutorials), and they are also called primitive types/value types/primitive values/primitive types. Of course, reference types are also called differently, such as object types/complex types

Basic types include undefined, null, string, number, boolean, symbol (new in ES6), bigint (new in ES10)

The reference type is object (a collection of properties)

It is hereby stated that:

In "JavaScript Advanced Programming Fourth Edition", the data types are summarized as Undefined, Null, Boolean, Number, String, Symbol, BigInt, Object in camel case, and in the lowercase form in the website modern JavaScript tutorial and MDN Display the display data type, the author here is based on the website

The difference between primitive types and reference types

Primitive types are stored in stack memory

Reference types are stored in heap memory

Basic types cost less memory, so copy values

The memory cost of the reference type is large, so copy the reference address

类型存储

 // 案例1
var string1 = 'foo';
var string2 = string1;
string1 = 'bar';
console.log(string1, string2); // 输出 bar, foo

// 案例2
var object1 = {
    name: 'johan',
    age: 23,
};
var object2 = object1;
object1.name = 'elaine';
object2.age = 22;
console.log(object1, object2);
// 输出 { name: 'elaine', age: 22 } { name: 'elaine', age: 22 }

Because the basic type is stored in the stack memory, after string1 is assigned to string2, it is equivalent to opening an independent space for string2. String1 and string2 are two completely independent individuals, and what is assigned to string1 has nothing to do with string2.

The reason why the reference type is called a reference type (or complex type/complex value) is because the address of the object is a reference, Object can be nested all the time, Function can also be nested many layers (callback functions), Array can change tricks Make a three-dimensional array and the like, in short, the object value can be infinite. The larger the value, the more memory it occupies. If a large value is copied randomly, it will be a disaster for the user (it will occupy a large amount of memory unconsciously). So it is impossible to copy at will, but to use pointers to point the object to the same address (here can be derived to deep copy)

When you create an object1, you allocate a memory in the heap memory. If you assign a value to object2, you are actually copying the address that object1 points to the heap memory to object2, and they point to the same address. If you modify object1 or object2, it is equivalent to modifying the same memory. No matter whether object1 is modified or object2 is modified, it will change.

 var obj1 = {};
var obj2 = obj1;
obj1.name = 'elaine';
obj2.age = 23;
console.log(obj1); // { name: 'elaine', age: 22};
console.log(obj2); // { name: 'elaine', age: 22};
Derivative thinking: Although the dynamic nature of JavaScript is very convenient, if some newbie modifies the value of the object type without telling it, then it becomes a disaster. Because of the dynamic + global scope, the naming of all variables becomes a problem, so the general library uses IIFE, closure and other methods to break the situation, and then there is the concept of modularity (ES module), the essence of which is to solve the problem. Problems with variable naming, language dynamics

Knowing the data types of JavaScript is not enough, how to know each data type more accurately

There are four ways to determine the data type

  • use typeof
  • use instanceof
  • use constructor
  • Use Object.prototype.toString.call()

Type judgment

typeof operator

Role: Returns the basic type of the value being used

 // 基本类型/值类型/原始值/原始类型    
var null1 = null;
var undefined1 = undefined;
var string1 = 'foo';
var number1 = Number('10');
var boolean1 = Boolean('true');
var symbol1 = Symbol('foo');
console.log(typeof null1); // object, 需要注意
console.log(typeof undefined1); // undefined
console.log(typeof string1); // string
console.log(typeof number1); // number
console.log(typeof boolean1); // boolean
console.log(typeof symbol1); // symbol

// 引用类型/复杂值
var myString = new String('male');
var myNumber = new Number(23);
var myBoolean = new Boolean(false);
var myObject = new Object();
var myArray = new Array('foo', 'bar');
var myFunction = new Function('x', 'y', 'return x * y');
var myDate = new Date();
var myRegExp = new RegExp('\\bt[a-z]+\\b');
var myError = new Error('error');

console.log(typeof myString); // 输出 object
console.log(typeof myNumber); // 输出 object
console.log(typeof myBoolean); // 输出 object
console.log(typeof myObject); // 输出 object
console.log(typeof myArray); // 输出 object
console.log(typeof myFunction); // 输出 function 需要注意
console.log(typeof myDate); // 输出 object
console.log(typeof myRegExp); // 输出 object
console.log(typeof myError); // 输出 object
Tip: typeof xxx and typeof(xxx) have the same meaning

The typeof operator can determine the type of value used. Need to pay attention to the problem of judging reference types

  1. null type will return object
  2. new Function, which returns a function

By the way, this is also when we look at a lot of source code or write our own code, we often use typeof to judge the function type

 if (typeof XXX === 'function') {
    // 如果XXX是function的话做什么操作
}
PS: In Chapter 1, Section 8 of "JavaScript Revelation", it is said that the type of RegExp() returns a function, but the author found that it was not after inspection. The author guessed that because the old version of the browser judged RegExp as funtion, and The author uses the Chrome browser to indicate that the type of RegExp is object

instanceof operator

instanceof operator is used to detect whether the prototype property of the constructor appears on the prototype chain of an instance object

 function People(name, age) {
    this.name = name;
    this.age = age;
}

const elaine = new People('elaine', 23);
console.log(elaine instanceof People);
console.log(elaine instanceof Object);

The instanceof operator allows us to find out who its father is (who made it, biologically speaking, who is the mother), and its eighteenth generation ancestors, which are often encountered in interviews - the principle of instanceof is what

constructor constructor

constructor is a special method for creating and initializing objects created by class. Note that it is a function (method)

Like:

 function sayHello() {
    console.log('hello');
}

Don't mistake a word for an attribute just because it's unfamiliar

grammar:

 constructor([arguments]) { ... }

One more thing here, the React class component is written like this:

 class HelloWorld extends React.Component {
    constructor(props) {
        super(props);
    }
}

The meaning here is very clear, HelloWorld component inherits React.Component component, constructor(props) means calling the constructor of the parent class and passing props to HelloWorld, using super because in the derived class, you must call super to use this , of course, this part is related to the knowledge of the class, not listed here

What you need to know about the constructor (constructor) is that it is a method on the Object prototype, that is, Object.prototype.constructor. All objects will have a constructor attribute, which points to the constructor of the object. The subsequent articles about inheritance will explain

After the digression, let's continue to see constructor Can we check the data type?

 // 借 typeof 中的例子,直接打印看效果
// 基本类型
console.log(null1.constructor); // Cannot read properties of null (reading 'constructor')
console.log(undefined1.constructor); // Cannot read properties of null (reading 'constructor')
console.log(string1.constructor); // String() { [native code] }
console.log(number1.constructor); // Number() { [native code] }
console.log(boolean1.constructor); // Boolean() { [native code] }
console.log(symbol1.constructor); // Symbol() { [native code] }
// 引用类型
console.log(myString.constructor); // String() { [native code] }
console.log(myNumber.constructor); // Number() { [native code] }
console.log(myBoolean.constructor); // Boolean() { [native code] }
console.log(myObject.constructor); // Object() { [native code] }
console.log(myArray.constructor); // Array() { [native code] }
console.log(myFunction.constructor); // Function() { [native code] }
console.log(myDate.constructor); // Date() { [native code] }
console.log(myRegExp.constructor); // RegExp() { [native code] }
console.log(myError.constructor); // Error() { [native code] }

To sum up, constructor is invalid for undefined and null (because they are not objects and cannot inherit constructor properties from Object.prototype)

In addition, the pointer of constructor can be changed (because it is a property, the following example belongs to property assignment)

 function Person() {}
function Student() {}
Student.prototype = new Person();
var student = new Student();
console.log(student.constructor); // Person() {}

Specifically, we will introduce it in detail in the prototype article.

Object.prototype.toString.call(source)

toString() method returns a string representing the object

Each object has a toString() method (inherited from the ancestor of Object.prototype), which can really detect the type

 // 继续引用上述例子
// 基本类型
console.log(Object.prototype.toString.call(null1)); //[object Null]
console.log(Object.prototype.toString.call(undefined1)); //[object Undefined]
console.log(Object.prototype.toString.call(string1)); //[object String]
console.log(Object.prototype.toString.call(number1)); //[object Number]
console.log(Object.prototype.toString.call(boolean1)); //[object Boolean]
console.log(Object.prototype.toString.call(symbol1)); //[object Symbol]
// 引用类型
console.log(Object.prototype.toString.call(myString)); //[object String]
console.log(Object.prototype.toString.call(myNumber)); //[object Number]
console.log(Object.prototype.toString.call(myBoolean)); //[object Boolean]
console.log(Object.prototype.toString.call(myObject)); //[object Object]
console.log(Object.prototype.toString.call(myArray)); //[object Array]
console.log(Object.prototype.toString.call(myFunction)); //[object Function]
console.log(Object.prototype.toString.call(myDate)); //[object Date]
console.log(Object.prototype.toString.call(myRegExp)); //[object RegExp]
console.log(Object.prototype.toString.call(myError)); //[object Error]

We can see that it returns a string in the format of [object NativeConstructorName], which can clearly determine the native constructor we need. Again, it has the disadvantage of not being able to detect non-native constructors

$.type() in jquery is the internal principle and uses Object.prototype.toString.call(). Let's write a small tool library for type judgment.

 function isType(source) {
    const target = Object.prototype.toString.call(source);
    switch(target) {
        case "[object Null]":
            return 'null';
        case "[object Undefined]":
            return 'undefined';
        case "[object String]":
            return 'string';
        case "[object Number]":
            return 'number';
        case "[object Boolean]":
            return 'boolean';
        case "[object Object]":
            return 'object';
        case "[object Array]":
            return 'array';
        case "[object Function]":
            return 'function';
        case "[object Date]":
            return 'date';
        case "[object RegExp]";
            return 'regexp';
        case "[object Error]";
            return 'error'
    }
}

function getType(target) {
    return Object.prototype.toString.call(target);
}

You may be confused here, the constructor of Object.prototype cannot call null and undefined, but Object.prototype.toString can. why is that?

This involves implicit prototypal inheritance, that is, when using object literals, inheritance has already been implemented, and Object.prototype.toString uses the original method. Believe it or not, you see

 console.log(null1.toString()); // Cannot read properties of null (reading 'toString')
console.log(undefined1.toString()); // Cannot read properties of undefined (reading 'toString')

Summarize

In this section we talked about what JavaSript consists of

In terms of composition, it includes syntax, variables and data types, keywords and reserved words, operators, statements, objects

The data types include primitive types (simple types/value types) and reference types (complex types). The basic types are number, string, boolean, null, undefined, symbol, bigInt, and the reference type is object

How to judge the data type? The author summarizes four methods

name Can detect cannot detect
typeof string, number, boolean, undefined and function null and objects other than function, the result is object
instanceof Accurately determine complex reference data types Unable to correctly determine the underlying data type
constructor string, number, boolean, array, object, function, and constructor undefined, null. Not safe because the pointer can change
Object.prototype.toString() Built-in (native) constructor custom constructor

We have learned about basic types, reference types, their differences and how to distinguish them, but the basic types are simple, and although the reference type is only object, it accounts for most of the knowledge points in JavaScript. Only if you master object, you can learn it. JavaScript

Next, let's talk about KING in JavaScript - object

series of articles


山头人汉波
394 声望555 粉丝