强迫上下文

Erm*_*lla 4 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.Name = value; //Set
        }
    };

    return _public;
};
Run Code Online (Sandbox Code Playgroud)

我想强制上下文_public.Name访问a this.Name.

我知道关闭的技巧,但我想知道我是否可以强制上下文.

我发现了一种技术,扩展对象功能:

Function.prototype.setScope = function (scope) {
    var f = this;

    return function () {
        f().apply(scope);
    }
}
Run Code Online (Sandbox Code Playgroud)

我的班级成了:

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;
};
Run Code Online (Sandbox Code Playgroud)

所以我可以强制正确的上下文,但我不能通过,但不能value返回this.Name.

T.J*_*der 9

f().apply(scope);
Run Code Online (Sandbox Code Playgroud)

只是

f.apply(scope);
Run Code Online (Sandbox Code Playgroud)

(()之后没有f.)你想apply在函数f对象上使用函数,而不是调用函数f并访问apply它的返回值.

要传递函数setScope接收的参数,请添加以下内容:

f.apply(scope, arguments);
Run Code Online (Sandbox Code Playgroud)

arguments是所有函数的隐式参数,它是在运行时传递给函数的实际参数的伪数组.apply接受任何类似数组的东西作为其第二个参数来指定调用底层函数时使用的参数.

我也让它返回返回值:

return f.apply(scope, arguments);
Run Code Online (Sandbox Code Playgroud)

所以setScope就变成了:

Function.prototype.setScope = function (scope) {
    var f = this;

    return function () {
        return f.apply(scope, arguments);
    }
}
Run Code Online (Sandbox Code Playgroud)

实例

需要注意的是平时的名字此功能,它在新的名称ECMAScript5标准,是bind(第15.3.4.5; ECMAScript5的bind,您还可以咖喱参数,这是不能由此实现完成).setScope是一个特别不幸的名称,因为它没有设置范围,它设置了上下文.

说了这么多,setScope你的Person构造函数就没有理由了.你可以这样做:

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;
};
Run Code Online (Sandbox Code Playgroud)

实例

但是使用bind(aka setScope)在你不想在你正在进行的上下文中使用新闭包的地方会很有用.


偏离主题:您指定的方式Person会破坏人们可能期望的某些事情,例如:

var p = new Person();
alert(p instanceof Person); // Expect "true", but in your case will be "false"
Run Code Online (Sandbox Code Playgroud)

...因为你正在替换new为你创建的对象,但是从构造函数中返回一个不同的对象(它会覆盖默认值).

不是创建一个新对象并在构造函数中返回它,而是允许为您构造的对象new成为对象(因此Person保持关系),但您仍然可以获得真正的私有变量并使用访问器:

function Person() {
    // Private variable
    var name = "asd";

    // Accessor function
    this.Name = function(value) {
        if (typeof value === "undefined") {
            return name;
        }
        name = value;
    };
}
Run Code Online (Sandbox Code Playgroud)

实例

正如您所看到的,这非常简单,并且保留了这种instanceof关系.请注意,我们没有资格我们引用nameName的一切,所以我们使用,使我们的构造函数调用的局部变量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;
    }
}
Run Code Online (Sandbox Code Playgroud)

偏离主题2:JavaScript代码中的压倒性约定是仅对构造函数(如Person)使用函数名的初始上限,而不对其他类型的函数(如Name)使用.当然,你可以自由地做任何你喜欢的事情,但我想我会提到这个惯例,因为它让其他人更容易阅读你的代码.


值得注意的是:所有这些技术都会导致每个Person对象都拥有自己的存取函数副本.如果会有很多这些对象,那可能是内存问题.如果只有一些,那很好.