2009-07-05 17 views
5

JSONデータを逆シリアル化して各オブジェクトのプロトタイプを更新し、共通の機能を継承しようとしています。評価版のデシリアライズ後にJavaScriptのプロトタイプが定義されていません

ただし、次のスクリプトは「people [0] .getFullNameは関数ではありません」というエラーをスローします。デシリアライズされたオブジェクトのプロトタイプは、割り当て後に定義されていないように見えます。

<html> 
<head> 
<script> 
var json = '[ {"firstName": "John", "lastName": "Smith"}, {"firstName": "Nancy", "lastName": "Jones"} ]'; 
var people; 
eval('people = ' + json); 

function Person() { } 

Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i].prototype = new Person(); 
} 


if(people[0].getFullName() !== 'John Smith') 
    alert('Expected fullname to be John Smith but was ' + people[0].getFullName()); 
</script> 
</head> 
</html> 

答えて

2

prototypeプロパティがコンストラクタのではなく、インスタンスの財産です。悪いニュースは、それはすべてのブラウザでは動作しませんことです

people[i].__proto__ = new Person(); 

:何あなたが探していることは財産__proto__です。 FirefoxやSafariで動作しますが、IEでは動作しません。別の方法として、コンストラクタを使用して人の配列をインスタンス化する方法があります。

function Person(obj) { 
    for (var property in obj) { 
     this[property] = obj[property]; 
    } 
    return this; 
} 
Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

var people; 
eval('people = ' + json); 
for(var i=0; i < people.length; i++) { 
    people[i] = new Person(people[i]); 
} 
+0

CTORのプロパティコピーループは、私がやろうとしているものに対して、最も遅い解決策を提供します。どうも! –

4

がリンクしている()は、x = 新しい人によって作成されたオブジェクトxは、/ Person.prototypeから継承しますが、限りECMA標準が懸念しているあなたは、するためにx.prototypeを変更することはできません後でそのリンク/継承を変更する、それは "魔法の力"の新しいキーワードが所有しているだけです。
Mozillaは、非標準プロパティ__proto__でオブジェクトが作成された後、オブジェクトリンクを変更する方法を提供しているようです。

のMozillaのみ:

//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i].__proto__ = Person.prototype; 
} 

はどこでも動作するはずです:

function Person(data) { this.data = data; } 
Person.prototype.getFullName = function() { 
    return this.data.firstName + ' ' + this.data.lastName; 
} 

eval('people = ' + json); 
//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i] = new Person(people[i]); 
} 
+0

ああ...おかげで...あり、おそらくより良い方法ですが、私はこれがあなたの意図されたものですね。データargを使用して構築するクロスブラウザの例が機能します。私はこれをもう少し試してみましょう。どうも! –

2

は基本的に、あなたはPersonオブジェクトにJSONオブジェクトを取得する必要があり、その後、getFullNameだけ適用されます。残念ながら、あなたはすべてのプロパティをコピーする必要があります。私はあなたが少し働いたことを書き直しました。啓発のための

<html> 
<head> 
<script> 
//NOTE: Sending around JSON arrays leaves bad security holes for non-IE browsers (__defineSetter__) 
var json = '[ {"firstName": "John", "lastName": "Smith"}, {"firstName": "Nancy", "lastName": "Jones"} ]'; 
//Persons is just a temporary JSON array 
var persons = eval(json); 

//constructor takes optional object instance and copies all properties if it gets one 
function Person(person) { 
    if (person) { 
     for(var prop in person) 
     this[prop] = person[prop]; 
    } 
} 

//Prototype applies to all Person objects 
Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

//Create People array 
var people = new Array(); 
for(var i=0; i < persons.length; i++){ 
    people[i] = new Person(persons[i]); 
} 

//Now do your check 
if(people[0].getFullName() !== 'John Smith') 
    alert('Expected fullname to be John Smith but was ' + people[0].getFullName()); 

</script> 
</head> 
</html> 
+0

ありがとうTony。私は、実稼働環境でevalの代わりにASP.NET Sys.Serialization名前空間を使用しています。 JSONデータの送信に関する潜在的なセキュリティリスクの詳細については、興味がありますか? –

+0

を参照してください。 http://haacked.com/archive/2009/06/25/json-hijacking.aspx –

2
for(var i=0; i < people.length; i++){ 
     people[i].getFullName = Person.prototype.getFullName; } 
+0

これは、すべてのインスタンスでメソッドのコピーを作成するため、非効率的です。 – kpozin

関連する問題