如何使用javascript Object.defineProperty

如何使用javascript Object.defineProperty,javascript,object,defineproperty,Javascript,Object,Defineproperty,我四处寻找如何使用这种方法,但找不到合适的方法 有人给了我: 但我不明白。主要是,get是我无法得到的(双关语)。它是如何工作的?get是一个函数,当您尝试读取值player.health时会调用该函数,如: console.log(player.health); 事实上,这与: player.getHealth = function(){ return 10 + this.level*15; } console.log(player.getHealth()); 设置get的反面,在指定

我四处寻找如何使用这种方法,但找不到合适的方法

有人给了我:


但我不明白。主要是,
get
是我无法得到的(双关语)。它是如何工作的?

get
是一个函数,当您尝试读取值
player.health
时会调用该函数,如:

console.log(player.health);
事实上,这与:

player.getHealth = function(){
  return 10 + this.level*15;
}
console.log(player.getHealth());
设置get的反面,在指定值时使用。由于没有二传手,似乎不打算为球员的健康分配:

player.health = 5; // Doesn't do anything, since there is no set function defined
一个非常简单的例子:

var播放器={
级别:5
};
Object.defineProperty(玩家“健康”{
get:function(){
返回10+(玩家等级*15);
}
});
console.log(player.health);//85
player.level++;
console.log(player.health);//100
player.health=5;//无所事事

console.log(player.health);//100
基本上,
defineProperty
是一种包含三个参数的方法,即对象、属性和描述符。在这个特殊调用中发生的是
玩家对象的
属性“health”
将被分配到该玩家对象级别的10加15倍。

既然你问了一个问题,让我们一步一步来解决。虽然有点长,但它可能比我写这篇文章节省的时间多得多:

属性是一种面向对象的功能,旨在清晰地分离客户端代码。例如,在某些电子商店中,您可能有如下对象:

function Product(name,price) {
  this.name = name;
  this.price = price;
  this.discount = 0;
}

var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10);  // {name:"T-shirt",price:10,discount:0}
function Product(name,price) {
  var _name=name, _price=price, _discount=0;
  this.getName = function() { return _name; }
  this.setName = function(value) { _name = value; }
  this.getPrice = function() { return _price; }
  this.setPrice = function(value) { _price = value; }
  this.getDiscount = function() { return _discount; }
  this.setDiscount = function(value) { _discount = value; } 
}
然后在您的客户代码(电子商店)中,您可以为您的产品添加折扣:

function badProduct(obj) { obj.discount+= 20; ... }
function generalDiscount(obj) { obj.discount+= 10; ... }
function distributorDiscount(obj) { obj.discount+= 15; ... }
后来,网店老板可能意识到折扣不能超过80%。现在,您需要在客户机代码中查找每次折扣修改,并添加一行

if(obj.discount>80) obj.discount = 80;
然后网店老板可能会进一步改变他的策略,比如“如果客户是经销商,最大折扣可以是90%”。你需要再次在多个地方进行更改,并且你需要记住,在策略更改时,随时更改这些行。这是一个糟糕的设计。这就是为什么封装是OOP的基本原理。如果构造函数是这样的:

function Product(name,price) {
  this.name = name;
  this.price = price;
  this.discount = 0;
}

var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10);  // {name:"T-shirt",price:10,discount:0}
function Product(name,price) {
  var _name=name, _price=price, _discount=0;
  this.getName = function() { return _name; }
  this.setName = function(value) { _name = value; }
  this.getPrice = function() { return _price; }
  this.setPrice = function(value) { _price = value; }
  this.getDiscount = function() { return _discount; }
  this.setDiscount = function(value) { _discount = value; } 
}
然后您可以只更改
getDiscount
(访问器)和
setDiscount
(mutator)方法。问题是大多数成员的行为都像公共变量,只是折扣需要特别注意。但好的设计需要封装每个数据成员,以保持代码的可扩展性。因此,您需要添加大量不起任何作用的代码。这也是一个糟糕的设计,一个样板反模式。有时,您不能在以后将字段重构为方法(eshop代码可能会变大,或者某些第三方代码可能依赖于旧版本),因此样板文件在这里的危害较小。但是,这仍然是邪恶的。这就是为什么属性被引入到许多语言中。您可以保留原始代码,只需将折扣成员转换为具有
get
set
块的属性:

function Product(name,price) {
  this.name = name;
  this.price = price;
//this.discount = 0; // <- remove this line and refactor with the code below
  var _discount; // private member
  Object.defineProperty(this,"discount",{
    get: function() { return _discount; },
    set: function(value) { _discount = value; if(_discount>80) _discount = 80; }
  });
}

// the client code
var sneakers = new Product("Sneakers",20);
sneakers.discount = 50; // 50, setter is called
sneakers.discount+= 20; // 70, setter is called
sneakers.discount+= 20; // 80, not 90!
alert(sneakers.discount); // getter is called
如果您不希望允许客户端代码进行此类欺骗,可以通过三个级别的限制来限制对象:

  • 阻止向对象添加新属性。使用
    Object.isExtensible()
    检查对象上是否使用了该方法。预防措施很肤浅(见下文)
  • 如上所述,无法删除属性(有效地将
    可配置:false设置为所有属性)。使用
    Object.isseald()
    检测对象上的此功能。密封件较浅(见下文)
  • 与上述内容相同,并且无法更改属性(有效地将
    可写:false
    设置为具有数据描述符的所有属性)。Setter的可写属性不受影响(因为它没有可写属性)。冻结是浅冻结:这意味着如果属性是对象,则其属性不会冻结(如果您希望冻结,则应执行类似“深度冻结”的操作,类似于)。使用
    Object.isfronged()
    检测它

如果你只写几行有趣的话,你就不必为此烦恼了。但是如果你想编写一个游戏(正如你在链接问题中提到的),你应该关注好的设计。尝试用谷歌搜索一些关于反模式和代码气味的信息。它将帮助您避免“哦,我需要再次完全重写我的代码!”这样的情况,如果您想大量编写代码,它可以让您免于数月的绝望。祝你好运。

是-否-设置setter和getter的更多功能扩展 这是我的例子Object.defineProperty(obj,name,func)


Object.defineProperty()是一个全局函数。它在声明对象的函数中不可用。您必须静态使用它。

defineProperty是一个对象上的方法,允许您配置属性以满足某些标准。 下面是一个简单的示例,其中employee对象具有两个属性firstName和lastName,并通过覆盖对象上的toString方法来附加这两个属性

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
employee.toString=function () {
    return this.firstName + " " + this.lastName;
};
console.log(employee.toString());
您将获得以下输出:Jameel Moideen

我将通过在对象上使用defineProperty来更改相同的代码

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
    value: function () {
        return this.firstName + " " + this.lastName;
    },
    writable: true,
    enumerable: true,
    configurable: true
});
console.log(employee.toString());
第一个参数是对象的名称,第二个参数是我们要添加的属性的名称,在我们的例子中是toString,最后一个参数是json对象,它的值将是一个函数和三个可写、可枚举和可配置的参数。现在我刚刚声明所有内容都为true

如果您运行该示例,您将得到如下输出:Jameel Moideen

让我们了解为什么我们需要这三个属性,例如可写、可枚举和可配置。

可写

javascript中一个非常恼人的部分是,如果您将toString属性更改为其他属性,例如

var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
    value: function () {
        return this.firstName + " " + this.lastName;
    },
    writable: true,
    enumerable: true,
    configurable: true
});
console.log(employee.toString());
console.log(Object.keys(employee));
var employee = {
    firstName: "Jameel",
    lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
    value: function () {
        return this.firstName + " " + this.lastName;
    },
    writable: false,
    enumerable: false,
    configurable: true
});

//change enumerable to false
Object.defineProperty(employee, 'toString', {

    enumerable: true
});
employee.toString="changed";
console.log(Object.keys(employee));
Object.defineProperty(player, "health", {
    get: function () {
        return 10 + ( player.level * 15 );
    }
});
   const object1 = {};
   Object.defineProperty(object1, 'property1', {
      value: 42,
      writable: false, //If its false can't modify value using equal symbol
      enumerable: false, // If its false can't able to get value in Object.keys and for in loop
      configurable: false //if its false, can't able to modify value using defineproperty while writable in false
   });