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"