The introduction

27 JS series are tentatively planned, from basic, to prototype, to asynchronous, to design mode, to architecture mode, etc.

Instanceof JS instanceof JS instanceof JS instanceof And instanceof with typeof, Symbol. HasInstance, isPrototype, Object. The prototype. ToString, such as [[Class]] contrast, insight into the JS instanceof.

A, instanceof

1. Introduce the instanceof

In JS, typeof is often used to determine the typeof a variable, but when typeof is used to determine the typeof a variable, no matter what typeof variable it is, it will return Object.

// Basic type
console.log(typeof 100); // number
console.log(typeof 'bottle'); // string
console.log(typeof true); // boolean

// Reference type
console.log(typeof {}); // object
console.log(typeof [1.2.3]); // object
Copy the code

For this, Instanceof was introduced.

The instanceof operator is used to check whether an object belongs to a class, and inheritance relationships are taken into account.

/ / class
class Bottle {}
// bottle is an instance object of the bottle class
let bottle = new Bottle();
console.log(bottle instanceof Bottle); // true

// Can also be a constructor instead of a class
function AnGe() {}
let an = new AnGe();
console.log(an instanceof AnGe); // true
Copy the code

2. Instanceof with typeof

Instanceof in contrast to Typeof, the Instanceof method requires the developer to explicitly identify an object as a particular type. That is the method instanceof uses to determine which constructor a reference type belongs to.

var arr = []
arr instanceof Array // true
typeof arr // "object"
// Typeof cannot determine whether a type is an array
Copy the code

E.g. < 1 > The relationship is instanceof

Also, more importantly, instanceof can be used in inheritance relationships to determine whether an instance is of its parent type.

// Determine if f is an instance of class Foo and of its parent type
function Aoo(){} 
function Foo(){} 
//JavaScript prototype inheritance
Foo.prototype = new Aoo();
 
var foo = new Foo(); 
console.log(foo instanceof Foo) // true 
console.log(foo instanceof Aoo) // true
Copy the code

F instanceof Foo

  • f__proto__Level by level, does that correspond toFoo.prototype
  • Let’s go up and see if that correspondsAoo.prototype
  • Try againf instanceof Object

That is, instanceof can be used to judge multi-level inheritance relationships.

Let’s look at a complicated set of examples

console.log(Object instanceof Object) //true 
console.log(Function instanceof Function) //true 
console.log(Number instanceof Number) //false 
console.log(String instanceof String) //false 
console.log(Array instanceof Array) // false
 
console.log(Function instanceof Object) //true 
 
console.log(Foo instanceof Function) //true 
console.log(Foo instanceof Foo) //false
Copy the code

In this set of data, Object and Function instanceof themselves are true, and other instanceof themselves are false, which starts from the internal implementation mechanism of Instanceof and JS prototype inheritance mechanism.

Ii. The internal implementation mechanism of Instanceof

Instanceof’s internal implementation is to determine the return value of instanceof by determining whether the object’s prototype can be found on the object’s prototype chain

1. Internal implementation

// An internal implementation of instanceof
function instance_of(L, R) {//L indicates the left expression of the table, R indicates the right expression, i.e., L is a variable, R is a type
// take the display prototype of R
var prototype = R.prototype
// take the implicit prototype of L
L = L.__proto__
// Determine whether the type of object (L) is exactly equal to the explicit prototype of type (R)
while (true) { 
 if (L === null) {
   return false
 }
   
 // Key here: return true when prototype is strictly L
 if (prototype === L) {
   return true
 } 
 
 L = L.__proto__
} 
}
Copy the code

The instanceof operator is used to test whether constructor. Prototype exists on the prototype chain of the parameter Object.

2. Do you really understand Instanceof

For example, why does instanceof return true? Clearly, an is not created by Bottle().

function An() {}
function Bottle() {}
An.prototype = Bottle.prototype = {};

let an = new An();
console.log(an instanceof Bottle); // true
Copy the code

This is because Instanceof is not concerned with constructors, but with prototype chains.

an.__proto__ === An.prototype; // true
An.prototype === Bottle.prototype; // true
/ / that
an.__proto__ === Bottle.prototype; // true
Copy the code

__proto__ === Bottle. Prototype; an instanceof Bottle returns true.

So, according to instanceof’s logic, it is prototype, not the constructor, that really determines the type.

3. JS prototype chain inheritance relationship

The image is from the JS prototype chain

Since this article deals with displaying prototype and implicit prototype __proto__, a brief explanation of these two concepts is given below.

In the JavaScript Prototype inheritance structure, the specification uses [Prototype]] to represent the implicit Prototype of an object, __proto__ in JavaScript, and this property is accessible in Firefox and Chrome. But Internet Explorer doesn’t work. All JavaScript objects have a __proto__ attribute, but only object.prototype. __proto__ is null if this attribute has not been modified in Firefox or Chrome. This property points to its prototype object. As for the display prototype, it is represented by the prototype property in JavaScript. This is the basic knowledge of JavaScript prototype inheritance. If you want to learn more about it, please refer to the JS basics: Dive into constructor, prototype, __proto__, [[prototype]] and the prototype chain

Here are a few examples (and their reasoning) to deepen your understanding:

1. Object instanceof Object

// For convenience, first distinguish between left and right expressions
ObjectL = Object, ObjectR = Object; 
// Follow the rules step by step
O = ObjectR.prototype = Object.prototype 
L = ObjectL.__proto__ = Function.prototype 
// First judgmentO ! = L// loop to see if L still has __proto__
L = Function.prototype.__proto__ = Object.prototype 
// Second judgment
O === L 
/ / return true
Copy the code

2. Function instanceof Function

// For convenience, first distinguish between left and right expressions
FunctionL = Function, FunctionR = Function; 
// Follow the rules step by step
O = FunctionR.prototype = Function.prototype 
L = FunctionL.__proto__ = Function.prototype 
// First judgment
O === L 
/ / return true
Copy the code

3. Foo instanceof Foo

// For convenience, first distinguish between left and right expressions
FooL = Foo, FooR = Foo; 
// Follow the rules step by step
O = FooR.prototype = Foo.prototype 
L = FooL.__proto__ = Function.prototype 
// First judgmentO ! = L// Loop again to see if L still has __proto__
L = Function.prototype.__proto__ = Object.prototype 
// Second judgmentO ! = L// Loop again to see if L still has __proto__
L = Object.prototype.__proto__ = null 
// The third judgment
L == null 
/ / returns false
Copy the code

4, Instanceof and Symbol. HasInstance

Symbol. HasInstance is used to determine whether an object is an instance of a constructor. So you can use it to customize the behavior of the Instanceof operator on a class.

You can implement a custom instanceof behavior, for example:

class MyArray {  
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance); }}console.log([] instanceof MyArray); // true
Copy the code

Instanceof and isPrototypeOf

IsPrototypeOf is also used to determine whether an object exists on a prototype chain with another object.

// Determine if f is an instance of Foo,
// and is an instance of its parent type
function Aoo(){} 
function Foo(){} 
// JavaScript prototype inheritance
Foo.prototype = new Aoo();
 
var foo = new Foo(); 
console.log(Foo.prototype.isPrototypeOf(foo)) //true 
console.log(Aoo.prototype.isPrototypeOf(foo)) //true
Copy the code

Note that:

  • instanceof:fooThe prototype chain is aimed atFoo.prototypeexamined
  • isPrototypeOf:fooThe prototype chain is aimed atFooitself

Instanceof and Multiple global objects (interaction between multiple frames or Windows)

Instanceof can be problematic in multiple global scopes, for example:

// parent.html
<iframe src="child.html" onload="test()">
</iframe>
<script>
  function test(){
    var value = window.frames[0].v;
    console.log(value instanceof Array); // false
  }
</script>
Copy the code
// child.html
<script>
  window.name = 'child';
  var v = [];
</script>
Copy the code

Value is technically an array, but the parent page prints: false;

This is because array.prototype! == window.frames[0].array. prototype, and the Array inherits from the former.

The problem is mainly in the browser, when our script starts working with multiple frames or Windows or interacting with multiple Windows. Multiple Windows means multiple global environments, and different global environments have different global objects and thus different built-in type constructors.

The solution

You can use

  • Array. IsArray (myObj) or

  • Object.prototype.toString.call(myObj) === "[object Array]"

To securely check whether the object being passed is an array

Seven, extension: Object. The prototype. The toString method

By default (without overriding toString methods), any call to Object’s native toString method returns “[Object type]”, where type is the type of the Object;

let obj = {};

console.log(obj); / / {}
console.log(obj.toString()); // "[object Object]"
Copy the code

1. [[Class]]

Each instance has a [[Class]] attribute that specifies the type (constructor name) in the above string. [[Class]] can’t directly access, but usually can indirectly by borrowing the default on the value of the Object. The prototype. ToString. Call (..) Method call to show.

Object.prototype.toString.call("abc"); // "[object String]"
Object.prototype.toString.call(100); // "[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([1.2.3]); // "[object Array]"
Object.prototype.toString.call(/\w/); // "[object RegExp]"
Copy the code

2. UseObject.prototype.toString.call(..)Detection Object Type

By the Object. The prototype. ToString. Call (..) To get the type of each object.

function isFunction(value) {
  return Object.prototype.toString.call(value) === "[object Function]"
}
function isDate(value) {
  return Object.prototype.toString.call(value) === "[object Date]"
}
function isRegExp(value) {
  return Object.prototype.toString.call(value) === "[object RegExp]"
}

isDate(new Date()); // true
isRegExp(/\w/); // true
isFunction(function(){}); //true
Copy the code

Or it can be written as:

function generator(type){
  return function(value){
    return Object.prototype.toString.call(value) === "[object "+ type +"]"}}let isFunction = generator('Function')
let isArray = generator('Array');
let isDate = generator('Date');
let isRegExp = generator('RegExp');

isArray([]));    // true
isDate(new Date()); // true
isRegExp(/\w/); // true
isFunction(function(){}); //true
Copy the code

3. Symbol.toStringTag

Object. The prototype. The toString method can use Symbol. ToStringTag this particular Object properties to customize the output.

For example:

let bottle = {
  [Symbol.toStringTag]: "Bottle"
};

console.log(Object.prototype.toString.call(bottle)); // [object Bottle]
Copy the code

Most environment-related objects also have this property. The following output may vary from browser to browser:

// toStringTag for environment-related objects and classes:
console.log(window[Symbol.toStringTag]); // Window
console.log(XMLHttpRequest.prototype[Symbol.toStringTag]); // XMLHttpRequest

console.log(Object.prototype.toString.call(window)); // [object Window]
console.log(Object.prototype.toString.call(new XMLHttpRequest())); // [object XMLHttpRequest]
Copy the code

The output is the same as symbol.toStringTag (if it exists), but wrapped in object… In the water.

So, if you want to get the built-in object type information as a string, rather than just detect the type, you can use this method instead of Instanceof.

Eight, summary

Apply to return
typeof Basic data types string
instanceof Any object true/false
Object.prototype.toString Basic data types, built-in objects, and containsSymbol.toStringTagProperty object string

Object. The prototype. ToString is basically a enhanced version typeof.

Instanceof is useful in situations involving multi-tier class structures, where class inheritance needs to be taken into account.

Nine, reference

An in-depth look at the JavaScript instanceof operator

Type check: “instanceof”

Series of articles

  • JS series 1: var, let, const, deconstruct, expand, new, this, class, function
  • JS series 2: Constructor, Prototype,proto, [[Prototype]] and Prototype chain
  • JS series 3: Six implementations of inheritance
  • JS series 4: An in-depth look at the Instanceof operator

For more on this series,Click on the Github homepage

Walk last

1. ❤️ Have fun, keep learning, and always keep coding. 👨 💻

2. If you have any questions or more unique insights, please feel free to comment or contact Me directly (123)! 👀 👇

3. 👇 Welcome to pay attention to: front-end bottle Jun, daily update! 👇