如何使用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
});