在JavaScript中为属性添加别名

时间:2016-09-10 22:41:47

标签: javascript variables properties

我认为这很简单,

是否有一种简单的方法为属性添加辅助名称(我认为这是特定于字符串的 - 我不确定),即。,

c = length // this line pseudo code

'hello world'.length // returns 11
'hello world'.c      // this line is pseudo code, meant to return 11

在上面的示例中,为属性长度创建了一个别名。这可以用JavaScript吗?

2 个答案:

答案 0 :(得分:37)

<强> 1。使用括号表示法

使用bracket notation,您可以像这样访问该属性:

'hello world'[c]

如果'hello world'.lengthc为字符串,则与'length'相同。

&#13;
&#13;
var c = 'length';
console.log('hello world'[c]);
&#13;
&#13;
&#13;

唯一的区别是该属性是一个字符串。括号表示法是属性访问者。

<强> 2。使用Object.defineProperty()

现在,如果你想要一个别名:

&#13;
&#13;
Object.defineProperty(String.prototype, 'c', {
    get: function() {
        return this.length;
    }
});

console.log("hello world".c);
&#13;
&#13;
&#13;

以上使用Object.defineProperty来定义现有对象String的prototype对象的属性。这样,字符串的所有实例都将具有此新属性。根据文件:

  

Object.defineProperty()方法直接在对象上定义新属性,或修改对象上的现有属性,并返回该对象。

     

<强>语法

     

Object.defineProperty(obj, prop, descriptor)

obj是要修改的对象,prop是新属性或现有属性,descriptor是新属性或现有属性的描述符。

因此,上面定义了对象String.prototype的属性,名称为c。它的描述符是一个get函数,它返回this的长度。在上面的示例中,this引用字符串,因此它返回字符串的长度。您可以阅读有关getter here的更多信息。

也可以通过更改为适用的原型(obj)来定义更多类型,例如使用Object.prototype。但是,这有潜在的问题,因为尝试在没有长度属性的对象上返回this.length将返回undefined,如here所示。您也可以使用Object.defineProperties一次定义多个属性。

答案 1 :(得分:6)

为了扩展@ AndrewLi的答案,你可以使用Object.defineProperty()做一些别名的事情。

  • 只读别名(与他的回答相同)
  • 同步别名在修改后修改了
  • 默认别名读取或“默认为”来源直到更改(此时关系被破坏)

我会将它们编写为将对象与属性相关联的函数, sProp 以及带有属性的目标对象 tProp 即可。源和目标可以是同一个对象(允许属性成为同一对象上另一个属性的别名),但这不是必需的。此外,源(或目标)可以是原型(如Object.prototype,String.prototype等)。

“正常”分配

这个不是别名,也不是Object.defineProperty()。目标被指定为源的 VALUE ,而不是对其的引用。这意味着当源更改时,目标不会。

function assign(target, tProp, source, sProp) {
  target[tProp] = source[sProp];
  return target;
}

let myTarget = {}
let mySource = {b: 12}

myTarget = assign(myTarget, 'a', mySource, 'b')

// "alias" was assigned source value
console.log('"alias":',myTarget.a) // 12

// changes to source independent of "alias"
mySource.b = 13
console.log("source:", mySource.b) // 13
console.log('"alias":', myTarget.a) // still 12

只读别名(以上解决方案)

当属性定义没有setter时,它实际上是一个只读值。对source属性的更改将反映在别名中;但是,您无法设置别名的值。

function read(target, tProp, source, sProp){
  Object.defineProperty(target, tProp, {
    enumerable: true,
    configurable: true,
    get(){
      return source[sProp];
    }
  })
  return target;
}

let myTarget = {}
let mySource = {b: 12}

myTarget = read(myTarget, 'a', mySource, 'b')

// Alias gets value from source
console.log("alias:", myTarget.a) // 12

// No setter effectively means read-only
myTarget.a = 15
console.log("alias:", myTarget.a) // 12

// Changes to source are seen in target
mySource.b = 15
console.log("source:", mySource.b) //15
console.log("target:", myTarget.a) //15

同步别名

此别名修改上面的只读版本,以便在设置别名(目标)属性时设置source属性。通过这种方式,源和目标始终保持同步。

function sync(target, tProp, source, sProp){
  Object.defineProperty(target, tProp, {
    enumerable: true,
    configurable: true,
    get(){
      return source[sProp];
    },
    set(value){
      source[sProp] = value;
    }
  })
  return target;
}

let myTarget = {}
let mySource = {b: 12}

myTarget = sync(myTarget, 'a', mySource, 'b')

// Alias gets value from source
console.log("alias:", myTarget.a) // 12

// Changing alias' value modifies the source
myTarget.a = 15
console.log("alias:", myTarget.a) // 15
console.log("source:", mySource.b) // 15

// Changing source modifies alias still
mySource.b = 20
console.log("source:", mySource.b) // 20
console.log("alias:", myTarget.a) // 20

Alias as Default

这允许您默认别名/目标值,直到另行更新。与只读的情况不同,您可以更改别名/目标值,但与同步不同,当您更改别名时,您不会更新源 - 而是别名变为常规值。

function setDefault(target, tProp, source, sProp){
  Object.defineProperty(target, tProp, {
    enumerable: true,
    configurable: true,
    get(){
      return source[sProp];
    },
    set(value){
      delete target[tProp];
      target[tProp] = value;
    }
  })
  return target;
}

let myTarget = {}
let mySource = {b: 12}

myTarget = setDefault(myTarget, 'a', mySource, 'b')

// Alias gets value from source
console.log('alias:', myTarget.a) // 12

// Changing source modifies alias still
mySource.b = 15
console.log('source:', mySource.b) // 15
console.log('alias:', myTarget.a) // 15

// Changing alias' value DOES NOT modify source
myTarget.a = 20
console.log("alias:", myTarget.a) // 20
console.log("source:", mySource.b) // 15

// The relationship between source and alias is BROKEN
mySource.b = 100
console.log("source:", mySource.b) // 100
console.log("alias:", myTarget.a) // 20