Javascript Object.defineProperty与构造函数和原型

Javascript Object.defineProperty与构造函数和原型,javascript,properties,Javascript,Properties,我刚刚发现,而且我最熟悉C#我想在我的构造函数中使用访问器属性,例如: 函数库(id){ var _id=id; Object.defineProperty(这个“ID”{ get:function(){return\u id;}, 集合:函数(值){u id=value;} }) } 派生函数(id、名称){ var _name=名称; Base.call(这个,id); Object.defineProperty(此“名称”{ get:function(){return\u name;},

我刚刚发现,而且我最熟悉C#我想在我的构造函数中使用访问器属性,例如:

函数库(id){
var _id=id;
Object.defineProperty(这个“ID”{
get:function(){return\u id;},
集合:函数(值){u id=value;}
})
}
派生函数(id、名称){
var _name=名称;
Base.call(这个,id);
Object.defineProperty(此“名称”{
get:function(){return\u name;},
集合:函数(值){u name=value;}
})
}
Derived.prototype=Object.create(Base.prototype);
派生的构造函数=派生的;
var b=新基数(2);
var d=新衍生(4,“Alexander”);
控制台日志(b.ID);
console.log(d.ID,d.Name);
d、 ID=100;
console.log(d.ID,d.Name)
有人能解释一下哪种方法适合我吗

不要使用
Object.defineProperty
。这里绝对不需要属性描述符,而且getter和setter也不做任何特殊的事情。只需使用一个简单的法线属性。它将比您关心的任何其他东西都更快、更好地优化

function Base(id) {
    this.ID = id;
}

function Derived(id, name) {
    Base.call(this,id);
    this.Name = name;
}

Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;

如果对于每个对象都重新生成函数,那么我可能需要考虑第二种方法:


是的,没错,但可以忽略不计。你不应该过早地进行微观优化。您将知道何时真正需要它,然后仍然可以轻松地交换实现。在此之前,请使用简洁明了的代码。

我参加聚会可能会晚一点,但这里有几件小事我想指出

首先,您要在构造函数中定义自己的属性,这对于特定于实例的属性和不应与其他实例共享的属性很好,但对于getter、setter和方法则不行。相反,您应该在函数的原型上定义它们

我理解你这样的问题

你如何打造真正的私人房产? 它很简单,并且可以在所有浏览器中使用。首先,我们将详细介绍Object.defineProperty和派生的Object.create、Object.defineProperties

function MyConstructor() { /* example function or "class" */ }
javascript对象定义的原型 现代javascript允许一些“语法糖”来声明类,但是每一个自豪的开发者都应该理解它是如何工作的

首先没有课程。Javascript没有类。它有原型,而不是类。这些课程很像课堂,所以在我天真的固执中,我花了好几节课去寻找真相,我反对又反对——我一路走到底。没有课

成为对象。如果
您的原型
无法回答问题,则会询问您的
原型
,然后会询问您的
原型
,直到没有更多原型可问

所有这些原型仍然是对象。该算法说明了这一点:

// Friendly version
function askQuestion(askee, question) {
  do {
    if (askee.hasOwnProperty(question)) {
      return askee[question];
    }
  } while (askee = Object.getPrototypeOf(askee))
}
ECMAScript 6(无聊) 为了说明“现代javascript”的语法,我将离题:

class Tortoise extends Turtle {

  constructor() {
    while (this.__proto__) {
      this.__proto__ = Object.getPrototypeOf(this.__proto__);
    }
  }

  #privateProperty = "This isn't a comment"

  get __proto__() { return Object.getPrototypeOf(this); }

  set __proto__(to) { Object.setPrototypeOf(this, to); }

}
这并不适用于所有浏览器。它在任何浏览器中都不起作用。这只是为了显示语法

有人声称,上述内容只是老派javascript之上的语法糖,但当涉及到扩展本机对象时,它怀疑这其中有更多的东西

即使“现代javascript”(ECMAScript 6)允许我们编写如上所述的类,您也应该理解它

此外,现代javascript加上Internet Explorer 11的顽固性,迫使我们使用巴别塔(babel),这是一个非常棒的工具,具有难以置信的能力,非常先进、灵活,以至于这种工具存在的可能性,仅仅是巧合,是极不可能的

工具的存在本身就是上帝存在的证明,我很遗憾地说,这也证明了上帝不存在


WTF??见和,和

打开引擎盖 不要在构造函数中创建可重用属性。许多实例使用的函数不应在构造函数中赋值

真实版本

function Base(id) {
  // GOOD
  this.id = id;

  // GOOD, because we need to create a NEW array for each
  this.tags = [];

  // Okay, but could also just be in the prototype
  this.numberOfInteractions = 0;

  // BAD
  this.didInteract = function() {
    this.numberOfInteractions++;
  }
}
function Base(id) {
  this.id = id;
  this.tags = [];
}
Base.prototype.numberOfInteractions = 0;
Base.prototype.didInteract = function() {
  this.numberOfInteractions++;
}
糖衣

class Base {
  constructor(id) {
    // GOOD
    this.id = id;

    // GOOD, because we need to create a NEW array for each
    this.tags = [];

    // Okay, but could also just be in the prototype
    this.numberOfInteractions = 0;

    // BAD
    this.didInteract = function() {
      this.numberOfInteractions++;
    }
  }
}
改进的真实版本

function Base(id) {
  // GOOD
  this.id = id;

  // GOOD, because we need to create a NEW array for each
  this.tags = [];

  // Okay, but could also just be in the prototype
  this.numberOfInteractions = 0;

  // BAD
  this.didInteract = function() {
    this.numberOfInteractions++;
  }
}
function Base(id) {
  this.id = id;
  this.tags = [];
}
Base.prototype.numberOfInteractions = 0;
Base.prototype.didInteract = function() {
  this.numberOfInteractions++;
}
改良糖衣版

function Base(id) {
  // GOOD
  this.id = id;

  // GOOD, because we need to create a NEW array for each
  this.tags = [];

  // Okay, but could also just be in the prototype
  this.numberOfInteractions = 0;

  // BAD
  this.didInteract = function() {
    this.numberOfInteractions++;
  }
}
function Base(id) {
  this.id = id;
  this.tags = [];
}
Base.prototype.numberOfInteractions = 0;
Base.prototype.didInteract = function() {
  this.numberOfInteractions++;
}
如果您坚持使用sugar,并且在编写代码之后喜欢编写更多的代码行和一些额外的工作,那么您可以安装babel并编写如下代码

它会使脚本文件稍微变大和变慢,除非你真的不需要支持所有的浏览器

class Base {

  constructor(id) {
    this.id = id;
    this.tags = [];
  }

  numberOfInteractions = 0;

  didInteract() {
    this.numberOfInteractions++;
  }

}
遗传ABC EcmaScript中的继承非常简单,只要您真正理解它

TLDR:如果您希望上面的类扩展另一个类,您可以这样做:

Object.setPrototypeOf(Base.prototype, Parent.prototype);
这应该适用于所有地方。它本质上是
Base.prototype.\uuuu proto\uuu=Parent.prototype

Base.prototype
vs实例prototype

var myInstance = new MyConstructor();

myInstance instanceof MyConstructor;
// this is TRUE because
Object.getPrototypeOf(myInstance) === MyInstance.prototype
javascript中的所有对象都有一个实例原型。它是为对象属性搜索“默认值”的实例原型

function MyConstructor() { /* example function or "class" */ }
上面的语句创建了一个名为
MyConstructor
对象,该对象有一个引用
函数的实例原型。同时,它也是一个可以调用的函数

这很重要:

MyConstructor instanceof Function;
// is TRUE because
Object.getPrototypeOf(MyConstructor) === Function.prototype

// this is NOT TRUE
MyConstructor.prototype === Function.prototype
因为这种细微的差别

var myInstance = new MyConstructor();

myInstance instanceof MyConstructor;
// this is TRUE because
Object.getPrototypeOf(myInstance) === MyInstance.prototype
现在,
MyConstructor.prototype
只是一个空对象(它有一个引用
object.prototype
)的实例原型)

访问属性

在javascript中,对象只有属性。它们没有方法,但具有指向函数的属性

当您尝试访问上的属性时