Javascript 强制上下文
我有这个类,其中我有一个私有属性和一个访问的公共方法:Javascript 强制上下文,javascript,jquery,scope,this,Javascript,Jquery,Scope,This,我有这个类,其中我有一个私有属性和一个访问的公共方法: Person = function () { this.Name = "asd"; var _public = new Object(); _public.Name = function (value) { if (value == undefined) { //Get return this.Name } else { this.Na
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;
};
我想强制使用\u 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;
};
因此,我可以正确地强制上下文,但我不能传递值
,也不能返回此名称
f().apply(scope);
只是
(在f
之后没有()
)您希望在函数f
对象上使用apply
函数,而不是调用函数f
并访问其返回值上的apply
要同时传递函数在setScope
中接收的参数,请添加以下内容:
f.apply(scope, arguments);
arguments
是所有函数的隐式参数,它是在运行时传递给函数的实际参数的伪数组apply
接受任何类似数组的东西作为其第二个参数,以指定调用基础函数时要使用的参数
我还要让它返回返回值:
return f.apply(scope, arguments);
因此setScope
变为:
Function.prototype.setScope = function (scope) {
var f = this;
return function () {
return f.apply(scope, arguments);
}
}
请注意,此函数的常用名称及其在新函数中的名称是bind
(第15.3.4.5节;ECMAScript 5的bind
还允许使用参数,这不是此实现所能完成的)setScope
是一个特别不幸的名称,因为它不设置范围,而是设置上下文
话虽如此,您没有理由在Person
构造函数中需要setScope
。您可以这样做:
Person = function () {
var self = this;
this.Name = "asd";
var _public = new Object();
_public.Name = function (value) {
if (value == undefined) {
return self.Name;
} else {
self.Name = value;
}
};
return _public;
};
但是,如果您不希望在执行操作的上下文中出现新的闭包,那么使用bind
(又称setScope
)可能非常有用
非主题:您指定人员的方式将破坏人们可能期望工作的某些事情,例如:
var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
…因为您正在替换为您创建的对象new
,但从构造函数中返回不同的对象(这将覆盖默认值)
与其创建新对象并在构造函数中返回,不如允许new
为您构建的对象作为对象(从而保持Person
关系),但您仍然可以获得真正的私有变量并使用访问器:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = function(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
};
}
如您所见,这非常简单,并且它保留了instanceof
关系。请注意,我们根本没有限定name
中对name
的引用,因此我们在构造函数调用中使用了局部变量,在构造函数调用中创建了关闭它的name
函数
我还冒昧地给构造函数起了个名字,因为。我也应该给访问者一个名字:
function Person() {
// Private variable
var name = "asd";
// Accessor function
this.Name = Person_Name;
function Person_Name(value) {
if (typeof value === "undefined") {
return name;
}
name = value;
}
}
主题2:JavaScript代码中压倒性的惯例是只对构造函数(如Person
)的函数名使用首字母大写,而不对其他类型的函数(如Name
)使用首字母大写。当然,你可以自由地做任何你想做的事情,但是我想我应该提到这个惯例,因为它使其他人更容易阅读你的代码
值得注意的是:所有这些技术导致每个人
对象都有自己的访问器函数副本。如果有很多这样的对象,那可能是内存问题。如果只有几个,那就好了。首先,我认为正确的方法是“闭包”方法,因为语法更容易理解,也更容易理解,而且大多数用Javascript编写的面向对象代码都是这样编写的。另外需要注意的是,在您的方法中,可以通过访问Person.Name
(而不是(new Person()).Name
)从外部访问“private”成员
也就是说,您似乎想要这样的东西,它允许您将函数引用绑定为对特定对象的方法调用,并且还可以正确地传递所有参数(包括允许预加载参数)
查看Prototype.JS源代码以了解完整的实现,但此语义的简单实现可能如下所示:
Function.prototype.bind = function(context) {
var callee = this;
var args = Array.prototype.slice.call(arguments,1);
return function() {
var newargs = args.concat(Array.prototype.slice.call(arguments,0));
return callee.apply(context, newargs);
};
};
很难理解你想要实现什么。但是,如果我猜您正在尝试使用name方法创建Person类来获取/设置此人的姓名,我的建议如下:
function Person() {
this._name = undefined; // not required but is better than assigning a fake name
return this;
}
Person.prototype.name = function( _name ) {
if ( _name === undefined ) return this._name; // get
return this._name = _name; // set
}
注意,我已经用小写的第一个字母定义了name函数。这是JavaScript中的标准实践,通常只有构造函数是大写的。要使用此类,请执行以下操作:
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"
不需要使用此方法绑定任何上下文,因此您可能正在寻找其他内容。如果你能澄清你的需要,我很乐意编辑我的答案
我希望这能有所帮助。哦,对不起,上次测试后我忘了删除。非常感谢您详尽的解释和您的timeSo new Person()返回绑定到此_public.Name函数的闭包。这是创建类的一种相当复杂的方法,该类不返回对象,而是返回函数。这可能不是你想要做的。但是很难从提供的代码示例中猜出您想要实现什么。@Jean:“这是一种相当复杂的方法,用于创建一个类,而不是返回一个对象,而是返回一个函数。”它不返回一个函数对象,只返回一个对象。对象有一个分配给其名称
属性的函数。同意这不是我应该怎么做的。^^你是对的,它确实返回了一个对象,但这是一个相当复杂的方法来做一些琐碎的事情。@Ermes-函数的this关键字与作用域无关,也不是“上下文”。@RobG:“Cont
person = new Person();
person.name( "Ermes Enea Colella" );
alert( person.name ); // displays "Ermes Enea Colella"