JavaScript - this关键字的含义

13
String.prototype.foo = {};
String.prototype.foo.bar = function() {
    //How can you reference the "grandparent" string?
    console.log(this.parent.parent); //obviously, doesn't exist
}

就像这样,"Hello, Nurse!".foo.bar()将会记录"Hello, Nurse!"。

如果对foo有控制权,是否会有所不同?

编辑:在这里,foo被定义了。

编辑2:好吧,用this.parent.parent代替this.this.this。当然parent不存在,但希望现在语义不会成为问题。

编辑3:没有具体的情况。提供的细节基本上是我拥有的全部信息:有一个名为foo的对象,是原型的一部分。foo.barfoo的一个方法,应该访问它的祖父级。就这些,没有其他信息。

编辑4:已解决。根据提供的答案(以及来自Douglas Crockford的一些二手帮助):

String.prototype.foo = function() {
    var that = this;
    return {
        bar : function() {
            console.log(that.valueOf());
        }
    }
}
//Called:
"Hello, Nurse!".foo().bar();

2
this 仍然是自身,而不是父级。 - Lightness Races in Orbit
如果我们了解你想做什么,回答会更容易。使用那段代码是行不通的,因为String.prototype.foo未定义。foo是什么?你是想继承某些东西吗? - Robert
4
我曾经在一家国外的商店走进去,不知道“西红柿”这个词怎么说。于是我耸了耸肩膀,要了草莓,期望店主知道我的意思。但事实并非如此。 - Lightness Races in Orbit
1
@Zirak:如果你知道什么是相关的,什么不是,那么你应该能够自己回答这个问题,对吧? :) - Lightness Races in Orbit
1
顺便说一下,这里的self并不总是指代自身,而是函数执行的上下文。如果你使用call和apply调用一个函数,你可以将其设置为任何值。 - Ruan Mendes
显示剩余13条评论
2个回答

8
唯一的方法是将foo()转化为函数。可以将其视为针对特定字符串初始化foo命名空间:
String.prototype.foo = function () {
    var str = String(this);
    var o = Object(this)
    o.bar = function () {
         console.log(str);
    };
    return o;
};

然后您可以使用:

"foobar".foo().bar(); // logs "foobar"

或者如果我们将foobar重命名为更加有趣的名称:

"Hello!".console().log(); // logs "Hello!"

为什么这很复杂?

每个函数都是使用特定的上下文(一个单一对象)调用的。无论是使用a.b()还是a.b.c.d()调用,它都会将紧贴在函数调用左侧的对象作为其上下文。因此,a.b()的上下文将是a,而a.b.c.d()的上下文是c。关键字this引用上下文。因为c只是一个对象(不是正在运行的函数),它没有上下文,并且没有this的概念,所以this.this没有意义。

因此,通常情况下不能通用地访问所谓的“父级”。Juan的答案给出了一个很好的概念性解释。但是,如果您想要在原型函数中实现命名空间,则可以通过从foo返回一个增强对象来实现。

请注意,我还必须将this转换为Object。这是因为您无法将属性附加到诸如字符串之类的基本值。 var str =“foo”; str.bar = 1 将起作用,但仅因为JS自动将“foo”转换为对象。但是,由于str引用原语而不是自动生成的对象,因此该对象随即被丢弃,我们失去了bar


这个如何以通用的方式让你访问父对象 - Ruan Mendes
@Juan,在这种情况下,str被称为父对象 - David Tang
嗯,这是硬编码的,任何人都可以做到,你可能直接使用String - Ruan Mendes
@Box9:我显然已经看过这个例子了!除了我告诉你的那种方式,我无法理解它。请解释一下如何使用它来通用地访问对象的父级。 - Ruan Mendes
@Juan 我从未声称通用地访问对象的父级。也许我会添加一个语句来查看你的答案,因为我并不争论它!我只是试图解决在原型上命名空间函数的问题。 - David Tang
非常感谢。最后,我使用了您提供的基本代码的稍微不同版本。请查看我的编辑后的问题。 - Zirak

3

一个对象无法知道它是哪个对象的属性。同一个对象(在你的情况下是一个函数)可以附加到多个对象上。以下是一个例子:

var myObj = {};
var objA = {prop: myObj};
var objB = {nother: myObj}

如果给定对myObj的引用,你怎么可能知道你正在引用哪个父对象?在一个情况下,它是空的,在另一个情况下,它是objA,在最后一个情况下,它是objB的“子”对象。如果你解释一下为什么你想要这种行为,我们可以帮助你解决手头的问题。但是问题的答案是你无法做到。


зҹҘйҒ“fooе§Ӣз»ҲжҳҜStringзҡ„дёҖдёӘж–№жі•пјҢиҖҢbarе§Ӣз»ҲжҳҜfooзҡ„дёҖдёӘж–№жі•пјҢиҝҷдјҡжңүжүҖеё®еҠ©еҗ—пјҹ - Zirak
问题在于你无法知道。任何人都可以执行 var b = String.prototype.foo.bar。这就是动态语言的本质。 - Ruan Mendes
当然,如果我执行 Object.toString = "hi".toLowerCase,你的方法也可以工作。但是它会出现错误,所以我假设最好情况下。 - Zirak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接