Delicious value: 🌟🌟🌟🌟🌟

Taste: Shrimp balls with mustard

In order to align with Teacher Yi, let’s have a brief review first.

JavaScript data types include primitive types and object types:

  • Primitive types: Null, Undefined, Number, String, Boolean, Symbol, BigInt
  • Object type: Object

We are used to referring to objects as reference types, and of course there are many special reference types, such as Function, Array, RegExp, Math, Date, Error, Set, Map, various stereotyped arrays TypedArray, etc.

The primitive type value is stored in the stack, and the object type value is stored in the heap, keeping the reference address of the object in the stack, and when JavaScript accesses the data, it accesses it through the reference in the stack.

In JavaScript, an assignment of a primitive type copies the value of a variable, while an assignment of an object (reference) type copies the reference address.

Let’s practice our skills with two more common interview questions

let a = {
    name: 'Front Canteen'.age: 2
}
let b = a
console.log(a.name)
b.name = 'Baby Oba'
console.log(a.name)
console.log(b.name)

// Front-end canteen
/ / child Obama
/ / child Obama
Copy the code

The first question is So Easy that you can answer it with your eyes closed.

let a = {
    name: 'Front Canteen'.age: 2
}
const expand = function(b) {
    b.age = 18
    b = {
        name: 'Baby Oba'.age: 25
    }
    return b
}
let c = expand(a)
console.log(c.age)
console.log(a.age)
console.log(a)

/ / 25
/ / 18
// {name: "Front-End dining hall ", age: 18}
Copy the code

Some students may get this question wrong, so let’s analyze it together:

Expand is passing the memory address of the object in the heap. You can change the age property of object A by calling b.age = 18.

{name: “child obar “, age: 25}; age: 25}

Next, let’s give a warm applause to welcome Mr. Yi.

I’ll ask you some questions, and you can always drink.

Do you know of any JavaScript methods for detecting data types?

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

So how does typeof work?

1.typeof

typeof 'a' // 'string'
typeof 1   // 'number' 
typeof true // 'boolean'
typeof undefined // 'undefined'
typeof Symbol('a') // 'symbol'
typeof 1n // 'bigint'

typeof null // 'object'

typeof function() {} // 'function'
typeof [] // 'object'
typeof {} // 'object'
typeof /a/ // 'object'
typeof new Date(a)// 'object'
typeof new Error(a)// 'object'
typeof new Map(a)// 'object'
typeof new Set(a)// 'object'
Copy the code

Two conclusions:

  1. Typeof determines primitive types other than NULL.
  2. Typeof can only determine the typeof object Function, other types of object.

Why are typeof null values object?

Typeof returns object when detecting null, a Bug in the original JavaScript language that has been retained for compatibility with older code.

If you want to learn more, please click the link below.

  • link

Tips

NaN has to be mentioned here, because we all know that he plays a lot.

typeof NaN // number
Copy the code

F**k NaN!

Do you know which types instanceof can identify?

2.instanceof

Checks whether the constructor’s Prototype property appears on the prototype chain of an instance object.

That is, a instanceof B is used to judge whether a is an instanceof B, that is, whether there is a constructor of B on the prototype chain of a.

console.log(1 instanceof Number) // false
console.log(new Number(1) instanceof Number) // true

const arr = []
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true

const Fn = function() {
    this.name = 'Constructor'
}
Fn.prototype = Object.create(Array.prototype)
let a = new Fn()
console.log(a instanceof Array) // true
Copy the code

Two conclusions:

  1. instanceofObject (reference) types can be accurately determined, but primitive types cannot be accurately detected.
  2. This method is not safe because we can modify the orientation of the prototype at will to lead to inaccurate detection results.

If I just want to check primitive types with Instanceof, can you meet my needs?

Ok, satisfied.

Although Instanceof cannot detect primitive types, there is a way to use it to detect primitive types.

Symbol.hasinstance allows us to customize the behavior of instanceof.

class PrimitiveNumber {
  static [Symbol.hasInstance] = x= > typeof x === 'number';
}
123 instanceof PrimitiveNumber; // true

class PrimitiveString {
  static [Symbol.hasInstance] = x= > typeof x === 'string';
}
'abc' instanceof PrimitiveString; // true

class PrimitiveBoolean {
  static [Symbol.hasInstance] = x= > typeof x === 'boolean';
}
false instanceof PrimitiveBoolean; // true

class PrimitiveSymbol {
  static [Symbol.hasInstance] = x= > typeof x === 'symbol';
}
Symbol.iterator instanceof PrimitiveSymbol; // true

class PrimitiveNull {
  static [Symbol.hasInstance] = x= > x === null;
}
null instanceof PrimitiveNull; // true

class PrimitiveUndefined {
  static [Symbol.hasInstance] = x= > x === undefined;
}
undefined instanceof PrimitiveUndefined; // true
Copy the code

The code source is linked below.

  • Is there a way to use instanceof for raw JavaScript values?

Since you know so much about Instanceof, can you hand write one for me on the spot?

Handwritten instanceof

const myInstanceof = function(left, right) {
    if (typeofleft ! = ='object' || left === null) return false
    let proto = Reflect.getPrototypeOf(left)
    while (true) {
        if (proto === null) return false
        if (proto === right.prototype) return true
        proto = Reflect.getPrototypeOf(proto)
    }
}

const arr = []
console.log(myInstanceof(arr, Array)) // true
console.log(myInstanceof(arr, Object)) // true
console.log(myInstanceof(arr, RegExp)) // false
Copy the code

To understand how Instanceof works, you need to understand prototype chains. For those of you who are not familiar with JavaScript prototype chains, check out the link below.

  • JavaScript goes from prototype to prototype chain
  • How to answer the JavaScript prototype chain question in an interview

B: How about constructor?

3.constructor

For numeric immediates, using constructor directly returns an error from literal parsing of floating-point numbers, rather than processing “.” as the access operator.

In JS, floating point decimal places are nullable, so 1. And 1.0 are parsed to the same floating point number.

// A parenthesis operator is needed to convert a value to an object
(1).constructor ƒ Number() {[native code]}
/ / or
1..constructor ƒ Number() {[native code]}

const a = 'Front Canteen'
console.log(a.constructor) ƒ String() {[native code]}
console.log(a.constructor === String) // true

const b = 5
console.log(b.constructor) ƒ Number() {[native code]}
console.log(b.constructor === Number) // true

const c = true
console.log(c.constructor) ƒ Boolean() {[native code]}
console.log(c.constructor === Boolean) // true

const d = []
console.log(d.constructor) ƒ Array() {[native code]}
console.log(d.constructor === Array) // true

const e = {}
console.log(e.constructor) ƒ Object() {[native code]}
console.log(e.constructor === Object) // true

const f = () = > 1
console.log(f.constructor) ƒ Function() {[model]}
console.log(f.constructor === Function) // true

const g = Symbol('1')
console.log(g.constructor) ƒ Symbol()
console.log(g.constructor === Symbol) // true

const h = new Date(a)console.log(h.constructor) ƒ Date() {[native code]}
console.log(h.constructor === Date) // true

const i = 11n
console.log(i.constructor) ƒ BigInt() {[native code]}
console.log(i.constructor === BigInt) // true

const j = /a/
console.log(j.constructor) ƒ RegExp() {[native code]}
console.log(j.constructor === RegExp) // true


String.prototype.constructor = 'aaa'
console.log(a.constructor === String) // false

const k = null
console.log(k.constructor) // Cannot read property 'constructor' of null

const l = undefined
console.log(l.constructor) // Cannot read property 'constructor' of undefined
Copy the code

Two conclusions:

  1. Except for null and undefined,constructorPrimitive and object (reference) types are correctly detected.
  2. Because we can modify at willconstructorResults in inaccurate detection results, so this method is not safe.

Left of the Object. The prototype. ToString, it perfect?

4.Object.prototype.toString

The toString() method returns a string representing the object, and we can change its this to point to the value to be tested to return information about the current tested value.

Object.prototype.toString({}) // '[object Object]'

Object.prototype.toString.call({}) // '[object Object]'
Object.prototype.toString.call('a') // '[object String]'
Object.prototype.toString.call(1) // '[object Number]'
Object.prototype.toString.call(true) // '[object Boolean]'
Object.prototype.toString.call(null) // '[object Null]'
Object.prototype.toString.call(undefined) // '[object Undefined]'
Object.prototype.toString.call(Symbol('a')) // '[object Symbol]'
Object.prototype.toString.call(11n) // '[object BigInt]'
Object.prototype.toString.call(/a/) // '[object RegExp]'
Object.prototype.toString.call(new Date()) // '[object Date]'
Object.prototype.toString.call([0.1.2]) // '[object Array]'
Object.prototype.toString.call(function() {}) // '[object Function]'
Object.prototype.toString.call(new Error()) // '[object Error]'
Object.prototype.toString.call(new Set()) // '[object Set]'
Object.prototype.toString.call(new Map()) // '[object Map]'
Copy the code

Can you encapsulate a general method for detecting data types?

Encapsulate a common way to detect data types

Be case sensitive when encapsulating methods.

There are many kinds of schemes, here simply provide two ideas.

const getType = function(obj) {
    let type = typeof obj
    if(type ! = ='object') {
        return type
    }
    return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/.'$1').toLowerCase()
}

getType({}) // object
getType('a') // string
getType(1) // number
getType(true) // boolean
getType(null) // null
getType(undefined) // undefined
getType(Symbol('a')) // symbol
getType(11n) // bigint
getType(/a/) // regexp
getType(new Date()) // date
getType([0.1.2]) // array
getType(function() {}) // function
getType(new Error()) // error
getType(new Map()) // map
getType(new Set()) // set
Copy the code

Of course, you can do this by changing your position.

Object.prototype.toString.call('1').slice(8, -1).toLowerCase()
// 'string'
Copy the code

At this point, it’s almost a perfect answer.

If you think you missed something, feel free to add it in the comments section.

The last question from Mr. Yi is:

Do you like JavaScript?

❤️ Love triple punch

1. If you think the food and drinks in the canteen are ok with you, please give me a thumbs-up. Your thumbs-up is my biggest motivation.

2. Pay attention to the front canteen of the public account and eat every meal!

3. Like, comment, forward === urge more!