我认识到一些 JavaScript 对象具有内部槽属性,在规范中用双方括号 [[ ]] 表示,只能通过方法访问。
例如:
var str = new String('example');
检查变量
str
时,我看到属性 [[PrimitiveValue]] 具有 example 值,但我无法访问此属性,因为它是内部属性。只能通过方法 toString()
来访问它。
我的问题是:如何使用自定义内部属性和访问该属性的方法来实现具有该行为的自定义对象?
var SLOT = require('internal-slot');
var assert = require('assert');
var o = {};
assert.throws(function () { SLOT.assert(o, 'foo'); });
assert.equal(SLOT.has(o, 'foo'), false);
assert.equal(SLOT.get(o, 'foo'), undefined);
SLOT.set(o, 'foo', 42);
assert.equal(SLOT.has(o, 'foo'), true);
assert.equal(SLOT.get(o, 'foo'), 42);
assert.doesNotThrow(function () { SLOT.assert(o, 'foo'); });
[[PrimitiveValue]]
是一个内部属性,您无法通过代码与它交互。但是您可以通过重写 String
方法来模拟 toPrimitive
类的行为:
var str = {
[Symbol.toPrimitive]: (hint) => {
return 'example';
}
};
console.log(`${str}`); // 'example'
toPrimitive
方法在EcmaScript 6.0、7.1.1中定义。它通过一个名为 hint
的参数调用,该参数可以是 'default'
、'string'
或 'number'
。您可以根据提示返回不同的值,以获得一个行为类似于字符串和数字的对象:
var str = {
[Symbol.toPrimitive]: (hint) => {
if (hint === 'number') return 111;
return 'example';
}
};
console.log(`${str}`); // 'example'
console.log(str * 10); // 1110
我认为你无法创建真正的内部属性/插槽。
来自 262.ecma-international.org:
在 ECMAScript 中,对象的实际语义是通过称为内部方法的算法指定的。 ECMAScript 引擎中的每个对象都与一组定义其运行时行为的内部方法相关联。这些内部方法 不是 ECMAScript 语言的一部分。本规范定义它们纯粹是为了说明目的(强调添加了 KooiInc)。
但是,您可以创建具有可通过您定义的方法访问的内部值的对象 - 使用工厂函数。例如:
function myNumbersFactory() {
return function(defaultValue = 0) {
const internalHistory = [];
const internalDefaultValue = defaultValue;
return Object.freeze({
set value(val) {
const nr = parseInt(val);
internalHistory.push(isNaN(nr) ? internalDefaultValue : nr); },
get value() { return internalHistory.slice(-1).pop(); },
get default() { return `default value ${internalDefaultValue}`; },
get history() { return [...internalHistory]; }
});
};
}
const numbers = myNumbersFactory();
const myNumbers = numbers();
const myNumbers2 = numbers(42);
// myNumbers
let i = 0;
myNumbers.value = `will be set to internalDefaultValue (0)`;
while(++i < 6) { myNumbers.value = i; }
myNumbers.value = 42;
console.log(`* myNumbers\n${
Object.keys(myNumbers)
.map(k => `${k}: ${myNumbers[k]}`).join(`\n`)}`);
// myNumbers2
i = -1;
while(++i < 6) { myNumbers2.value = i; }
myNumbers2.value = `will be set to internalDefaultValue (42)`;
console.log(`* myNumbers2\n${
Object.keys(myNumbers2)
.map(k => `${k}: ${myNumbers2[k]}`).join(`\n`)}`);
.as-console-wrapper {
max-height: 100% !important;
}
您可以在 JavaScript 中创建一个具有私有属性的自定义对象以及一个模仿内部插槽行为的访问它的方法。例如:
function CustomObject(value) {
const primitiveValue = value;
this.getValue = function () {
return primitiveValue;
};
}
const obj = new CustomObject('example');
console.log(obj.getValue());
以下是有关此主题的文档的链接: