Object.defineProperty
方法的相关信息,但是没有找到什么有用的东西。有人给我提供了这段代码片段:
Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
})
但我不理解它。主要是,我无法获得 get
(双关语意)。它是如何工作的?
Object.defineProperty
方法的相关信息,但是没有找到什么有用的东西。Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
})
但我不理解它。主要是,我无法获得 get
(双关语意)。它是如何工作的?
既然你提了一个类似的问题,我们就一步一步来解决吧。这会有点长,但比我写这个答案花费的时间要多得多:
属性是面向对象编程的一个特性,旨在清晰地分离客户端代码。举个例子,在某个电子商务网站中,你可能会有像这样的对象:
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; ... }
if(obj.discount>80) obj.discount = 80;
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 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
class
语法,这是一个“特殊函数”,可以为代码提供相同的功能。class Product {
constructor(name, price) {
this.name = name;
this.price = price;
}
#discount = 0; // # = private member in classes
get discount() { return this.#discount; }
set discount(v) { this.#discount = v; if(this.#discount>80) this.#discount = 80; }
}
这两种描述符都可以具有以下成员:
for(var i in theObject)
中进行迭代;如果为false,则不会进行迭代,但仍然可以作为公共属性访问* 除非在严格模式下 - 在这种情况下,JS会停止执行并抛出TypeError,除非它在try-catch块中捕获
要读取这些设置,请使用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.isExtensible(<yourObject>)
来检查该方法是否在对象上使用过。这种防止是浅层的(请参阅下文)。configurable: false
)。使用 Object.isSealed(<yourObject>)
来检测对象上的此特性。这种封闭是浅层的(请参阅下文)。writable: false
)。Setter 的 writable 属性不受影响(因为它没有该属性)。冻结是浅层的:这意味着如果属性是对象,则其属性不会被冻结(如果您希望冻结,请执行类似于深拷贝 - 克隆的“深度冻结”操作)。使用 Object.isFrozen(<yourObject>)
来检测它。function Product(name,price) { this.name = name; this.price = price; var _discount; // 私有成员 Object.defineProperty(this,"discount",{ get: function() { return _discount; }, set: function(value) { _discount = value; if(_discount>80) _discount = 80; } }); } var sneakers = new Product("Sneakers",20); sneakers.discount = 50; // 调用setter,值为50 sneakers.discount+= 20; // 调用setter,值为70 sneakers.discount+= 20; // 值为80,而不是90! alert(sneakers.discount); // 调用getter
- abu abuget
是一个函数,当你尝试读取值player.health
时会调用它,例如:
console.log(player.health);
它实际上与以下内容没有太大区别:
player.getHealth = function(){
return 10 + this.level*15;
}
console.log(player.getHealth());
get 的反义词是 set,当你需要给某个值赋值时会使用 set。由于没有 setter,因此似乎不打算将玩家的健康值赋值:
player.health = 5; // Doesn't do anything, since there is no set function defined
var player = {
level: 5
};
Object.defineProperty(player, "health", {
get: function() {
return 10 + (player.level * 15);
}
});
console.log(player.health); // 85
player.level++;
console.log(player.health); // 100
player.health = 5; // Does nothing
console.log(player.health); // 100
()
来调用它...我不明白他们发明这个东西的想法是什么。函数完全一样:https://jsbin.com/bugipi/edit?js,console,output - vsyncdefineProperty 是 Object 上的一个方法,可以让你配置属性以满足某些标准。 以下是一个简单的示例,使用一个名为 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对象,其值将成为一个具有三个参数(writable、enumerable和configurable)的函数。现在,我将所有内容都声明为true。
如果您运行示例,您将得到输出:Jameel Moideen
让我们了解为什么我们需要三个属性,例如writable,enumerable和configurable。
writable
Javascript中非常讨厌的部分之一是,如果您将toString属性更改为其他内容,例如:
如果再次运行此操作,则会出现错误。让我们将writable更改为false。如果再次运行相同的操作,您将获得正确的输出“Jameel Moideen”。该属性将防止后面覆盖此属性。
enumerable
如果您打印对象内的所有键,则可以看到所有属性,包括toString。
console.log(Object.keys(employee));
如果把enumerable设为false,就可以隐藏toString属性,让其他人看不到。如果再次运行,将会输出firstName和lastName。
configurable
如果稍后有人重新定义对象,例如将enumerable设置为true并运行它,你就会看到toString属性再次出现。
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));
您可以将configurable设置为false来限制此行为。
基本上,defineProperty
是一个方法,它需要三个参数 - 一个对象,一个属性和一个描述符。在这个特定的调用中发生的是,player
对象的"health"
属性被分配为10加上该玩家对象级别的15倍。
Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
});
Object.defineProperty
用于在 player 对象上创建一个新属性。 Object.defineProperty
是 JS 运行时环境中本地存在的函数,它接受以下参数:
Object.defineProperty(obj, prop, descriptor)
描述符对象是有趣的部分。在这里,我们可以定义以下内容:
<boolean>
: 如果为true
,则属性描述符可以被更改并且该属性可以从对象中删除。如果configurable为false
,则在Object.defineProperty
中传递的描述符属性不能被更改。<boolean>
: 如果为true
,则可以使用赋值运算符覆盖该属性。<boolean>
: 如果为true
,则可以在for...in
循环中迭代该属性。同时,在使用Object.keys
函数时,该键将存在。如果该属性为false
,则不会在for..in
循环中迭代,并且在使用Object.keys
时不会显示。<function>
: 每当需要该属性时调用的函数。而不是直接给出值,调用此函数并返回的值作为属性的值。<function>
: 每当分配该属性时调用的函数。而不是设置直接值,调用此函数并使用返回的值来设置属性的值。const player = {
level: 10
};
Object.defineProperty(player, "health", {
configurable: true,
enumerable: false,
get: function() {
console.log('Inside the get function');
return 10 + (player.level * 15);
}
});
console.log(player.health);
// the get function is called and the return value is returned as a value
for (let prop in player) {
console.log(prop);
// only prop is logged here, health is not logged because is not an iterable property.
// This is because we set the enumerable to false when defining the property
}
是的,不再为设置setter和getter函数进行更多的功能扩展。 这是我的例子:Object.defineProperty(obj,name,func)
var obj = {};
['data', 'name'].forEach(function(name) {
Object.defineProperty(obj, name, {
get : function() {
return 'setter & getter';
}
});
});
console.log(obj.data);
console.log(obj.name);
import { CSSProperties } from 'react'
import { BLACK, BLUE, GREY_DARK, WHITE } from '../colours'
export const COLOR_ACCENT = BLUE
export const COLOR_DEFAULT = BLACK
export const FAMILY = "'Segoe UI', sans-serif"
export const SIZE_LARGE = '26px'
export const SIZE_MEDIUM = '20px'
export const WEIGHT = 400
type Font = {
color: string,
size: string,
accent: Font,
default: Font,
light: Font,
neutral: Font,
xsmall: Font,
small: Font,
medium: Font,
large: Font,
xlarge: Font,
xxlarge: Font
} & (() => CSSProperties)
function font (this: Font): CSSProperties {
const css = {
color: this.color,
fontFamily: FAMILY,
fontSize: this.size,
fontWeight: WEIGHT
}
delete this.color
delete this.size
return css
}
const dp = (type: 'color' | 'size', name: string, value: string) => {
Object.defineProperty(font, name, { get () {
this[type] = value
return this
}})
}
dp('color', 'accent', COLOR_ACCENT)
dp('color', 'default', COLOR_DEFAULT)
dp('color', 'light', COLOR_LIGHT)
dp('color', 'neutral', COLOR_NEUTRAL)
dp('size', 'xsmall', SIZE_XSMALL)
dp('size', 'small', SIZE_SMALL)
dp('size', 'medium', SIZE_MEDIUM)
export default font as Font
Object.defineProperty() 是一个全局函数。它不能在声明对象的函数内部使用。否则,您必须静态地使用它...
Object.defineProperty(Array.prototype, "last", {
get: function() {
if (this[this.length -1] == undefined) { return [] }
else { return this[this.length -1] }
}
});
console.log([1,2,3,4].last) //returns 4
在对象上直接定义一个新属性,或者修改对象上的现有属性,并返回该对象。
注意:您需要直接在 Object 构造函数上调用此方法,而不是在 Object 类型的实例上调用。
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
});
关于定义属性的简单解释。