19

John Resig の「 Pro Javascript Techniques 」を読んでいて、例と混同しています。これはコードです:

// Create a new user object that accepts an object of properties
function User( properties ) {
  // Iterate through the properties of the object, and make sure
  // that it's properly scoped (as discussed previously)
  for ( var i in properties ) { (function(){
  // Create a new getter for the property
  this[ "get" + i ] = function() {
    return properties[i];
  };
  // Create a new setter for the property
  this[ "set" + i ] = function(val) {
    properties[i] = val;
  };
})(); }
}

// Create a new user object instance and pass in an object of
// properties to seed it with
var user = new User({
  name: "Bob",
  age: 44
});

// Just note that the name property does not exist, as it's private
// within the properties object
alert( user.name == null );

// However, we're able to access its value using the new getname()
// method, that was dynamically generated
alert( user.getname() == "Bob" );

// Finally, we can see that it's possible to set and get the age using
// the newly generated functions
user.setage( 22 );
alert( user.getage() == 22 );

これを Firebug コンソール (FF3) で実行すると、user.getname() が関数ではないことがスローされます。私はこれをやってみました:

var other = User
other()
window.getname() --> this works!

そしてそれは働いた!

理由はありますか?みんなありがとう!

PS: この本を強くお勧めします。

編集:

やっている:

var me = this;

少しうまくいくようですが、「getname()」を実行すると「44」(2 番目のプロパティ) が返されます...

また、変更せずにウィンドウオブジェクトで機能したのも奇妙だと思います...

3 番目の質問は、PEZ ソリューションとオリジナルの違いは何ですか? (彼は無名関数を使用しません)

フィードバックをお寄せいただきありがとうございます。+1

4

8 に答える 8

5

newJavaScriptで作業するときは、キーワードをまったく使用しないのが最善だと思います。

これは、誤って new キーワード (例: ) を使用せずvar user = User()にオブジェクトをインスタンス化すると、*非常に悪いことが起こるためです...* 関数内で (newキーワードなしでインスタンス化された場合)、thisが参照するためです。グローバルオブジェクト、つまりwindow...

したがって、クラスのようなオブジェクトを使用する方法について、より良い方法を提案します。

次の例を考えてみましょう:

var user = function (props) {
    var pObject = {};
    for (p in props) {
        (function (pc) {
            pObject['set' + pc] = function (v) {
                props[pc] = v;
                return pObject;
            }
            pObject['get' + pc] = function () {
                return props[pc];
            }
        })(p);
    }
    return pObject;
}

上記の例では、関数内に新しいオブジェクトを作成し、この新しく作成されたオブジェクトにゲッターとセッターをアタッチしています。

最後に、この新しく作成されたオブジェクトを返します。thethisキーワードはどこにも使用されていないことに注意してください

次に、 a を「インスタンス化」するuserには、次のようにします。

var john = user({name : 'Andreas', age : 21});
john.getname(); //returns 'Andreas'
john.setage(19).getage(); //returns 19

落とし穴に陥るのを避ける最善の方法は、そもそもそれらを作成しないことです...上記の例では、newキーワードの落とし穴を回避しています(前述のように、使用されるはずのキーワードを使用しないnewと悪いことが起こります)一切使用newしないでください。

于 2008-12-19T13:57:08.120 に答える
4

編集:今、ジェイソンの答えを適応させると、うまくいきます:

値のクロージャを作成する必要があります。1 つの方法を次に示します。

function bindAccessors(o, property, value) {
  var _value = value;
  o["get" + property] = function() {
    return _value;
  };
  o["set" + property] = function(v) {
    _value = v;
  };
}

次に、User コンストラクターは次のようになります。

function User( properties ) {
  for (var i in properties ) {
    bindAccessors(this, i, properties[i]);
  }
}
于 2008-12-18T12:58:40.193 に答える
3

おそらく、次のような読みやすいものが必要になるでしょう: (クロージャは、練習すれば簡単に習得できます)

function User( properties ) {
  // helper function to create closures based on passed-in arguments:
  var bindGetterSetter = function(obj,p,properties)
  {
    obj["get"+p]=function() { return properties[p]; }
    obj["set"+p]=function(val) { properties[p]=val; return this; }
  };
  for (var p in properties)
    bindGetterSetter(this, p, properties);
}

「これを返す」も追加しました。あなたができるように:

u=new User({a: 1, b:77, c:48});
u.seta(3).setb(20).setc(400)
于 2008-12-18T16:26:43.720 に答える
3

なぜそのようなことが起こったのかを知るという唯一の目的でこの投稿を始めましたが、ついにそうしました. したがって、「なぜ」に興味を持っている人が他にいる場合は、次のとおりです。

無名関数内で「this」が変化するのはなぜですか?

オブジェクトまたは別の関数内で宣言された匿名関数であっても、新しい関数は常にスコープを変更します。この場合、グローバル スコープ (ウィンドウ) に戻ります。

解決策:投稿にすべて記載されていますが、.call(this)を使用して匿名関数を実行する方が明確だと思います

getname() が常に年齢を返すのはなぜですか?

匿名関数はすぐに実行されますが、ゲッター/セッターは呼び出されたときに初めて実行されます。その瞬間、iの値は常に最後になります。これは、すべてのプロパティに対して既に反復処理が行われているためです...そして、最後の値である properties[i] を常に返します。この場合は age です。

解決策: i 値を次のような変数に保存します

 for ( i in properties ) { (function(){ 
  var j = i
  //from now on use properties[j]

私はこれを学ぼうとしているので、私が言ったことに間違っている場合は、私を修正してください...

再度、感謝します。

于 2008-12-19T13:14:30.403 に答える
2

このようにコードを少し変更しました..これは動作するはずです..これは、me = this; を設定するのと同じです。ただし、各プロパティの値を適切に設定するにはクロージャが必要です。そうしないと、最後の値がすべてのプロパティに割り当てられます。

    // Create a new user object that accepts an object of properties
    var User = function( properties ) {
      // Iterate through the properties of the object, and make sure
      // that it's properly scoped (as discussed previously)
      var THIS = this;
      for ( var i in properties ) { (function(i){
      // Create a new getter for the property
      THIS[ "get" + i ] = function() {
        return properties[i];
      };
      // Create a new setter for the property
      THIS[ "set" + i ] = function(val) {
        properties[i] = val;
      };
    })(i); }
    }

    // Create a new user object instance and pass in an object of
    // properties to seed it with
    var user = new User({
      name: "Bob",
      age: 44
    });

// Just note that the name property does not exist, as it's private
// within the properties object
alert( user.name == null );

// However, we're able to access its value using the new getname()
// method, that was dynamically generated
alert( user.getname() == "Bob" );

// Finally, we can see that it's possible to set and get the age using
// the newly generated functions
user.setage( 22 );
alert( user.getage() == 22 );
于 2011-10-31T06:21:26.783 に答える
2

OPに書かれているようthisに、ループ内では User オブジェクトを参照していません。ループの外側でその変数をキャプチャすると、それを機能させることができます。

function User( properties ) {
  // Iterate through the properties of the object, and make sure
  // that it's properly scoped (as discussed previously)
 var me = this;
 for ( i in properties ) { (function(){
  // Create a new getter for the property
  me[ "get" + i ] = function() {
    return properties[i];
  };
  // Create a new setter for the property
  me[ "set" + i ] = function(val) {
    properties[i] = val;
  };
 // etc
于 2008-12-18T13:08:57.253 に答える
1

変数iは、反復の最後の値 (「年齢」) で「閉じられている」のでしょうか? 次に、すべての getter と setter が properties["age"] にアクセスします。

于 2008-12-18T15:15:39.323 に答える