gpt4 book ai didi

javascript - 如何使用 javascript Object.defineProperty

转载 作者:IT老高 更新时间:2023-10-28 13:16:55 25 4
gpt4 key购买 nike

我四处寻找如何使用 Object.defineProperty 方法,但找不到任何像样的东西。

有人给我this snippet of code :

Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
})

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

最佳答案

既然你问了 similar question ,让我们一步一步来。它有点长,但它可能比我花在写这个上的时间节省更多的时间:
属性(property)是一种 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 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) {
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) 方法。问题是大多数成员的行为就像公共(public)变量,只是折扣在这里需要特别注意。但是好的设计需要封装每个数据成员以保持代码的可扩展性。所以你需要添加很多什么都不做的代码。这也是一个糟糕的设计,一个样板的反模式。有时你不能只是在以后将字段重构为方法(eshop 代码可能会变大或者一些第三方代码可能依赖于旧版本),所以这里的样板是不那么邪恶的。但是,它仍然是邪恶的。这就是为什么将属性引入许多语言的原因。您可以保留原始代码,只需将折扣成员(member)转换为带有 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
请注意最后一行:正确折扣值的责任从客户代码(电子商店定义)转移到产品定义。产品负责保持其数据成员的一致性。好的设计是(粗略地说)代码的工作方式与我们的想法相同。
这么多关于属性。但是 javascript 与纯面向对象的语言(如 C#)不同,并且对功能进行了不同的编码:
在 C# 中 ,将字段转换为属性是 breaking change ,因此公共(public)字段应编码为 Auto-Implemented Properties如果您的代码可能用于单独编译的客户端。
在 Javascript 中 ,标准属性(具有上述 getter 和 setter 的数据成员)由访问器描述符(在您的问题中的链接中)定义。独占地,您可以使用数据描述符(因此您不能使用 i.e. value 并在同一属性上设置):
  • 访问器描述符 = get + set(见上面的例子)
  • 获取 必须是一个函数;它的返回值用于读取属性;如果未指定,则默认值为 undefined,其行为类似于返回 undefined
  • 的函数。
  • 必须是一个函数;在给属性赋值时,它的参数用 RHS 填充;如果未指定,则默认值为 undefined,其行为类似于空函数

  • 数据描述符 = 值 + 可写(见下面的例子)
  • 默认未定义;如果可写、可配置和可枚举(见下文)为真,则该属性的行为类似于普通数据字段
  • 可写 - 默认为假;如果不为真,则该属性是只读的;尝试写入被忽略,没有错误*!


  • 两个描述符都可以具有以下成员:
  • 可配置 - 默认为假;如果不为真,则无法删除该属性;尝试删除被忽略,没有错误*!
  • 可枚举 - 默认为假;如果为真,它将在 for(var i in theObject) 中迭代;如果为 false,它将不会被迭代,但它仍然可以作为公共(public)访问

  • * 除非在 strict mode - 在这种情况下 JS 会停止执行 TypeError 除非它被捕获在 try-catch block
    要读取这些设置,请使用 Object.getOwnPropertyDescriptor() .
    通过例子学习:
    var o = {};
    Object.defineProperty(o,"test",{
    value: "a",
    configurable: true
    });
    console.log(Object.getOwnPropertyDescriptor(o,"test")); // check the settings

    for(var i in o) console.log(o[i]); // nothing, o.test is not enumerable
    console.log(o.test); // "a"
    o.test = "b"; // o.test is still "a", (is not writable, no error)
    delete(o.test); // bye bye, o.test (was configurable)
    o.test = "b"; // o.test is "b"
    for(var i in o) console.log(o[i]); // "b", default fields are enumerable
    如果您不希望允许客户端代码进行此类作弊,您可以通过三个级别的限制来限制对象:
  • Object.preventExtensions(yourObject) 防止将新属性添加到 yourObject。使用 Object.isExtensible(<yourObject>)检查是否在对象上使用了该方法。预防很浅(阅读下文)。
  • Object.seal(yourObject) 同上,属性不能被删除(有效地将 configurable: false 设置为所有属性)。使用 Object.isSealed(<yourObject>)检测物体上的这个特征。密封很浅(阅读下文)。
  • Object.freeze(yourObject) 同上,属性不能更改(有效地将 writable: false 设置为所有带有数据描述符的属性)。 Setter 的可写属性不受影响(因为它没有)。卡住是浅的:这意味着如果属性是对象,它的属性不会被卡住(如果你愿意,你应该执行类似“深度卡住”的操作,类似于 deep copy - cloning )。使用 Object.isFrozen(<yourObject>)检测它。

  • 如果你只写几行有趣的,你就不需要为此烦恼。但是如果你想编写一个游戏(正如你在链接问题中提到的),你应该关心好的设计。尝试在 google 上搜索有关反模式和代码异味的信息。它将帮助您避免诸如“哦,我需要再次完全重写我的代码!”之类的情况,如果您想编写大量代码,它可以为您节省数月的绝望。祝你好运。

    关于javascript - 如何使用 javascript Object.defineProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18524652/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com