簡體   English   中英

為什么不能在該構造函數中指定構造函數的原型? JavaScript

[英]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將在每次構造函數調用時重新更新。
    • 這將是一件壞事:我不確定 JavaScript 引擎是否會將相同的詞法對象文字視為 object 的相同實例,或者會創建一個的 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.constructorthis.constructor.prototypeGraph.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 ):

順便說一句,它破壞了 JSON:

請注意,您可能不想這樣做,因為從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的所有實例共享,您可能實際上並不想這樣做。 如果沒有上下文,似乎您需要為每個實例再添加兩個屬性xy

 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM