JavaScript的OOP公共和私有变量的作用域(Javascript OOP public an

2019-07-31 11:31发布

我有关于JavaScript对象的公共和私有变量的问题。 下面是简单的代码我一直在玩,让我周围的变量范围以及私人和公共属性头。

var fred = new Object01("Fred");
var global = "Spoon!";

function Object01(oName) {
    var myName = oName;
    this.myName = "I'm not telling!";
    var sub = new subObject("underWorld");
    this.sub = new subObject("Sewer!");

    Object01.prototype.revealName = function() {
        return "OK, OK, my name is: " + myName + ", oh and we say " + global;
    }

    Object01.prototype.revealSecretName = function() {
        console.log ("Private: ");
        sub.revealName();
        console.log("Public: ");
        this.sub.revealName();
    }
}

function subObject(oName) {
    var myName = oName;
    this.myName = "My Secret SubName!";

    subObject.prototype.revealName  = function() {
        console.info("My Property Name is: " + this.myName);
        console.info("OK, my real name is: " + myName + ", yeah and we also say: " + global);
    }
}

到目前为止,我所观察到的有趣的事情是我的对象中,一个普通的VAR是作为私处理(很明显,因为他们是在一个功能块),并且this版本是公开的。 但我注意到,与具有相同名称的变量this.xxx似乎被认为是不同的变量。 所以,在上面的例子中,我的目标fred将报告的东西不同this.myName与我的功能来拉我比较var myName

但这种相同的行为不是一个子对象创建相同。 在的情况下, var sub VS this.sub上述两种使用new subObject调用理应做两个子对象。 但似乎都this.subvar sub返回Sewer! 版。

索姆我有点搞不清楚为什么,如果我用字符串this.myNamevar myName我得到两个不同的结果,但我试图做同样的与其他对象不会产生类似的结果? 我想这可能是我使用他们是错的,或者不理解之间的差异thisvar版本。

Answer 1:

在这里你最大的问题是没有真正的区别this基于对象的属性和var -declared变量。

你的问题是,你正在努力使原型充当包装,会给你这是提供给子类保护类的属性,让你的主类的单独实例。

prototype 不能正常工作"private"在所有类的成员(即正变量的构造函数的范围内定义的,而不是属性添加到您传回构造的对象)。

function Person (personName) {
    var scoped_name = personName;

    this.name = "Imposter " + scoped_name;
}


Person.prototype.greet = function () { console.log("Hi, I'm " + this.name + "!"); };


var bob = new Person("Bob");
bob.greet(); // "Hi, I'm Imposter Bob!"

该点prototype串要么是提供您的对象的可公开访问的属性操作的方法(例如,如果你想改变的值this.name ,但你永远失去隐藏scoped_name参考)...

...或者,如果你想所有相同种类的对象能够获得相同的值。

function Student (name, id) {
    function showIDCard () { return id; }
    function greet () { console.log("I'm " + name + ", and I attend " + this.school); }

    this.showID = showIDCard;
    this.greet = greet;
}


Student.prototype.school = "The JS Academy of Hard-Knocks";
Student.prototype.comment_on_school = function (feeling) {
    console.log("I " + feeling + " " + this.school);
}

var bob = new Student("Bob", 1);
var doug = new Student("Doug", 2);
var mary = new Student("Mary", 1);


mary.school = "The JS School of Closure";



bob.greet(); // I'm Bob and I attend The JS School of Hard-Knocks
mary.greet(); // I'm Mary and I attend the JS School of Closure
mary.comment_on_school("love"); // I love The JS School of Closure

prototype已经定义了默认值school ,为Student小号谁不给自己。 prototype还提供了可以将对象之间共享,这是因为函数使用函数this访问该对象的实际特性。

功能的任何内部变量只能通过其内部的功能的定义的属性或方法来访问。

因此,在这种情况下, prototype方法始终不能访问id ,除了通过this.showID ,因为this.showID是对参考showIDCard功能,这是每一个单一的学生创建的,谁都有自己独特的id ,以及它们的该函数的自己的副本有这样的说法自己独特的副本的引用。

我对申请大型“类”的方法来JS的建议是去有利于该物体组成的风格。 如果你要子类,使每个子类中的模块,拥有自己的面向公众的界面,和自己的私人范围的增值经销商,然后使该模块无论你试图做的属性,而不是试图得到继承工作链。

也就是说方式,JS太多的工作,如果你期待做的事情就像从一个基类继承,然后扩展其8或10代。 它会刚刚结束在流泪,抱怨,JS不是“面向对象”(的风格,你想它是)。



Answer 2:

有没有私人或公共的,有变量和对象属性。

变量和对象属性在许多比具有可变范围,并且不具有可变范围的对象属性的变量的一个多种方式不同。 变量的作用域是不一样的作为对象的私有财产,因为它不是一个属性,但一个变量。

变量不属于任何对象,但他们可以通过封闭来维持。 你可以在所有调用这些倒闭的任何对象或属性没有任何物体与所谓私有财产将工作:

function A() {
    var private = 0;

    this.setPrivate = function( value ) {
        private = value;    
    };

    this.getPrivate = function() {
        return private;
    };
}

var a = new A();

a.getPrivate() //0;

var b = [];

b.fn = a.setPrivate; //The function is fully promiscuous, especially since the data is closed over by it,
                    //so it doesn't matter at all where or how it's invoked.

b.fn(1);

a.getPrivate(); //1

您每次调用构造函数时重新定义的原型对象的功能。 原型的整点是,你只需要仅仅一次创造一定的作用对象。 您正在分配方法,在函数内部原型对象,所以每一个函数被调用时,该功能被重新创建和形成是指特定的国家新的关闭。

我发现,关闭之上,因为他们在关闭了变量保持状态,不关心他们是如何被调用。 所以,当你分配一个封闭的属性设置为原型,所有的情况下,你必须是指分配最新的关闭,以及您得到它的状态。

我建议使用JS定义“类”,而不是与关闭混合起来的标准方式:

function A() {
    this._private = 1;
}
//Note, this code is outside any function
//The functions assigned to prototype are therefore only defined once.
A.prototype.getPrivate = function() {
    return this._private;
};

A.prototype.setPrivate = function( value ) {
    this._private = value;
};

var a = new A();

你可以在这里找到一个很好的教程: https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model



Answer 3:

其实,我提倡使用非标准的方法来定义JavaScript类。 以下编码约定使得代码容易阅读和理解具有一个面向对象的背景的人; 它也很容易不像保持Method.prototype=function(){}; 这吮吸随时方法要重命名一个类,添加更多的方法,了解一个类的层次,甚至重新诠释一下你自己的代码在做什么。

相反,你可以声明采用以下架构的面向对象的结构:

/**
* public class Animal
**/
(function(namespace) {
    var __class__ = 'Animal';

    /**
    * private static:
    **/
    var animalCount = 0;

    /**
    * public Animal(string name)
    **/
    var constructor = function(name) {

        // here you can assert arguments are correct
        if(arguments.length == 0) {
            return global.error('needs a name');
        }

        /**
        * private:
        **/
        var animalIndex = animalCount++;

        /**
        * public:
        **/
        var operator = {
            speak: function() {
                console.log('?');
            },
            getName: function() {
                return name;
            },
            getAnimalIndex: function() {
                return animalIndex;
            },
        };

        return operator;
    };

    /**
    * public static Animal()
    **/
    var global = namespace[__class__] = function() {
        // new Animal();
        if(this !== namespace) {
            // construct a new instance of this class
            instance = constructor.apply(this, arguments);
            return instance;
        }
        // Animal();
        else {
            // return the last instantiation of this class
            return instance; // or do whatever you want
        }
    };

    /**
    * public static:
    **/
    // overrides the default toString method to describe this class from a static context
    global.toString = function() {
        return __class__+'()';
    };

    // prints a message to the console's error log
    global.error = function() {
        var args = Array.prototype.slice.apply(arguments);
        args.unshift(__class__+':');
        console.error.apply(console, args);
    };
})(window);

/**
* publc class Dog extends Animal
**/
(function(namespace) {
    var __class__ = 'Dog';

    /**
    * private static:
    **/
    var dogCount = 0;

    /**
    * public Dog()
    **/
    var construct = function(name) {

        /**
        * private:
        **/
        var dogIndex = dogCount++;

        /**
        * public operator() ();
        **/
        var operator = new Animal(name);

        /**
        * public:
        **/

        // overrides parent method 'speak'
        operator.speak = function() {
            console.log(operator.getName()+': bark!');
        };

        // method returns value of private variable
        operator.getSpeciesIndex = function() {
            return dogIndex;
        };

        return operator;
    };

    /**
    * public static Dog()
    **/
    var global = namespace[__class__] = function() {

        // new Dog();
        if(this !== namespace) {
            // construct a new instance of this class
            instance = construct.apply(this, arguments);
            return instance;
        }

        // Dog();
        else {
            // return the last instantiation of this class
            return instance; // or do whatever you want
        }
    };
})(window);


/**
* publc class Cat extends Animal
**/
(function(namespace) {
    var __class__ = 'Cat';

    /**
    * private static:
    **/
    var catCount = 0;

    /**
    * public Cat()
    **/
    var construct = function(name) {

        // here you can assert arguments are correct
        if(arguments.length == 0) {
            return global.error('needs a name');
        }

        /**
        * private:
        **/
        var catIndex = catCount++;

        /**
        * public operator() ();
        **/
        var operator = new Animal(name);

        /**
        * public:
        **/

        // overrides parent method 'speak'
        operator.speak = function() {
            console.log(name+': meow!');
        };

        // method returns value of private variable
        operator.getSpeciesIndex = function() {
            return catIndex;
        };

        return operator;
    };

    /**
    * public static Cat()
    **/
    var global = namespace[__class__] = function() {

        // new Cat();
        if(this !== namespace) {
            // construct a new instance of this class
            instance = construct.apply(this, arguments);
            return instance;
        }

        // Cat();
        else {
            // return the last instantiation of this class
            return instance; // or do whatever you want
        }
    };
})(window);

现在,上述类中声明:动物,狗伸出动物,和Cat扩展动物...我们得到如下:

new Dog(); // prints: "Animal: needs a name" to error output

var buddy = new Dog('Buddy');
buddy.speak(); // prints: "Buddy: bark!"

var kitty = new Cat('Kitty');
kitty.speak(); // prints: "Kitty: meow!"

var oliver = new Dog('Oliver');
oliver.speak(); // prints: "Oliver: bark!"


buddy.getSpeciesIndex(); // returns 0;
buddy.getAnimalIndex(); // returns 0;

kitty.getSpeciesIndex(); // returns 0;
kitty.getAnimalIndex(); // returns 1;

oliver.getSpeciesIndex(); // returns 1;
oliver.getAnimalIndex(); // returns 2;

我只提供这个JavaScript编码约定,以维持组织的面向对象的结构的一种手段。 我不吹嘘这样的编码风格比其他公约的表现,但如果你想从你的代码的性能,我强烈建议使用谷歌的关闭编译器将优化相同。

我从多年的编码我自己的经验和批评对方的代码的同化得出这个JavaScript编码风格。 我发誓,它的坚固性和模块化,并欢迎有关,否则任何评论。



Answer 4:

你疯玩。 构造函数应该改变的原型。 或者:

function subObject(oName)
{
    var myName = oName;
    this.myName = "My Secret SubName!";

}

subObject.prototype.revealName  = function()
{
    console.info("My Property Name is: " + this.myName);
    console.info("OK, my real name is: " + myName + ", yeah and we also say: " + global);
}

要么:

function subObject(oName)
{
    var myName = oName;
    this.myName = "My Secret SubName!";

    subObject.revealName  = function()
    {
        console.info("My Property Name is: " + this.myName);
        console.info("OK, my real name is: " + myName + ", yeah and we also say: " + global);
    }
}


Answer 5:

布莱克的回答启发了我,但我发现它不这样做,我想要的一切,所以我砍死个不停,直到我有东西,涵盖了大部分的C ++面向对象的特点在一个简单而优雅的语法。

此刻的唯一的东西,不支持(但它是实现它们的问题):

  • 多重继承
  • 纯虚函数
  • 友元类

见例子,一个严重的自述GitHub的回购:

  • https://github.com/najamelan/TidBits_Javascript_OoJs


文章来源: Javascript OOP public and private variable scope