それが原因だと思います person が表示されているため、そのすべてのプロパティが公開されています。
ではない正確に。まず、 person は正規関数です。new-keyword なしで完全に呼び出すことができますが、その結果、アプリケーション全体が壊れてしまいます。
その理由を理解するには、まず new-keyword が舞台裏で何をしているのかを理解する必要があります。これは js 実装になります。
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
うわぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁぁ
public メソッド getNameAndAge をオーバーライドしました。名前は、現在の Object
で (これも public) メソッド getName() を呼び出すことによってアクセスされます。
しかし、giveAge() は、この特定の「getNameAndAge 関数のインスタンス」が宣言されたスコープからの囲まれた変数のままであるため、Joe の関数呼び出しからのものです。
この影響を理解するために、スコーピングをさらに奇妙にしましょう
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
これが悪いとか、避けるべきだと言いたいわけではありませんが、それが機能する方法があり、それを考慮する必要があります。
この方法により、プロトタイプの継承が提供され、常にラッパーメソッドを作成することなく、ミックスインを作成する優れた方法が提供されます。
これは、「私は自分のプライベートな状態を確保する必要がある」または「あなたが私に提供する環境で仕事をしている」と見なすことができます。
もう 1 つの質問は、なぜ console.log(jack.getAge()); を実行するのかということです。エラーをスローしますか?
jack.getAge は undefined で undefined は関数ではないため
var getAge = function() {
return age;
}
この行への別のコメント
JS では、関数宣言と変数宣言が巻き上げられるため、関数の最初から使用できます。式はそうではありません。
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
}