Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.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_Oop_Object_Encapsulation_Data Hiding - Fatal编程技术网

Javascript中的封装/数据隐藏?

Javascript中的封装/数据隐藏?,javascript,oop,object,encapsulation,data-hiding,Javascript,Oop,Object,Encapsulation,Data Hiding,我想了解JavaScript中封装的概念,以及如何使我的属性和方法公开或私有 我在玩这个例子: var person = function(newName, newAge) { // Private variables / properties var name = newName; var age = newAge; // Public methods this.getName = function() { return na

我想了解JavaScript中封装的概念,以及如何使我的属性和方法公开或私有

我在玩这个例子:

    var person = function(newName, newAge) {

    // Private variables / properties
    var name = newName;
    var age = newAge;

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

    // Private methods
    var getAge = function() {
        return age;
    }

    // Public method, has acces to private methods
    this.giveAge = function() {
        return getAge();
    }
}

var jack = new person("Jack", 30);

console.log(jack.name); // undefined
console.log(jack.getName); // Jack
console.log(jack.getAge()); // TypeError: jack.getAge is not a function
console.log(jack.getAge); // undefined
console.log(jack.giveAge()); // 30
因此,变量
var name
var age
是私有的。要访问它们,我使用公共方法,使用
。这是
参考。因此,在我的函数中
var
的任何内容都是私有的,而在我的对象中
的任何内容都是外部可见的

我猜这是因为人是可见的,所以它会暴露它的所有属性

我走对了吗?这是隐藏或公开属性/方法的正确方法吗

还有一个问题,为什么
console.log(jack.getAge())抛出错误?当引用我“存储”在变量中的函数时,我是否应该将()放在该函数的末尾,它是双向工作的,所以我不知道该使用什么

谢谢

我猜这是因为人是可见的,所以它会暴露它的所有属性

我走对了吗?这是隐藏或公开属性/方法的正确方法吗

如果你想这样做,那么是的,这是一个相当标准的方法。截至ES2015,至少还有一种方法,但(可能)会有更多的开销

还有一个问题,为什么console.log(jack.getAge());抛出错误

因为
jack
对象没有
getAge
属性,所以
jack.getAge
产生
未定义的
,这不是一个函数。
giveAge
闭包可以访问的上下文中有一个
getAge
变量(以及
age
name
),但是
jack
没有
getAge
属性

当引用我“存储”在变量中的函数时,我是否应该将()放在该函数的末尾,它是双向工作的,所以我不知道该使用什么

不,这不是双向的
jack.getName
获取对函数的引用
jack.getName()
调用函数并获取其返回值

我应该注意到,
getAge
函数没有意义。只有在
person
函数中定义的闭包才能访问它,就像
age
name
一样。因此,任何使用
getAge
的方法都只需使用
age
,并避免函数调用


为了完整起见,我要指出,许多人并不担心JavaScript中真正的私有属性,而是选择“按约定私有”——例如,他们使用命名约定(例如以
\uuu
开头的名称)来表示“不要碰这些,它们是私有的。”当然,这并不能阻止人们使用它们,这只是表明他们不应该这样做。提倡这一点的人通常会指出,在许多具有“真正”私有属性/字段的语言(Java、C#)中,这些属性/字段只需通过反射进行少量操作即可访问。因此,论点是,仅使用命名约定是“作为私有的”

我并不同意(也不是特别不同意)这一点,它确实需要更多的Java或C语言来访问私有属性,而不是公共属性。我只是注意到“按惯例私有”的方法非常普遍,而且常常“足够好”

我猜这是因为人是可见的,所以它会暴露它的所有属性

我走对了吗?这是隐藏或公开属性/方法的正确方法吗

如果你想这样做,那么是的,这是一个相当标准的方法。截至ES2015,至少还有一种方法,但(可能)会有更多的开销

还有一个问题,为什么console.log(jack.getAge());抛出错误

因为
jack
对象没有
getAge
属性,所以
jack.getAge
产生
未定义的
,这不是一个函数。
giveAge
闭包可以访问的上下文中有一个
getAge
变量(以及
age
name
),但是
jack
没有
getAge
属性

当引用我“存储”在变量中的函数时,我是否应该将()放在该函数的末尾,它是双向工作的,所以我不知道该使用什么

不,这不是双向的
jack.getName
获取对函数的引用
jack.getName()
调用函数并获取其返回值

我应该注意到,
getAge
函数没有意义。只有在
person
函数中定义的闭包才能访问它,就像
age
name
一样。因此,任何使用
getAge
的方法都只需使用
age
,并避免函数调用


为了完整起见,我要指出,许多人并不担心JavaScript中真正的私有属性,而是选择“按约定私有”——例如,他们使用命名约定(例如以
\uuu
开头的名称)来表示“不要碰这些,它们是私有的。”当然,这并不能阻止人们使用它们,这只是表明他们不应该这样做。提倡这一点的人通常会指出,在许多具有“真正”私有属性/字段的语言(Java、C#)中,这些属性/字段只需通过反射进行少量操作即可访问。因此,论点是,仅使用命名约定是“作为私有的”

我并不同意(也不是特别不同意)这一点,它确实需要更多的Java或C语言来访问私有属性,而不是公共属性。我只是注意到“按惯例私有”的方法非常普遍,而且常常“足够好”

我想这是因为人是可见的,所以它是透明的
function fakeNew(constructor, ...args){
    if(typeof constructor !== "function"){
        throw new TypeError(constructor + " is not a constructor");
    }

    //create a new Instance of the constructors prototype-property
    var instance = Object.create(constructor.prototype);

    //invoke the constructor with the scope set to the instance and the provided arguments
    var result = constructor.apply(instance, args);

    //check wether the returned value is an Object (and functions are considered as Objects)
    if(result === Object(result)){
        //then return the result-value in favor to the instance
        return result;
    }

    //otherwise return the instance
    return instance;
}
var jack = person("Jack", 30);  //would result in the following desaster:
console.log(jack);      //undefined, since person doesn't return anthing

console.log(jack.getName());    
//will throw, since jack is still undefined, and therefore doesn't have any properties

//BUT:
console.log(window.getName())   //will return "Jack" now

console.log(window.getAge);     //undefined, but this is fine 
//global scope has not been polluted with this one, cause getAge was a local variable inside the function-call

console.log(window.giveAge())   //can still call the enclosed (private) function getAge()
var jill = person("Jill", 28);
//will overwrite the global functions and expose new values now
console.log(window.getName(), window.giveAge()) //"Jill", 28    
//and Jack is kind of gone, well the variable is left but the variable contained undefined, so...
//first let's add a function that executes on the scope
//inside the constructor
this.getNameAndAge = function(){
    return this.getName() + ": " + getAge();
}
var andy = new person("Andy", 45);
var joe = new person("Joe", 32);

//let's make Andy a little younger
andy.getNameAndAge = joe.getNameAndAge;
console.log(andy.getNameAndAge(), andy.getName() + ": " + andy.giveAge());
//will result in "Andy: 32", "Andy": 45
funciton Animal(species, _name){
    //species is likewise a local variable and can be enclosed, modified, or whatever
    //we don't need to write it to some different variable

    //but we want to expose the name of this animal, since it should be possible to change it later
    //without the need to create a getter and a setter just to change the property of _name
    this.name = _name;

    this.whoAreYou = function(){
        //so we concat the enclosed value from species with the name-argument on this object
        //in the hope that everything will be alright.
        return species + " " + this.name;
    }
}

var jack = new Animal("dog", "Jack");
var jill = new Animal("cat", "Jill");
var joe = new Animal("fish", "Joe");

console.log(jack.whoAreYou());  //"dog Jack"
console.log(jill.whoAreYou());  //"cat Jill"
console.log(joe.whoAreYou());   //"fish Joe"

//as far so good; till now ...
//since these properties are still writable someone will start and move them around

//maybe like a callback
function someFunction(someArg, callback){
    console.log(someArg, callback());
}
someFunction("Who are you?", jack.whoAreYou);

//or sth. like this:
//you may not believe that someone would ever do that, but it will happen!
jack.whoAreYou = jill.whoAreYou;
console.log(jack.whoAreYou());

//and now the poor dog has an Identity-crisis.
//the first one will result in:
"Who are you?", "dog undefined"

//the latter will log "cat Jack"

or even more fummy if sth. like this happens:

var fn = joe.whoAreYou;
console.log(fn.call(jack), fn.call(jill), fn.call(joe), fn.call(Animal));
//cause now they are all fishes, even the Animal-constuctor
var getAge = function() {
    return age;
}
var person = function(){
    //...
    foo();
    bar();
    baz();

    function foo(){ console.log("this will work"); }
    var bar = function(){ console.log("this will fail"); }
    //because to this point, bar was delared and assigned with undefined, 
    //and we remember? undefined can't be invoked

    return whatever;

    function baz(){ console.log("event this would work"); }
    //unless some preprocessor decided (falsely), that this function can be removed 
    //since it is after the return-statement, and is therefore unreachable
}