Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/456.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
JavaScript私有变量的解决方案?_Javascript_Private Members - Fatal编程技术网

JavaScript私有变量的解决方案?

JavaScript私有变量的解决方案?,javascript,private-members,Javascript,Private Members,我问这个问题是因为我想我找到了一个JavaScript问题的解决方案,我想知道我是否偏离了底线。我希望在这里问这个问题是恰当的 我相信您知道,JavaScript没有私有属性。此问题通常使用两种模式之一解决 第一种方法是使用闭包在构造函数内创建特权方法,并使用this关键字将它们绑定到对象。这就是技术。下面是一个例子: function Person(name) { function getName() { return name; } this.who

我问这个问题是因为我想我找到了一个JavaScript问题的解决方案,我想知道我是否偏离了底线。我希望在这里问这个问题是恰当的

我相信您知道,JavaScript没有私有属性。此问题通常使用两种模式之一解决

第一种方法是使用闭包在构造函数内创建特权方法,并使用
this
关键字将它们绑定到对象。这就是技术。下面是一个例子:

function Person(name) {
    function getName() {
        return name;
    }
    this.who = getName;
}
这种模式的问题在于存在污染全局名称空间的巨大危险:

var me = Person("Karl"); // Oops! no "new"
me.who(); // TypeError: Cannot read property 'who' of undefined
who(); // "Karl" - "who" is in global namespace!
第二种解决方案是使用。您将特权方法绑定到一个新对象,而不是绑定到
this

function Person(name) {
    function getName() {
        return name;
    }
    return {
        who: getName
    }
}
var me = Person("Karl"); // No "new," but that's OK
me.who(); // "Karl"
who(); // TypeError: undefined is not a function
该模式的问题在于对象没有Person的原型链。因此,您无法正确检查其类型,也无法使用构造函数的原型扩展对象:

console.log(me instanceof Person); // "false"
Person.prototype.what = function() {
    return this.constructor.name + ": " + this.who();
}
me.what(); // TypeError: undefined is not a function
我找到了解决这个问题的办法。使用具有Person原型链的临时构造函数,并返回使用临时构造函数构造的对象:

function Person(name) {
    function getName() {
        return name;
    }
    // Temporary constructor
    function F() {
        this.who = getName;
    }
    F.prototype = Person.prototype;
    return new F();    
}
// Can't pollute the global namespace
var me = Person("Karl");
me.who(); // "Karl"
who(); // TypeError: undefined is not a function

// Proper prototype chain: correct type checking, extensible
console.log(me instanceof Person); // "true"
Person.prototype.what = function() {
    return this.constructor.name + ": " + this.who();
}
me.what(); // "Person: Karl"
关于此解决方案,我有几个相关问题:

  • 这种技术有什么缺点吗
  • 尽管模块模式和临时构造函数模式已经存在了一段时间,但我从未见过有人将它们放在一起。这是我以前不知道的模式吗
  • 如果第二个问题的答案是“不”,我能为此得到疯狂的道具吗
    我对你的问题没有答案,但有一个建议可以用一种更简单的方式解决你的所有问题:

    function Person(name) {
        "use strict";
        if (!this) return new Person(name);
        function getName() {
            return name;
        }
        this.who = getName;
    }
    Person.prototype.what = function() {
        return this.constructor.name + ": " + this.who();
    }
    


    适用于所有浏览器的替代方案

    function Person(name) {
        if (!(this instanceof Person)) return new Person(name);
        function getName() {
            return name;
        }
        this.who = getName;
    }
    Person.prototype.what = function() {
        return this.constructor.name + ": " + this.who();
    }
    

    这种模式的问题是有污染全局名称空间的巨大危险:“这不是该模式的问题,而是所有“正常”构造函数的“问题”。如果这正是您所担心的,那么一个简单的解决方案就是做一个
    instanceof
    检查:
    If(!(this instanceof Person)){return new Person(name);}
    。我个人认为,试图实现“私有财产”是不值得的努力和缺点。我们很快就会得到
    Symbol
    s,使用它应该会更容易。“
    this.who=getname
    ”会将`who()添加到全局命名空间中吗?真的吗?@GolezTrol:是的,确实会。如果调用该函数时没有“new”关键字,则该函数不是构造函数,
    绑定到全局对象。@FelixKling:您的解决方案似乎非常简单,这让我质疑为什么在我读过的JavaScript书籍中没有遇到它。您是否确定
    instanceof
    运算符在构造函数中有效(即原型链已绑定)?如果你的函数被称为“超级构造函数”呢?有边缘情况吗?我愿意承认我的无知。是的,
    instanceof
    在构造函数中工作。使用
    new
    调用函数时,基本上会发生以下情况:
    var newObj=Object.create(Constr.prototype);Constr.apply(newObj,参数);返回newObj。超级调用应该没有问题,因为您应该在子构造函数中而不是在父构造函数中进行此测试。如果这个测试只在父母体内进行,它就不能正常工作。另一个缺点是如果你有一个可变构造函数。您不能将
    .apply
    新的
    操作符一起使用(但请参见)。这将非常棒,但旧浏览器不支持“严格使用”@FelixKling建议在构造函数中使用
    instanceof
    (而不是
    if(!this)
    test)来获得相同的结果;用旧的browsers@dandavis:这将在旧浏览器中工作,但在严格模式下不起作用(其中
    将是
    未定义的
    )。如果混合使用严格代码和非严格代码,或者希望代码与所有JavaScript引擎使用严格模式时的前向兼容,那么这是个坏主意。编辑:如果你的对象是故意设计用来扩展全局对象的,那也不好。@KarlGiesing:我不严格要求,但我的观点是明确的。这样做:如果(!this | | this.Math)返回新的人(姓名);在100%的情况下工作。除非您在原型上定义了“数学”,否则在这种情况下,请使用另一个江湖医生。@dandavis:这会考虑严格模式,但不会考虑将对象设计为扩展全局对象的边缘情况。在这种情况下,
    this.Array===Array
    将始终返回true,并最终进入无限循环。但这是一个边缘案例,如果你有足够的知识来做这件事,你可能有足够的知识来知道为什么检查是坏的。