7

在下面的示例中,如何在 JavaScript 对象表示法 (JSON) 中使用“this”关键字?

{
    firstName: "Foo",
    lastName: "Bar",
    fullName: function () {
        return this.firstName + " " + this.lastName;
    }
}

上面的代码既不能使用this关键字,也不能没有它。这是为什么?唯一可行的解​​决方案是将 JSON 对象分配给一个变量并在代码中使用该变量。

有没有类似于“this”关键字的东西可以用来代替它?

欢迎任何建议。

编辑:正如下面评论中所述,它不是 JSON,而是“javascript 对象文字”。谢谢你的提示。尽管如此,我的问题仍然有效(对于 javascript 对象文字)。

无效:上面的代码按预期工作,因此 fullName() 返回“Foo Bar”。

4

3 回答 3

15

如果我理解它,这实际上可能不是一个无效的问题(只是一个问得不好,有一些错误的问题),并且真的可能有点有趣。JSON 用词不当是一个令人分心的不幸错误,但实际上,他在问如何动态地让一个属性等于其他属性的动态结果——即,为什么不

x = {
  a: "hello",
  b: " ",
  c: "world",
  d: this.a + this.b + this.c
}

导致

x.d === "hello world"

?

相反,您发现的是thiswindow那里。这向我们展示了这this只是从函数内部获得的东西,而不是我们可以在该上下文之外依赖的内在关系引用。

这显然是为什么提问者然后使用一个函数来访问this. 但是,我认为问题在于你得到了一个你必须调用的函数,他实际上想要文本。(我可能会在那里推断一下,不确定。)

有人可能会想只使用 IIFE,但这也行不通:

x = {
  a: "hello",
  b: " ",
  c: "world",
  d: (function() { this.a + this.b + this.c })()
}

x.d === NaN  // undefined + undefined + undefined

发生的情况是,当我们调用 IIFE 时,我们创建了一个新的作用域,带有一个新的this-- 而且,它只会在对象初始化时运行一次,并且不会动态地反映那些其他值的变化。

因为他说'我们必须将对象分配给一个变量然后使用它',所以我认为他找到了一种解决方法,您只需声明它两次,如果您指的是全局属性,第二次它就可以工作(所以,x.a + x.b),并提供了错误的例子。

所有这些都表明词法作用域在这里超越了动态作用域。人们可能会考虑尝试解决此问题的另一种天真方式是这样的:

x = {
  a: "hello",
  b: " ",
  c: "world",
  d: (function() { this.x.a + this.x.b + this.x.c })()
  // or maybe:
  e: (function() { this.x.a + this.x.b + this.x.c }).call(this)
}

(解释:因为this指的是windowx是一个全局的,因此是window(ie, window.x === x) 的属性......老实说,我们也可以在this这里省略,但它有助于说明这里发生了什么,所以我会留下它。)

但是不,该函数x在初始化时被调用,因此x直到该函数调用之后才在词法范围内定义。或者e,'this' 仍然是window

我们在这里了解到的是,在 Javascript 中评估对象时也无法访问同级属性。

整洁的!

因此,要实现预期目标,需要两个单独的语句:

x = {
  a: "hello",
  b: " ",
  c: "world"
}

x.d = x.a + x.b + x.c;

除非您希望 xd 能够以这些值动态响应,而不是此时添加这些值的结果 - 那么您只需使用问题中的原始代码,并且必须将其作为函数进行评估。

……

写完上面的内容后,我想起了一个我从未使用过的 JavaScript 特性:getter 和 setter。果然,他们完成了我们在这里寻找的东西:

var hello = {
  a: "hello",
  b: "world",
  get test() {
    return this.a + this.b
  }
}
// undefined
hello.test
// "helloworld"
hello.a = 'stuff'
// "stuff"
hello.test
// "stuffworld"

当然,这在计算上等价于调用 hello.test() 并将 test 设为函数,就像在原始代码中一样。这个 getter 不能像函数一样被序列化,就 JSON 而言(尽管我们确定这不是重点,我只是想清楚一点)。最后,我们真正获得的唯一东西是省略括号的能力——而且这不会通过 JSON 序列化,要明确的是,如果这真的是问题的故意部分。

于 2016-08-16T17:15:15.587 回答
4

“上面的代码既不能使用 this 关键字,也不能没有它。这是为什么呢?”

尽管您谈论的是 JSON,但在阅读问题的文本时,听起来您要问的是this在使用对象文字语法时如何在对象创建过程中引用该对象。

对您不起作用的原因this是它的值仅在函数中定义,而定义它的是函数的调用方式。

尽管您的代码确实提供了一个函数,但它无法在创建过程中引用该对象,因为在文字语法之后之前没有可用的引用。


“唯一可行的解​​决方案是将 JSON 对象分配给一个变量并在代码中使用该变量。”

没错,您不能this在对象文字语法中使用来引用新对象,因此您需要在之后使用变量引用。

尽管作为文字语法的替代方案,您可以使用构造函数来创建对象。这样,您就不需要在创建fullName对象后使用变量来创建属性。

var obj = new function() {
    this.firstName = "Foo";
    this.lastName = "Bar";
    this.fullName = this.firstName + " " + this.lastName;
};

如果您将对象传递给函数,这也很有用。

my_func(new function() {
    this.firstName = "Foo";
    this.lastName = "Bar";
    this.fullName = this.firstName + " " + this.lastName;
});

所以你可以使用的原因this是正如我上面所说的,this它是在一个函数中定义的,并且是根据函数的调用方式来定义的。

在这里,我们使用匿名函数作为构造函数,使用new. 这使得this引用一个正在构造的新对象,然后自动从构造函数返回。

于 2013-10-29T13:15:28.273 回答
4

代码存在多个问题。比问题更基本的this是 JSON 甚至不能包含函数(请记住 JSON 被 Javascript 以外的语言使用!)。它纯粹是一个数据传输系统。

并非所有可以成为 Javascript 对象一部分的对象都可以在 JSON 中序列化。

于 2013-10-29T13:10:01.593 回答