[英]Why can't specify the constructor's prototype inside that constructor? JavaScript
function Graph() { this.vertices = []; this.edges = []; Graph.prototype = { x: 0, y: 0 }; }; console.log(Graph.prototype); var g = new Graph(); console.log(gx); console.log(gy);
在構造函數Graph中,這是一個玩具示例,我嘗試將 object 分配給它的原型。
function Graph() {
this.vertices = [];
this.edges = [];
Graph.prototype = {
x : 0,
y : 0
};
}
當我使用以下方法查看 Graph.prototype 時:
console.log(Graph.prototype);
我發現 Graph.prototype 仍然是默認原型。 我沒有對其進行任何更改。
為什么我不能在該構造函數中指定構造函數的原型? 有人能告訴我背后的真正原因嗎?
非常感謝!
我假設您正在調用console.log(Graph.prototype);
在運行Graph
構造函數之前。
請記住,JavaScript 的object
值的正式類型系統使用可變原型作為實現對象繼承的一種方式,並且這些prototype
object 引用也可以完全換出並在運行時重新定義,即使在使用已經存在的 ZA8CFDE6331BD59EB666Z 值之后更難推斷 JavaScript 程序的類型安全性(因此 TypeScript 仍然不能代表每個有效的 Z686155AF75A60A0F6E9D80C1F7EDD203E9Z 程序,截至 2 月初)。
例如,考慮:
// 1. Declare `Foo` constructor.
function Foo() {
this.bar = 123;
}
// 2. Extend the prototype:
Foo.prototype.baz = 456;
// 3. Create a new instance of Foo:
const foo1 = new Foo();
console.log( "foo1.baz == %o", foo1.baz ); // "456"
// 4. Change the prototype:
delete Foo.prototype.baz;
Foo.prototype.qux = "abc";
// 5. Create a second new instance of Foo:
const foo2 = new Foo();
console.log( "foo2.qux == %o", foo2.qux ); // "abc"
// 6. Because Foo's prototype is changed, `foo1.baz` is no-longer valid:
console.log( "foo1.baz == %o", foo1.baz ); // "undefined"
所以foo1
的形式類型(即foo1
的屬性集)完全是懸而未決的——這就是為什么在創建使用該原型的任何對象之前永遠不要在 JavaScript 中重新定義prototype
是個好主意。
有了這個背景...
“為什么我不能在那個構造函數中指定構造函數的原型?有人能告訴我它背后的真正原因嗎?”
從技術上講,您可以,但它不會按照您希望的方式工作:
Foo.prototype
(或Graph.prototype
在您的情況下)只會在且僅在進行第一次new Foo()
調用時設置。Foo.prototype
object將在每次構造函數調用時重新更新。
如果您想在項目代碼庫中的同一“位置”簡潔地定義原型,那么只需在 Constructor function 定義之后立即定義它,這也意味着Graph.prototype
將按預期更新,而無需實際創建任何new Graph
對象。
所以這就是你目前正在做的事情:
function Graph() {
this.vertices = [];
this.edges = [];
Graph.prototype = {
x: 0,
y: 0
};
}
console.log( Graph.prototype ); // "{}" or "{constructor: f}"
但是,如果您在定義構造函數后立即更新原型,它將按預期工作:
function Graph() {
this.vertices = [];
this.edges = [];
}
Graph.prototype = {
x: 0,
y: 0
};
console.log( Graph.prototype ); // "{x: 0, y: 0}"
this.constructor
、 this.constructor.prototype
和Graph.prototype
。在構造函數 function 內部:
this
指的是新創建的對象實例。this.constructor
指的是構造函數 function ( function TypeName()
)。this.prototype
未定義,因為prototype
僅在(構造函數)函數上定義。 TypeName.prototype
:
默認情況下,這是一個具有以下定義的 object:
{ constructor: f } // where `f` is `function TypeName`.
TypeName.prototype
在任何地方(甚至在構造函數內部)被重新定義,那么它將等於該重新定義,但僅在執行重新定義的代碼實際執行之后(所以不是在 JavaScript 代碼僅被加載和解析時)。this.constructor.prototype
也指TypeName.prototype
(即TypeName.prototype === this.constructor.prototype
): 請注意,您可能不想這樣做,因為從prototype
繼承的 object 屬性不被視為“自己的”屬性,因此被排除在JSON.stringify
output 之外,例如:
var g = new Graph();
var json = JSON.stringify( g );
console.log( json ); // "{"vertices":[],"edges":[]}"
幸運的是,您可以使用一種解決方法進行序列化(但實現prototype
JSON.parse
是讀者的練習):
function JSON_stringify_for_prototypes( obj ) {
const flat = Object.create( obj );
for( const key in flat ) { // `for( x in y )` includes non-"own" properties.
flat[key] = flat[key]; // This looks silly, but this actually causes each property to be marked as "own" in `flat`.
}
return JSON.stringify( flat );
}
您需要更新Graph.prototype
而不是用新的 object 替換它,並且您需要在調用構造函數之后而不是之前調用console.log(Graph.prototype)
:
function Graph() { this.vertices = []; this.edges = []; Graph.prototype.x = 0; Graph.prototype.y = 0; }; var g = new Graph(); console.log(Graph.prototype); console.log(gx); console.log(gy);
但正如其他人所說,由於原型由Graph
的所有實例共享,您可能實際上並不想這樣做。 如果沒有上下文,似乎您需要為每個實例再添加兩個屬性x
和y
:
function Graph() { this.vertices = []; this.edges = []; this.x = 0; this.y = 0; }; var g = new Graph(); console.log(g); console.log(gx); console.log(gy);
在我看來,你真的只是想創建一個設置 static 屬性的方法。 以下是 go 關於嘗試在 JavaScript 中復制此內容的方式:
function Graph(){ this.vertices = []; this.edges = []; this.staticXY = (x = 0, y = 0)=>{ const p = this.constructor.prototype; px = x; py = y; return this; } if(this.x === undefined && this.y === undefined)this.staticXY(); } const graph1 = new Graph; graph1.staticXY(2, 8); graph1.x = 3; graph1.y = 1; console.log(graph1.x, graph1.y); // static remains anyways const graph2 = new Graph; console.log(graph2.x, graph2.y);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.