Compact-base series (I) Data types and their detection and progression

1. Series introduction

In the recent interview, as well as in the process of interviewing others, I deeply understand that now many front end bosses are deeply submerged by various frameworks, or unable to extricate themselves in the business. Ignore the foundation, become CV believers, the problem depends on Baidu. Rarely to think, or to summarize, of course, including myself, so I decided to consolidate the foundation, start again.

The first section covers data types and their common detection methods, data storage forms, garbage collection, including some methods of handwriting that are often requested in interviews.

2. Data types in JS

JS data types fall into two broad categories: basic types and reference types.

Boolean, undefined, null, and symbol. Reference types include: Object.

Interviewer: “So what are basic types and what are reference types?”

Xiao Ming: “Basic types are simple data segments, while reference types may consist of multiple values.

Interviewer: “How are simple types and reference types stored?” Simple types are accessed by value and stored in the memory stack, reference types are accessed by reference, addresses are stored in the stack, and contents are stored in the heap. So when you copy a simple type, you copy a value, but when you copy a reference type, you copy a reference address, so there’s deep copy and shallow copy. “

Interviewer: “Good answer, next question.”

x

3. Check the data type

typeof

Using typeof can detect the typeof data, which is good for basic types, but cannot detect the specific typeof an object, such as Date and RegExp. Take a look at the following example.

typeof '1'= = ='string'
typeof 1= = ='number'
typeof= = = {}'object'
typeof undefined= = ='undefined'
typeof null= = ='object' // Null is considered an empty object
typeof Symbol(1) = = ='symbol' typeof NaN= = ='number' typeof Function= = ='function' typeof true= = ='boolean' Copy the code

Typeof to return there are more than several types: string, number, object, function, undefined, symbol, Boolean seven, but cannot know whether array, etc.

Detection array

Detecting arrays provides two operators, isArray and Instanceof.

isArray

Array.isarray () is used to determine whether the value passed is an Array

Array.isArray([1.2.3])  // true 
Copy the code

instanceof

Tests whether an object is an instance of a constructor

[] instanceof Array // true

var a = {}
a instanceof Object // true
Copy the code

However, it is recommended to use isArray when detecting arrays, because instanceof does not work well in some scenarios.

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length- 1].Array;
var arr = new xArray(1.2.3); / / [1, 2, 3]

Array.isArray(arr); // true arr instanceof Array; // false Copy the code

Tiger balm

Object.protptype.toString.call(obj)

All types can be accurately detected using this method.

Object.protptype.toString.call({}) === "[object Object]"
Object.protptype.toString.call([]) === "[object Array]"
Copy the code

Why is this an accurate type of detection? Because the prototype of Object has a toString method on it, all other types of values inherit from the toString method on the Object. But since each type overwrites the toString method, we have to call the toString method on ojeact.prototype. Take a look at 👇 :

[].toString()   // The result is ""
Array.prototype.hasOwnProperty('toString') // true
Number.prototype.hasOwnProperty('toString') // true
String.prototype.hasOwnProperty('toString')  // true
Let's delete the toString method on the array prototype delete Array.prototype.toString  [].toString() // [object Array] Object.protptype.toString.call([]) === "[object Array]" Copy the code

It’s the same because he’s deleting the toString on the array stereotype and he’s looking for the toString method on the object based on the stereotype chain.

extension

A method to implement a detection type:

function detectType (obj) {
    return Object.prototype.toString.call(obj).slice(8.- 1).toLowerCase()
}
Copy the code

There are three special objects in js. String, Boolean, Number, all objects generated by the new keyword are objects of type, if typeof is used. You need to pay attention when you are developing.

4.Number

Probably the most interesting data type in ECMAScript is the Number type, which uses the IEEE754 format to represent integers and floating-point values (floating-point values are also called double values in some languages).

What is IEEE754 format?Copy the code

To tell you the truth, I don't understand it, there are too many technical terms, remember the double precision of JS floating point values, namely 64 bits (8 bytes)

0.1 + 0.2! == 0.3

Since 0.1 and 0.2 is converted into binary are: 0.00011001100110011001100 0.001100110011001100110011 (1100) infinite loop (0011) infinite loop. Js is 64-bit (8 bytes), so some of the later parts of the loop will be discarded, which leads to this kind of problem. Tips: Do not use floating-point numbers unless you do not require precision.

So how do you solve the floating-point calculation problem? As you can probably imagine, convert to integers, and then convert to floating point after you’ve done the math. So much for code.

function transform (num1, num2, type) {
    const typeList = ['add'.'min'.'multi'.'divide']
    if(! num1 || ! num2 || ! type) {        throw Error('num1 & num2 & type are required')
    }
  if(! typeList.includes(type)) { throw Error("There are four types can be accepted 'add', 'min', 'multi', 'divide'")  }   let maxLen = 0  let copyNum1 = 0  let copyNum2 = 0  let l = num1.toString().split('. ').length > 2 ? num1.toString().split('. ') [1].length : 0  let r = num2.toString().split('. ').length > 2 ? num2.toString().split('. ') [1].length : 0  maxLen = l < r ? r : l  copyNum1 = floatToInt(num1, maxLen)  copyNum2 = floatToInt(num2, maxLen)   if (type === 'add') {  return (copyNum2 + copyNum1) / Math.pow(10, maxLen)  } else if (type === 'min') {  return (copyNum1 - copyNum2) / Math.pow(10, maxLen)  } else if (type === 'divide') {  return copyNum1 / copyNum2  } else if (type === 'multi') {  return (copyNum1 * copyNum2) / Math.pow(Math.pow(10, maxLen), 2)  } }  function floatToInt (num, len) {  return num * Math.pow(10, len) }  Copy the code

5. Garbage collection

JavaScript has an automatic garbage collection mechanism, which means that the execution environment is responsible for managing the memory used during code execution. In languages such as C and C++, a basic task for developers is to manually track memory usage, which is a source of many problems. When writing JavaScript programs, developers no longer have to worry about memory usage, and the allocation of needed memory and the reclaiming of unused memory are fully automated. The principle of this garbage collection mechanism is simple: find the variables that are no longer in use and free up the memory they occupy. To do this, the garbage collector does this periodically at fixed intervals (or at predetermined collection times during code execution). Let’s examine the normal life cycle of a local variable in a function. Local variables exist only for the duration of function execution. In the process, local variables are allocated space in stack (or heap) memory to store their values. These variables are then used in the function until the end of the function execution. At this point, there is no need for local variables to exist, so their memory can be freed for future use. In this case, it’s easy to determine whether the variable is still necessary; But it is not so easy to draw conclusions in all cases. The garbage collector must keep track of which variables are useful and which are not, marking variables that are no longer useful in order to reclaim their memory in the future. The policies used to identify useless variables may vary from implementation to implementation, but when it comes to browser-specific implementations, there are usually two policies.

5.1 Reference Counting

Concepts are recycled once they are not referenced. But a special case is the problem of circular references. In this case, unrecyclable will occur. This results in a memory leak.

var a = {
    b: 1
}

var c = {
 d: 2 } a.c = c c.a = a Copy the code

In this case, A and C will not be recovered. This is the first js recycling mechanism. In this case, it can only be manually cleared


a = null
c = null

Copy the code

Setting it to NULL does not mean it will be cleared immediately. Will only wait for the next collector collection in order to remove it from the execution environment.

5.2 Mark Clearing

The tag sweep algorithm is a garbage collection algorithm that is the first garbage collection algorithm that can reclaim data structures that are circularly referenced. There are still a number of common garbage collection techniques that use variations of various mark-clearing algorithms.

Unreferenced objects are not immediately reclaimed when the marker cleanup algorithm is used. Instead, garbage objects accumulate until memory runs out. When memory runs out, the program is suspended and garbage collection begins. Execution continues when all unreferenced objects have been cleared.

Tag-cleaning algorithms are also called traceable garbage collectors because they track all the objects referenced by the program. An object that is directly accessible in a program is an object that is referred to by a local variable on the stack or by any static variable. From a garbage collection perspective, these objects are called roots. An object can be accessed indirectly if it is referenced by a field in another object that is accessible (directly or indirectly). Objects that are accessible are called live, and other objects are called garbage.

A couple of concepts here

5.2.1 accessibility

Simply put, “reachability” values are those that are accessible or available in some way and are guaranteed to be stored in memory.

5.2.2 root

1. Global variables 2. internal 3. other variables or functions on the current scope chain 4. The local variables and parameters of the local function are called roots

If the reference or chain of references can be found in the root, then the value is reachable.

Such as:

var a = {
    b: 'xx'
}
var c= 1
a.b = c
Copy the code

Window => a => b => a.b = c a in the global variable a, the value of the b attribute in a is variable c, which indicates that c can be found in the root, indicating that c is reachable. If we set a = null, the reference to a is lost globally. The variable C is unreachable and is removed from the execution environment until it is reclaimed. Above:

Cut reference a = null:

When cut off, a’s reference to B is lost, and the circle becomes unreachable, marked and waiting to be cleared.

Common Handwriting series

1.instanceof

Instanceof returns true if it is present in the prototype, false if it is not, and returns true if it is not null

function myInstanceOf (left, right) {
    const rightProto = right.prototype
    let leftVaule = left.__proto__

    while (true) {
 if (leftVaule === null) {  return false  } else if (leftVaule === rightProto) {  return true  }   leftVaule = leftVaule.__proto__  } }  Copy the code

2. Tyopeof principle

Different objects are represented as binary at the bottom level, and in Javascript their type information is stored in the first (low) bits of binary.

000: object 010: floating point 100: string 110: Boolean 1: integerCopy the code

Typeof NULL is “object” because different objects are represented as binary at the bottom level. In Javascript, if the first (low) bits of binary are all zeros, then the type is considered as object. So typeof returns “object”, function if the object has a “[[Call]]” method, and object otherwise.

3. Shallow copy and deep copy

3.1 shallow copy

Object.assign()
Object.create()
// Both are shallow copies

Copy the code

3.2 deep copy

Parse (json.stringify (obj))

JSON.parse(JSON.stringify(obj))
Copy the code

However, there are disadvantages, such as the failure to solve the circular reference problem, and the time zone will be lost by copying the time type.

2. Write the second one by hand. This attack is for reference only. There are many other areas that need special treatment, such as arrayBuffers, multi-weft arrays, circular references, and so on.

function detectType (obj) {
    return Object.prototype.toString.call(obj).slice(8.- 1).toLowerCase()
}

function deepClone (parent, obj = {}) {
 const newObj = Array.isArray(obj) ? [] : {}  for (let key in parent) {  if (detectType(parent[key]) === 'array') {  newObj[key] = parent[key].concat([])  } else if (detectType(parent[key]) === 'regexp') {  newObj[key] = new parent[key].constructor(obj)  } else if (detectType(parent[key]) === 'date') {  newObj[key] = new parent[key].constructor(parent[key].getTime())  } else if (detectType(parent[key]) === 'object') {  const temp = {}  newObj[key] = temp  deepClone(parent[key], temp)  } else {  newObj[key] = parent[key]  }  }  return newObj } 3.Use a library like Lodash, but still understand how it worksCopy the code

Refer to the article

JavaScript garbage collection — tag cleanup and reference counting

Front-end interview: Talk about JS garbage collection mechanism

Focus on me and lay the foundation with me

Next time we’ll focus on objects and functions

This article was typeset using MDNICE