构造函数
property returns a reference to the
Object
constructor function that created the instance object. Note that the value of this property is a reference to
the function itself
, not a string containing the function's name.
The value is only read-only for primitive values such as
1
,
true
,和
"test"
.
All objects (with the exception of objects created with
Object.create(null)
) will have a
构造函数
property. Objects created without the explicit use of a constructor function (such as object- and array-literals) will have a
构造函数
property that points to the Fundamental Object constructor type for that object.
let o = {}
o.constructor === Object // true
let o = new Object
o.constructor === Object // true
let a = []
a.constructor === Array // true
let a = new Array
a.constructor === Array // true
let n = new Number(3)
n.constructor === Number // true
The following example creates a constructor (
Tree
) and an object of that type (
theTree
). The example then displays the
构造函数
property for the object
theTree
.
function Tree(name) {
this.name = name
}
let theTree = new Tree('Redwood')
console.log('theTree.constructor is ' + theTree.constructor)
This example displays the following output:
theTree.constructor is function Tree(name) {
this.name = name
}
The following example shows how to modify the constructor value of generic objects. Only
true
,
1
,和
"test"
will not be affected (as they have read-only native constructors).
This example shows that it is not always safe to rely on the
构造函数
property of an object.
function Type () {}
let types = [
new Array(),
[],
new Boolean(),
true, // remains unchanged
new Date(),
new Error(),
new Function(),
function () {},
Math,
new Number(),
1, // remains unchanged
new Object(),
{},
new RegExp(),
/(?:)/,
new String(),
'test' // remains unchanged
]
for (let i = 0; i < types.length; i++) {
types[i].constructor = Type
types[i] = [types[i].constructor, types[i] instanceof Type, types[i].toString()]
}
console.log(types.join('\n'))
This example displays the following output (comments added for reference):
function Type() {},false, // new Array()
function Type() {},false, // []
function Type() {},false,false // new Boolean()
function Boolean() {
[native code]
},false,true // true
function Type() {},false,Mon Sep 01 2014 16:03:49 GMT+0600 // new Date()
function Type() {},false,Error // new Error()
function Type() {},false,function anonymous() {
} // new Function()
function Type() {},false,function () {} // function () {}
function Type() {},false,[object Math] // Math
function Type() {},false,0 // new Number()
function Number() {
[native code]
},false,1 // 1
function Type() {},false,[object Object] // new Object()
function Type() {},false,[object Object] // {}
function Type() {},false,/(?:)/ // new Regexp()
function Type() {},false,/(?:)/ // /(?:)/
function Type() {},false, // new String()
function String() {
[native code]
},false,test // 'test'
Mostly this property is used for defining a function as a function-constructor with further calling it with new and prototype-inherits chain.
function Parent() { /* ... */ }
Parent.prototype.parentMethod = function parentMethod() {}
function Child() {
Parent.call(this) // Make sure everything is initialized properly
}
Child.prototype = Object.create(Parent.prototype) // re-define child prototype to Parent prototype
Child.prototype.constructor = Child // return original constructor to Child
But when do we need to perform the last line here? Unfortunately, the answer is: it depends .
Let's try to define the cases in which re-assignment of the original constructor will play a major role, and when it will be one superfluous line of code.
Take the following case: the object has the
create()
method to create itself.
function Parent() { /* ... */ }
function CreatedConstructor() {
Parent.call(this)
}
CreatedConstructor.prototype = Object.create(Parent.prototype)
CreatedConstructor.prototype.create = function create() {
return new this.constructor()
}
new CreatedConstructor().create().create() // TypeError undefined is not a function since constructor === Parent
In the example above the exception will be shown since the constructor links to Parent.
To avoid this, just assign the necessary constructor you are going to use.
function Parent() { /* ... */ }
function CreatedConstructor() { /* ... */ }
CreatedConstructor.prototype = Object.create(Parent.prototype)
CreatedConstructor.prototype.constructor = CreatedConstructor // sets the correct constructor for future use
CreatedConstructor.prototype.create = function create() {
return new this.constructor()
}
new CreatedConstructor().create().create() // it's pretty fine
Ok, now it's pretty clear why changing the constructor can be useful.
Let's consider one more case.
function ParentWithStatic() {}
ParentWithStatic.startPosition = { x: 0, y:0 } // Static member property
ParentWithStatic.getStartPosition = function getStartPosition() {
return this.startPosition
}
function Child(x, y) {
this.position = {
x: x,
y: y
}
}
Child = Object.assign(ParentWithStatic)
Child.prototype = Object.create(ParentWithStatic.prototype)
Child.prototype.constructor = Child
Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() {
let position = this.position
let startPosition = this.constructor.getStartPosition() // error undefined is not a function, since the constructor is Child
return {
offsetX: startPosition.x - position.x,
offsetY: startPosition.y - position.y
}
};
For this example we need either to stay parent constructor to continue to work properly or reassign static properties to child's constructor:
... Child = Object.assign(ParentWithStatic) // Notice that we assign it before we create(...) a prototype below Child.prototype = Object.create(ParentWithStatic.prototype) ...
or assign parent constructor identifier to a separate property on the Child constructor function and access it via that property:
... Child.parentConstructor = ParentWithStatic Child.prototype = Object.create(ParentWithStatic.prototype) ... let startPosition = this.constructor.parentConstructor.getStartPosition() ...
摘要
: Manually updating or setting the constructor can lead to differrent and sometimes confusing consequences. To prevent this, just define the role of
构造函数
in each specific case. In most cases,
构造函数
is not used and reassignment of it is not necessary.
| 规范 |
|---|
|
ECMAScript (ECMA-262)
The definition of 'Object.prototype.constructor' in that specification. |
| Desktop | Mobile | Server | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
构造函数
|
Chrome 1 | Edge 12 | Firefox 1 | IE 4 | Opera 4 | Safari 1 | WebView Android 1 | Chrome Android 18 | Firefox Android 4 | Opera Android 10.1 | Safari iOS 1 | Samsung Internet Android 1.0 | nodejs Yes |
完整支持
The curly braces here invoke standard macroses defined by the MDN wiki. Checkout here for more info: https://developer.mozilla.org/en-US/docs/MDN/Contribute/Structures/Macros/Commonly-used_macros
Class declaration
Class constructor
Object
Object.prototype.__proto__
Object.prototype.constructor
Object.assign()
Object.create()
Object.defineProperties()
Object.defineProperty()
Object.entries()
Object.freeze()
Object.fromEntries()
Object.getOwnPropertyDescriptor()
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyNames()
Object.getOwnPropertySymbols()
Object.getPrototypeOf()
Object.is()
Object.isExtensible()
Object.isFrozen()
Object.isSealed()
Object.keys()
Object.preventExtensions()
Object.prototype.__defineGetter__()
Object.prototype.__defineSetter__()
Object.prototype.__lookupGetter__()
Object.prototype.__lookupSetter__()
Object.prototype.hasOwnProperty()
Object.prototype.isPrototypeOf()
Object.prototype.propertyIsEnumerable()
Object.prototype.toLocaleString()
Object.prototype.toSource()
Object.prototype.toString()
Object.prototype.valueOf()
Object.seal()
Object.setPrototypeOf()
Object.values()
Function