This article mainly explains ECMAScript7
Normative instanceof
The operator .
Preliminary knowledge
Famous Symbols
“ famous ” Of Symbols
Refers to built-in symbols , They are defined in Symbol
On the object .ECMAScript7
Used in @@name
These built-in symbols are referenced in the form of , For example, the following will be mentioned @@hasInstance
, In fact, that is Symbol.hasInstance
.
InstanceofOperator(O, C)
O instanceof C
Called internally InstanceofOperator(O, C)
Abstract operations , The steps of the abstract operation are as follows :
- If
C
Is not an object , Throw an exception of the wrong type ; - Give Way
instOfHandler
be equal toGetMethod(C, @@hasInstance)
, Maybe semantics is to get objectsC
Of@@hasInstance
The value of the property ; If
instOfHandler
The value is notundefined
, that :- return
ToBoolean(? Call(instOfHandler, C, « O »))
Result , Maybe semantics is executioninstOfHandler(O)
, Then the call result is forced to be converted to boolean type and returned .
- return
- If
C
Cannot be called , Throw an exception of the wrong type ; - return
OrdinaryHasInstance(C, O)
Result .
OrdinaryHasInstance(C, O)
OrdinaryHasInstance(C, O)
The steps of abstract operation are as follows :
- If
C
Cannot be called , returnfalse
; If
C
There are internal slots[[BoundTargetFunction]]
, that :- Give Way
BC
be equal toC
The internal slot of[[BoundTargetFunction]]
Value ; - return
InstanceofOperator(O, BC)
Result ;
- Give Way
- If
O
The type of is not an object , returnfalse
; - Give Way
P
be equal toGet(C, "prototype")
, Probably semantics is to getC.prototype
Value ; - If
P
Is not an object , Throw an exception of the wrong type ; Repeat the following steps :
- Give Way
O
be equal toO.[[GetPrototypeOf]]()
Result , Maybe semantics is to getO
Prototype object ; - If
O
be equal tonull
, returnfalse
; - If
SameValue(P, O)
The result istrue
, returntrue
.
- Give Way
SameValue
For abstract operations, see JavaScript Medium ==,=== and Object.js() Medium Object.is()
,Object.is()
This is the result of this abstract operation .
From the above steps 2
You know , If C
It's a bind
function , Then it will be back in C
Bound to the target function InstanceofOperator(O, BC)
operation .
From the above steps 6
You know , Will repeatedly get the object O
Prototype object , Then compare the prototype object with C
Of prototype
Whether the attributes are equal , Until equal returns true
, perhaps O
Turn into null
, That is, traversing the entire prototype chain , return false
.
Function.prototype[@@hasInstance] (V)
By the above InstanceofOperator(O, C)
Steps for abstract operations 2
and 3
You can know , If C
It defines or inherits from @@ hasInstance
Attribute words , The value of the property is called , And not to step up to the steps 4
and 5
. step 4
and 5
The aim is to be compatible without implementation @@hasInstance
Method browser . If a function has no definition or inheritance @@hasInstance
attribute , Then the default will be used instanceof
The semantics of the , That is to say OrdinaryHasInstance(C, O)
The steps described in the abstract operation .
ECMAScript7
Specification , stay Function
Of prototype
Property defined on @@hasInstance
attribute .Function.prototype[@@hasInstance](V)
The steps are as follows :
- Give Way
F
be equal tothis
value ; - return
OrdinaryHasInstance(F, V)
Result .
therefore , You can see that by default ,instanceof
The semantics of are the same , All return to OrdinaryHasInstance(F, V)
Result . Why say by default ? Because you can cover Function.prototype[@@hasInstance]
Method , To customize instanceof
act .
Example
function A () {}
function B () {}
var a = new A
a.__proto__ === A.prototype // true
a.__proto__.__proto__ === Object.prototype // true
a.__proto__.__proto__.__proto__ === null // true
a instanceof A // true
a instanceof B // false
from OrdinaryHasInstance(C, O)
Of the 6
Step by step :
- about
a instanceof A
,P
yesA.prototype
, In the first cycle ,a
Prototype objecta._proto__
yesA.prototype
, That is, in the stepsO
yesA.prototype
, So it goes backtrue
; - about
a instanceof B
,P
yesB.prototype
, In the first cycle ,a
Prototype objecta._proto__
yesA.prototype
, It's not equal toP
; Perform the second cycle , hereO
yesa.__proto__.__proto__
, That is to sayObject.prototype
, It's not equal toP
; Perform the third cycle , hereO
yesa.__proto__.__proto__.__proto__
, That is to saynull
, That is, the prototype chain has been traversed , So it goes backfalse
.
Next, let's take the example above :
A.prototype.__proto__ = B.prototype
a.__proto__ === A.prototype // true
a.__proto__.__proto__ === B.prototype // true
a.__proto__.__proto__.__proto__ === Object.prototype // true
a.__proto__.__proto__.__proto__.__proto__ === null // true
a instanceof B // true
In the example above , We put B.prototype
Set up a a
A link in the prototype chain of , such a instanceof B
stay OrdinaryHasInstance(C, O)
Of the 6
Step one 2
In the second cycle , Back to true
.
from OrdinaryHasInstance(C, O)
Of the 2
Step , We know bind
The behavior of a function is different from that of a normal function :
function A () {}
var B = A.bind()
B.prototype === undefined // true
var b = new B
b instanceof B // true
b instanceof A // true
From the above example ,B.prototype
yes undefined
. therefore ,instanceof
Act on bind
The return result of a function is actually the return value of the binding target function , and bind
Functions basically have nothing to do with .
from InstanceofOperator(O, C)
step 2
And steps 3
You know , We can go through @@hasInstance
Attributes come from definitions instanceof
act :
function A () {}
var a = new A
a instanceof A // true
A[Symbol.hasInstance] = function () { return false }
a instanceof A // ?
stay chrome
The browser tested , Discover or output true
. Then I took a look at ECMAScript6
Documents ,ECMAScript6
There is no provision in the document that can be passed @@hasInstance
change instanceof
act , So it should be the present chrome
The browser hasn't been implemented yet ECMAScript7
Medium instanceof
The behavior of the operator .
Until one day I saw MDN
On Symbol.hasInstance Compatibility section of , Find out chrome
from 51
The version starts to support Symbol.hasInstance
了 :
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance)
}
}
console.log([] instanceof MyArray) // true
So why can't I write like that ? Until I found out :
function A () {}
var fun = function () {return false}
A[Symbol.hasInstance] = fun
A[Symbol.hasInstance] === fun // false
A[Symbol.hasInstance] === Function.prototype[Symbol.hasInstance] // true
A[Symbol.hasInstance] === A.__proto__[Symbol.hasInstance] // true
You can tell by the code above ,A[Symbol.hasInstance]
No assignment succeeded , And always equal to Function.prototype[Symbol.hasInstance]
, That is always equal to A
On the prototype of Symbol.hasInstance
Method . Is that because of the same name method on the prototype ?
Object.getOwnPropertyDescriptor(Function.prototype, Symbol.hasInstance)
// Object {writable: false, enumerable: false, configurable: false, value: function}
You can tell by the code above ,Function.prototype
Upper Symbol.hasInstance
Of the property descriptor of writable
yes false
, That is, this property is read-only , So in A
Add above Symbol.hasInstance
Property failed . But why is there no hint of failure ?
'use strict'
function A () {}
var fun = function () {return false}
A[Symbol.hasInstance] = fun
// Uncaught TypeError: Cannot assign to read only property 'Symbol(Symbol.hasInstance)' of function 'function A() {}'
The error is coming out , So try to use strict mode in the future . Some operations in non strict mode will Silence fails , That is, even if the operation fails, there will be no prompt , Causes the developer to think that the operation was successful .
var a = {}
a[Symbol.hasInstance] = function () {return true}
new Number(3) instanceof a // true
Because you can customize Symbol.hasInstance
Method to override the default behavior , So use instanceof
Operators are not necessarily reliable in judging data types .
There's another problem : Why is it up there MDN
Examples of documents can be successful , My first example didn't work , The purpose is not to write a constructor , Then add an attribute to the constructor ?
The result of personal analysis is : Although everyone said Class
Is a syntax sugar for writing constructors , But it's still used function
There are differences in the way , Like the example above . Use Class
When , Will directly add a static property to the constructor , It does not first check whether there is an attribute with the same name on the prototype chain . While using function
The way when , Add a static method to the constructor , It is equivalent to assigning a value to an object , The assignment operation will first check whether there is an attribute with the same name on the prototype chain , So there is a risk of assignment failure . therefore , Just add... To the constructor Symbol.hasInstance
In terms of attributes ,Class
Can do , Use Function
The way it can't be done .
Updated on 2018/11/20
It concludes that
therefore , Just add... To the constructorSymbol.hasInstance
In terms of attributes ,Class
Can do , UseFunction
The way it can't be done .
however , It turns out that adding properties to an object is not just a way of assigning values , One more Object.defineProperty Method :
function A () {}
var a = new A
a instanceof A // true
Object.defineProperty(A, Symbol.hasInstance, {
value: function () { return false }
})
a instanceof A // false
summary
This article mainly explains ECMAScript7
Normative instanceof
The operator , I hope you can get something . If there is any mistake or laxity in this article , Feel free to leave a comment in the comments section .