0

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

所以 id 只能通过构造函数设置,而 name 可以随时设置和获取。

这是代码:

     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")执行时,我不明白它实际上是设置id还是name不设置,因为在调试时我可以看到将鼠标悬停在它们上时设置的值正确,但本地面板没有显示它们已初始化:

调试

或者在 print() 中不是指期望的idname变量:

调试

这里有什么问题?

4

5 回答 5

2

工作小提琴

原因是因为您将public成员用于Person.prototype. 您不需要添加this对这两个的引用。所以删除:

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

并简单地使用:

 var id = _id,
     name = _nm;  

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

id和两个成员name现在将成为您希望的闭包。

更新

如果你用过this.id,那么它就不会了private,你可以做var p = new Person(1, "Mahesha");直接访问p.name或访问p.id。他们应该是,private所以这不是你想要的。

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

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

于 2013-05-12T11:26:29.740 回答
1

您已经混淆了使用本地范围(“私有”)变量_id_nm“公共”实例属性(this.idthis.nm)。

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

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

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

    ...
};
于 2013-05-12T11:28:53.223 回答
1

this.id并且var id不一样。this.id是对象的属性。var id属于本地范围。

于 2013-05-12T11:42:27.067 回答
1

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

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

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

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

如果你的构造函数没有返回任何东西,那么 JavaScript 会自动返回this. 但是,您明确返回另一个对象。

难怪var person没有idandname属性(您只在 上定义this)。

另外print不显示idandname因为虽然你声明了它们 ( 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);
    };
}

我没有设置idandname属性,this因为包含它们没有意义。

于 2013-05-12T13:54:20.397 回答
0

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

// 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;是从未在代码中设置的方法。您将_idand设置_name为属性idname但未能返回刚刚创建的对象。相反,您返回一个字典,它引用您创建的变量name和您从未设置过的变量,因此调用中的未定义输出。idScope 2print()

这是你应该做的:

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

于 2013-05-12T13:09:57.527 回答