繁体   English   中英

为什么这些基于闭包的私有变量在JavaScript中不起作用

[英]Why these closure based private variables in JavaScript not working

我正在尝试模仿JS中的OOP行为。 我试图在功能Person拥有(私有)变量: idname 我要向该函数传递用于初始化(私有)变量的参数。 然后,我返回的对象的name具有getter和setter,而id仅有一个getter,从而有效地使id只读。

因此,只能通过构造函数设置id,而可以随时设置和获取名称。

这是代码:

     var Person = function (_id,_nm) {
        var id, name;    

        this.id = _id;
        this.name = _nm;

        return {               
            setName: function (nm) {
                name = nm;
            },
            getName: function () {
                return name;
            },
            getId: function () {
                return id;
            },
            print: function () {
                document.writeln("Id: "+id+"<br />Name: "+name);
            }
        }
    }

    var person = new Person(123, "Mahesh");
    person.print();

但是,当执行new Person(123,"Mahesh") ,我不明白它实际上是在设置idname还是不设置,因为在调试时,将鼠标悬停在它们上时可以看到设置正确的值,但是Locals面板未显示它们的初始化值:

调试

或者在print()中没有引用所需的idname变量:

调试

怎么了

工作提琴

原因是因为您正在使用Person.prototype public成员。 您无需this引用添加到这两个。 因此删除:

this.id = _id;
this.name = _nm;

并简单地使用:

 var id = _id,
     name = _nm;  

现在一切正常。 整个想法是使用var ,而不是this ,否则将不会创建闭包。 现在,您将无法直接访问nameid ,而必须使用setName(), getName(), setId(), getId()等。

现在,您想要的两个成员idname将成为闭包。

更新

如果您使用this.id ,那么它就不会是private ,您可以执行var p = new Person(1, "Mahesha"); 并直接访问p.namep.id 他们应该是private所以这不是您想要的。

对于关闭模式,p.name和p.id是未定义的,只能通过p.getName();进行访问p.getName(); p.getId(); 阅读有关闭包如何工作的信息。 这个想法是因为您使用的是var name ,所以将创建一个闭包来记住它的值。

您的getNamesetName使用该闭包来访问name属性。 没有this.name ,通过高阶闭包可以记住一个值。

您对_id_nm和“公共”实例属性( this.idthis.nm )使用局部范围内的(“私有”)变量进行了this.nm

在这种情况下,您需要前者,但是您创建了两者并且仅初始化了后者。

请注意,由于id是只读的,因此您根本不需要一个单独的局部变量,您可以对构造函数使用按词法定义的第一个参数:

var Person = function (id, _nm) {
    var name = _nm;

    ...
};

this.idvar id不相同。 this.id是对象的属性。 var id属于本地范围。

使用new或返回一个值。 不是都。

问题在于您正在使用new关键字创建Person的新实例,但是构造函数却返回了另一个对象。

当您从构造函数返回某些内容时,它将返回该值,而不是该函数的实例。

您会看到执行new Person(123, "Mahesh") ,会创建一个新的Person实例。 这可以在构造函数中作为this

如果您没有从构造函数中返回任何内容,那么JavaScript会自动返回this 但是,您将显式返回另一个对象。

难怪var person没有idname属性(只能在this定义)。

另外, print不显示idname因为尽管您声明了它们( var id, name ),但没有给它们提供任何值。 因此它们是undefined

这就是我重写您的Person构造函数的方式:

function Person(id, name) {
    this.getId = function () {
        return id;
    };

    this.getName = function () {
        return name;
    };

    this.setName = function (new_name) {
        name = new_name;
    };

    this.print = function () {
        document.writeln("Id: " + id + "<br/>Name: " + name);
    };
}

我没有this设置idname属性,因为将它们包括在内没有任何意义。

让我尝试使用以下内容进行解释:

// Scope 1
var Person = function (_id,_nm) {
    // Scope 2
    var id, name;    

    this.id = _id;
    this.name = _nm;

    return {
        // Scope 3
        setName: function (nm) {
            name = nm;
        },
        getName: function () {
            return name;
        },
        getId: function () {
            return id;
        },
        print: function () {
            $("#output").append("<p>Id: "+id+"; Name: "+name  + "<p/>");
        }
    }
}

print方法将返回undefined因为您引用的是var id, name; 从来没有在您的代码中设置 您将_id_name设置为属性idname但是无法返回刚刚创建的对象。 相反,您返回一个字典,该字典引用您从未设置的Scope 2中创建的nameid变量,因此在print()调用中未定义输出。

这是您应该做的:

var NewPerson = function (_id,_nm) {
    var self = this;
    this.id = _id;
    this.name = _nm;  

    this.print = function () {
        $("#output").append("<p>New Person Id: "+this.id+"; Name: "+ this.name  + "<p/>");
    };

    return this;
};

var nperson = new NewPerson(456, "Marcos");
nperson.print();

这将输出:

New Person Id: 456; Name: Marcos

从本质上讲, new正在创建一个由this表示的新对象,并且必须返回this以对创建的对象进行引用。 实际上,如果在创建对象之前不使用new ,则最终将引用this的全局实例。 请尝试以下操作:

var nperson = new NewPerson(456, "Marcos");
this.name = "Hello";
nperson.print();

var nperson1 = NewPerson(456, "Marcos");
this.name = "Hello";
nperson1.print();

您将看到第一个输出将与预期的一样:

New Person Id: 456; Name: Marcos

但是第二个将获取对此this.name所做的更改:

New Person Id: 456; Name: Hello

这是JSFiddle

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM