强制上下文
我有一个类,其中有一个私有属性和一个公共访问方法:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) { //Get
return this.Name
} else {
this.Name = value; //Set
}
};
return _public;
};
我想强制 _public.Name
中的上下文来访问 this.Name
。
我知道关闭技术,但我想看看是否可以强制上下文。
我找到了一种技术来做到这一点,扩展对象功能:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
f().apply(scope);
}
}
我的类变成:
Person = function () {
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return this.Name
} else {
this.Name = value;
}
}.setScope(this);
return _public;
};
所以我可以正确地强制上下文,但我无法传递 value
并且不能返回 this。名称
。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不仅仅是
(
f
之后没有()
。)您想在函数f
对象上使用apply
函数,而不是调用函数f
并在其返回值上访问apply
。要传递
setScope
中的函数接收的参数,请添加以下内容:arguments
是所有函数的隐式参数,它是传递的实际参数的伪数组到运行时的函数。apply
接受任何类似数组的东西作为其第二个参数,以指定调用底层函数时要使用的参数。我还希望它返回返回值:
因此
setScope
变为:Live example
请注意此函数的常用名称以及新 ECMAScript5标准,是
bind
(第15.3.4.5节;ECMAScript5的bind
还允许您柯里化 参数,此实现未完成)。setScope
是一个特别不幸的名字,因为它不设置范围,而是设置上下文。话虽如此,您没有理由在
Person
构造函数中需要setScope
。你可以这样做:Live example
但是使用
bind
(又名setScope
) 在您不希望在执行该操作的上下文中使用新的闭包的地方非常有用。离题:指定
Person
的方式会破坏人们可能期望的某些功能,例如:...因为您要替换对象
new
为您创建,但从构造函数中返回不同的对象(覆盖默认值)。不要创建一个新对象并在构造函数中返回该对象,而是允许由
new
为您构造的对象作为该对象(从而保持Person
关系),但是您仍然可以获得真正的私有变量并使用访问器:Live example
如您所见,这要简单得多,它保留了
instanceof
关系。请注意,我们根本没有限定Name
中对name
的引用,因此我们在构造函数调用中使用局部变量,其中Name创建了关闭它的
函数。我还冒昧地给构造函数起了一个名称,因为我不喜欢匿名函数。我还应该给访问器一个名称:
离题 2:JavaScript 代码中压倒性的约定是仅在构造函数的函数名称上使用首字母大写(例如
Person
),而不是其他类型的函数(例如Name
)。当然,您可以自由地做任何您喜欢的事情,但我想我应该提到约定,因为它使其他人更容易阅读您的代码。值得注意的是:所有这些技术都会导致每个
Person
对象都有其自己的访问器函数副本。如果有很多这些对象,则可能是内存问题。如果只有几个,那也没关系。Not
just
(No
()
afterf
.) You want to use theapply
function on the functionf
object, not call the functionf
and accessapply
on its return value.To also pass on the arguments that your function in
setScope
receives, add this:arguments
is an implicit argument to all functions, which is a pseudo-array of the actual arguments passed to the function at runtime.apply
accepts any array-like thing as its second parameter to specify the arguments to use when calling the underlying function.I'd also have it return the return value:
So
setScope
becomes:Live example
Note that the usual name for this function, and the name it has in the new ECMAScript5 standard, is
bind
(Section 15.3.4.5; ECMAScript5'sbind
also lets you curry arguments, which isn't done by this implementation).setScope
is a particularly unfortunate name, because it doesn't set the scope, it sets the context.Having said all that, there's no reason you need
setScope
in yourPerson
constructor. You can just do this:Live example
But using
bind
(akasetScope
) can be useful in places where you don't want a new closure over the context in which you're doing it.Off-topic: The way you're specifying
Person
will break certain things people might expect to work, such as:...because you're replacing the object
new
created for you, but returning a different object out of your constructor (which overrides the default).Rather than creating a new object and returning that in your constructor, allow the object constructed for you by
new
to be the object (and thus thePerson
relationship is maintained), but you can still get truly private variables and use accessors:Live example
As you can see, this is dramatically simpler, and it preserves the
instanceof
relationship. Note that we're not qualifying our references toname
withinName
at all, and so we're using the local variable in the constructor call in which ourName
function, which closes over it, was created.I've also taken the liberty there of giving the constructor function a name, because I'm not a fan of anonymous functions. I should have given the accessor a name as well:
Off-topic 2: The overwhelming convention in JavaScript code is to use initial caps on function names only for constructor functions (like
Person
), and not on other kinds of functions (likeName
). You're free to do whatever you like, of course, but I thought I'd mention the convention, as it makes it easier for other people to read your code.Worth noting: All of these techniques result in every single
Person
object having its own copy of the accessor function. If there are going to be a lot of these objects, that could be a memory issue. If there are only going to be a few, that's fine.首先,我认为正确的方法是“闭包”方法,因为语法更容易理解,也更有意义,并且大多数用 Javascript 编写的面向对象代码都是这样编写的。另一件需要注意的事情是,在您的方法中,可以通过访问
Person.Name
(而不是(new Person()).Name
从外部访问“私有”成员)。话虽这么说,你似乎想要像 Prototype.JS 的绑定方法 这样的东西,它允许您可以将函数引用绑定为对特定对象的方法调用,并且还正确传递所有参数(包括允许预加载参数)。
查看 Prototype.JS 源代码以获取完整的实现,但此语义的简单实现可能如下所示:
First thing, I think the correct way to go about this is the "closure" method, as the syntax is easier and simpler to understand and makes more sense and most object oriented code written in Javascript is written that way. Another thing to note is that in your method, the "private" member can be accessed from outside by accessing
Person.Name
(instead of(new Person()).Name
).That being said, it seems that you want something like Prototype.JS's bind method, which allows you to bind a function reference as a method call to a specific object, and also passes all the arguments correctly (including allowing preloaded arguments).
Look at Prototype.JS source for the complete implementation, but a simple implementation of this semantic might look like this:
很难理解你想要实现的目标。但是,如果我猜测您正在尝试创建一个带有 name 方法的 Person 类来获取/设置人名,那么我的建议是:
请注意,我已经使用小写首字母定义了 name 函数。这是 JavaScript 中的标准做法,通常只有构造函数是大写的。要使用此类,您需要执行以下操作:
无需使用此方法绑定任何上下文,因此您可能正在寻找其他内容。如果您能澄清您的需求,我将很乐意编辑我的答案。
我希望这有帮助。
It is difficult to understand what you are trying to achieve. But if I guess that you are trying to create a Person class with a name method to get/set the person's name, here is my suggestion:
Note that I have defined the name function with a lower case first letter. This is standard practice in JavaScript where only constructors are usually capitalized. To use this class you do:
There is no need to bind any context with this method, so you may be looking for something else. If you can clarify your need, I'll be happy to edit my answer.
I hope this helps.