强迫上下文
我有这个类,我有一个私有属性和一个公共访问方法:
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:
Function.prototype.setScope = function (scope) { var f = this; return function () { f().apply(scope); } }
我的class级成了:
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.Name
。
不
f().apply(scope);
只是
f.apply(scope);
( f
之后的No ()
。)你想在函数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); } }
实例
请注意,此函数的通常名称及其在新ECMAScript5标准中的名称是bind
(第15.3.4.5节; ECMAScript5的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
(aka setScope
)在你不想在你正在进行的上下文中使用新闭包的地方会很有用。
偏离主题 :你指定Person
会破坏人们可能期望工作的某些事情,例如:
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
)使用。 当然,你可以自由地做任何你喜欢的事情,但我想我会提到这个惯例,因为它让其他人更容易阅读你的代码。
值得注意的是: 所有这些技术都会导致每个Person
对象都有自己的存取函数副本。 如果会有很多这些对象,那可能是内存问题。 如果只有一些,那很好。
首先,我认为正确的方法是“闭包”方法,因为语法更容易理解,更有意义,大多数用Javascript编写的面向对象的代码就是这样编写的。 另外需要注意的是,在您的方法中,可以通过访问Person.Name
(而不是(new Person()).Name
来从外部访问“私有”成员(new Person()).Name
)。
话虽这么说,似乎你想要像Prototype.JS的bind方法 ,它允许你将一个函数引用绑定为对特定对象的方法调用,并且还正确地传递所有参数(包括允许预加载的参数)。
查看完整实现的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); }; };
很难理解你想要实现的目标。 但是,如果我猜你想创建一个带有名字方法的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 }
请注意,我已使用小写首字母定义了名称函数。 这是JavaScript中的标准做法,其中只有构造函数通常是大写的。 要使用此课程,您需要:
person = new Person(); person.name( "Ermes Enea Colella" ); alert( person.name ); // displays "Ermes Enea Colella"
不需要使用此方法绑定任何上下文,因此您可能正在寻找其他内容。 如果您能澄清您的需求,我将很乐意编辑我的答案。
我希望这有帮助。