ActionScript 3.0, ActionScript nesnelerini JavaScript Nesne Gösterimi (JSON) biçimi kullanarak kodlamak ve bunların kodunu çözmek için yerel bir API sağlar. JSON sınıfı ve destekleyici öğe işlevleri, çok az farkla ECMA-262 5. sürüm belirtimini izler.
Topluluk üyesi Todd Anderson, yerel JSON API ve üçüncü taraf as3corelib JSON sınıfının bir karşılaştırmasını sağlamaktadır. Bkz.
Working with Native JSON in Flash Player 11
(Flash Player 11'de Yerel JSON ile Çalışma).
JSON API'sine genel bakış
ActionScript JSON API'si, JSON sınıfı ve birkaç yerel sınıftaki
toJSON()
üye işlevlerinden oluşur. Herhangi bir sınıfa yönelik özel JSON kodlaması gerektiren uygulamalar için ActionScript çerçevesi, varsayılan kodlamayı geçersiz kılmaya yönelik yollar sağlar.
JSON sınıfı,
toJSON()
üyesi sağlamayan herhangi bir ActionScript sınıfı için içe aktarmayı ve dışa aktarmayı dahili olarak işler. Bu durumlar için JSON, karşılaştığı her nesnenin ortak özelliklerine çapraz geçiş uygular. Bir nesne başka nesneler içeriyorsa JSON, yuvalanmış nesnelerde yinelenir ve aynı çapraz geçişi gerçekleştirir. Herhangi bir nesne
toJSON()
yöntemi sunuyorsa JSON, iç algoritmaları yerine bu özel yöntemi kullanır.
JSON arabirimi
stringify()
kodlama yöntemi ve
parse()
kod çözme yönteminden oluşur. Bu yöntemlerin her biri, JSON kodlama veya kod çözme iş akışına kendi mantığınızı eklemenize olanak tanıyan bir parametre sağlar. Bu parametre,
stringify()
için
replacer
,
parse()
için ise
reviver
olarak adlandırılır. Bu parametreler, aşağıdaki imzayı kullanarak iki bağımsız değişkenli bir işlev tanımı alır:
function(k, v):*
toJSON() yöntemleri
toJSON()
yönteminin imzası şudur:
public function toJSON(k:String):*
Varsa,
JSON.stringify()
öğesi, nesne çapraz geçişi sırasında karşılaştığı her bir ortak özellik için
toJSON()
öğesini çağırır. Özellik anahtar-değer çiftinden oluşur.
stringify(
,
toJSON()
öğesini çağırdığında o anda incelemekte olduğu özelliğin anahtarını (
k
) iletir. Tipik bir
toJSON()
uygulaması, her bir özellik adını inceler ve istenen kodlama değerini getirir.
toJSON()
yöntemi, yalnızca bir String öğesini değil herhangi bir türün değerini (* olarak belirtilen) döndürebilir. Bu değişken döndürme türü
toJSON()
öğesinin bir nesneyi, uygunsa, döndürmesine olanak tanır. Örneğin, özel sınıfınızın bir özelliği üçüncü taraf bir kütüphaneden nesne içeriyorsa, bu nesneyi
toJSON()
özelliğinizle karşılaştığında döndürebilirsiniz. Sonrasında JSON üçüncü taraf nesnesinde yinelenir. Kodlama işlem akışı aşağıdaki şekilde davranır:
-
toJSON()
öğesi, dizeyi değerlendirmeyen bir nesne döndürürse
stringify()
öğesi bu nesnede yinelenir.
-
toJSON()
bir dize döndürürse,
stringify()
bu değeri başka bir dizede sarar, sarılmış dizeyi döndürür ve ardından bir sonraki değere geçer.
Birçok durumda, bir nesne döndürmek uygulamanız tarafından oluşturulan JSON dizesini döndürmeye tercih edilir. Bir nesne döndürmek, yerleşik JSON kodlaması algoritmasından faydalanır ve ayrıca JSON öğesinin yuvalanmış nesnelerde yinelenmesine izin verir.
toJSON()
yöntemi, Object sınıfı veya diğer birçok yerel sınıfta tanımlanmaz. Yokluğu, JSON'a nesnenin ortak özellikleri üzerinde standart çapraz geçişini gerçekleştirmesini belirtir. İsterseniz, nesnenizin özel özelliklerini göstermek için
toJSON()
öğesini de kullanabilirsiniz.
Birkaç yerel sınıf, ActionScript kütüphanelerinin tüm kullanma durumları için etkin bir şekilde çözemediği güçlüklere neden olur. ActionScript, bu sınıflar için, istemcilerin ihtiyaçlarına uyması için yeniden uygulayabileceği küçük bir uygulama sağlar. Önemsiz
toJSON()
üyeleri sağlayan sınıflar şunlardır:
-
ByteArray
-
Date
-
Dictionary
-
XML
ByteArray sınıfını,
toJSON()
yönteminin üzerine yazmak için alt sınıflandırabilirsiniz veya sınıfın prototipini yeniden tanımlayabilirsiniz. Son olarak belirtilen Date ve XML sınıfları,
toJSON()
öğesini yeniden tanımlamak için sınıf prototipini kullanmanızı gerektirir. Dictionary sınıfı dinamik olarak belirtilir ve bu size
toJSON()
öğesinin üzerine yazmanız için fazladan özgürlük verir.
Özel JSON davranışını tanımlama
Yerel sınıflar için kendi JSON kodlamanızı ve kod çözme işleminizi uygulamak için birkaç seçenek arasından seçim yapabilirsiniz:
-
Nihai olmayan yerel bir sınıfın özel alt sınıfında
toJSON()
öğesini tanımlama veya geçersiz kılma
-
Sınıf prototipinde
toJSON()
öğesini tanımlama veya yeniden tanımlama
-
Dinamik bir sınıfta
toJSON
özelliğini tanımlama
-
JSON.stringify() replacer
ve
JSON.parser() reviver
parametrelerini kullanma
toJSON() öğesini yerleşik bir sınıf prototipinde tanımlama
ActionScript'teki yerel JSON uygulaması, ECMA-262, 5. sürümde tanımlanan ECMAScript JSON mekanizmasını yansıtır. ECMAScript, sınıfları desteklemediğinden ActionScript, JSON davranışını prototip bazlı gönderme bakımından tanımlar. Prototipler benzetilmiş devralma işleminin yanı sıra üye eklentilerine ve yeniden tanımlamalarına izin veren ActionScript 3.0 sınıfı habercileridir.
ActionScript,
toJSON()
öğesini herhangi bir sınıf prototipinde tanımlamanıza ve yeniden tanımlamanıza olanak tanır. Bu ayrıcalık, son olarak işaretlenmiş sınıflar için bile geçerlidir.
toJSON()
öğesini bir sınıf prototipinde tanımladığınızda tanımınız, uygulama alanınızda bu sınıfın tüm örnekleri için geçerli olur. Örneğin burada bir
toJSON()
yöntemini MovieClip prototipinde nasıl tanımlayabileceğiniz bulunmaktadır:
MovieClip.prototype.toJSON = function(k):* {
trace("prototype.toJSON() called.");
return "toJSON";
}
Sonrasında uygulamanız
stringify()
öğesini herhangi bir MovieClip örneğinde çağırdığında
stringify()
öğesi,
toJSON()
yönteminizin çıktısını döndürür:
var mc:MovieClip = new MovieClip();
var js:String = JSON.stringify(mc); //"prototype toJSON() called."
trace("js: " + js); //"js: toJSON"
Ayrıca yöntemi tanımlayan yerel sınıflarda
toJSON()
öğesini geçersiz kılabilirsiniz. Örneğin, aşağıdaki kod
Date.toJSON()
öğesini geçersiz kılar:
Date.prototype.toJSON = function (k):* {
return "any date format you like via toJSON: "+
"this.time:"+this.time + " this.hours:"+this.hours;
}
var dt:Date = new Date();
trace(JSON.stringify(dt));
// "any date format you like via toJSON: this.time:1317244361947 this.hours:14"
Sınıf düzeyinde toJSON() öğesini tanımlama veya geçersiz kılma
toJSON()
öğesini yeniden tanımlamak üzere prototipleri kullanmak için uygulamalara her zaman gerek yoktur. Üst sınıf nihai olarak işaretlenmemişse
toJSON()
öğesini bir alt sınıfın üyesi olarak tanımlayabilirsiniz. Örneğin, ByteArray sınıfını genişletebilir ve genel bir
toJSON()
işlevi belirtebilirsiniz:
package {
import flash.utils.ByteArray;
public class MyByteArray extends ByteArray
{
public function MyByteArray() {
}
public function toJSON(s:String):*
{
return "MyByteArray";
}
}
}
var ba:ByteArray = new ByteArray();
trace(JSON.stringify(ba)); //"ByteArray"
var mba:MyByteArray = new MyByteArray(); //"MyByteArray"
trace(JSON.stringify(mba)); //"MyByteArray"
Bir sınıf dinamikse bu sınıfın nesnesine
toJSON
özelliğini ekleyebilirsiniz ve buna aşağıda olduğu gibi bir işlev atayabilirsiniz:
var d:Dictionary = new Dictionary();
trace(JSON.stringify((d))); // "Dictionary"
d.toJSON = function(){return {c : "toJSON override."};} // overrides existing function
trace(JSON.stringify((d))); // {"c":"toJSON override."}
toJSON()
öğesini herhangi bir ActionScript sınıfında geçersiz kılabilir, tanımlayabilir veya yeniden tanımlayabilirsiniz. Ancak, çoğu yerleşik ActionScript sınıfı
toJSON()
öğesini tanımlamaz. Object sınıfı
toJSON
öğesini kendi varsayılan prototipinde tanımlamaz veya onu bir sınıf üyesi olarak bildirmez. Yerel sınıfların yalnızca çok azı yöntemi bir prototip işlevi olarak tanımlar. Bu nedenle
toJSON()
öğesini çoğu sınıfta geleneksel anlamda geçersiz kılamazsınız.
toJSON()
öğesini tanımlamayan yerel sınıflar dahili JSON uygulaması tarafından JSON öğesine serileştirilirler. Mümkünse bu yerleşik işlevi değiştirmekten kaçının. Bir
toJSON()
öğesi tanımlarsanız, JSON sınıfı kendi işlevselliği yerine sizin mantığınızı kullanır.
JSON.stringify() değiştirici parametresini kullanma
Prototip üstünde
toJSON()
öğesinin üzerine yazma, uygulamada bir sınıfın JSON dışa aktarma davranışını değiştirmek için yararlıdır. Ancak bazı durumlarda, dışa aktarma mantığınız yalnızca geçici koşullar altındaki özel durumlar için geçerli olabilir. Böyle küçük kapsam değişikliklerini düzenlemek için
JSON.stringify()
yönteminin
replacer
parametresini kullanabilirsiniz.
stringify()
yöntemi,
replacer
parametresinden kodlanmakta olan nesneye geçirilen işlevi uygular. Bu işlevin imzası
toJSON()
öğesininkine benzer:
function (k,v):*
toJSON()
öğesinden farklı olarak,
replacer
işlevi anahtarın (
k
) yanı sıra değeri de (
v
) gerektirir. Bu farklılık,
stringify()
öğesi, kodlanmakta olan nesne yerine statik JSON nesnesinde arandığı için gereklidir.
JSON.stringify()
öğesi,
replacer(k,v)
öğesini çağırdığında orijinal girdi nesnesini çapraz geçiyordur.
replacer
işlevine iletilen örtük
this
parametresi, anahtarı ve değeri tutan nesne ile ilgilidir.
JSON.stringify()
öğesi, orijinal girdi nesnesini değiştirmediği için bu nesne kapsayıcıda çapraz geçirilerek değiştirilmemiş olarak kalır. Bu nedenle, orijinal nesnedeki anahtarı sorgulamak için
this[k]
kodunu kullanabilirsiniz.
v
parametresi,
toJSON()
öğesinin dönüştürdüğü değeri tutar.
toJSON()
gibi,
replacer
işlevi de herhangi bir değer türünü döndürebilir.
replacer
öğesi bir dize döndürürse JSON motoru, tırnak içindeki içeriklerden kurtulur ve ardından kurtulan içerikleri tırnak içine kaydırır. Bu kaydırma işlemi,
stringify()
öğesinin,
JSON.parse()
öğesini sonraki çağırışında bir dize olarak kalan geçerli bir JSON dizesi nesnesini almasını garantiler.
Aşağıdaki kod,
replacer
parametresi ile örtük
this
parametresini, Date nesnesinin
time
ve
hours
değerlerini döndürmek için kullanır:
JSON.stringify(d, function (k,v):* {
return "any date format you like via replacer: "+
"holder[k].time:"+this[k].time + " holder[k].hours:"+this[k].hours;
});
JSON.parse() reviver parametresini kullanma
JSON.parse()
yönteminin
reviver
parametresi,
replacer
işlevinin tersini yapar: JSON dizesini kullanılabilir bir ActionScript nesnesine dönüştürür.
reviver
bağımsız değişkeni, iki parametre alan ve herhangi bir tür döndüren bir işlevdir:
function (k,v):*
Bu işlevde,
k
öğesi bir anahtardır ve
v
öğesi,
k
öğesinin değeridir.
stringify()
öğesi gibi
parse()
öğesi, JSON anahtar-değer çiftlerini çapraz geçer ve varsa,
reviver
işlevini her bir çifte uygular. Olası bir problem, JSON sınıfının, bir nesnenin ActionScript sınıfı adının çıktısını almamasıdır. Bu nedenle, ne tür bir nesnenin kullanıma geçirileceğini bilmek zorlu olabilir. Bu problem özellikle nesneler iç içe geçmiş olduğu zaman sorun olabilir.
toJSON()
,
replacer
ve
reviver
işlevlerinin tasarlanması sırasında, orijinal nesneleri bozulmadan tutarken dışa aktarılan ActionScript nesnelerini tanımlamak için yollar bulabilirsiniz.
Ayrıştırma örneği
Aşağıdaki örnek, JSON dizelerinden ayrıştırılan nesneleri kullanıma geçirmek için bir strateji göstermektedir. Bu örnek iki sınıfı tanımlar: JSONGenericDictExample ve JSONDictionaryExtnExample. JSONGenericDictExample sınıfı özel bir sözlük sınıfıdır. Her kayıt, bir kişinin eşsiz kimliğinin yanı sıra adını ve doğum tarihini içerir. JSONGenericDictExample yapıcısı her çağrıldığında yeni oluşturulan nesneyi, kimlik olarak statik olarak artan bir tamsayı ile dahili bir statik dizeye ekler. JSONGenericDictExample sınıfı, daha uzun olan
id
üyesinden sadece tamsayı kısmını ayıklayan
revive()
yöntemini tanımlar.
revive()
yöntemi bu tamsayıyı, kullanıma geçirilebilir doğru nesneyi arayıp bulması ve döndürmesi için kullanır.
JSONGenericDictExample sınıfı, ActionScript Dictionary sınıfını genişletir. Kayıtları küme yapısına sahip değildir ve herhangi bir veriyi içerebilir. Veri, sınıf tanımlı özellikler olarak atanmak yerine, JSONDictionaryExtnExample nesnesi oluşturulduktan sonra atanır. JSONDictionaryExtnExample kayıtları anahtar olarak JSONGenericDictExample nesnelerini kullanır. Bir JSONDictionaryExtnExample nesnesi kullanıma geçirildiğinde
JSONGenericDictExample.revive()
işlevi, doğru anahtar nesnesini almak için JSONDictionaryExtnExample ile ilişkili kimliği kullanır.
En önemlisi,
JSONDictionaryExtnExample.toJSON()
yönteminin, JSONDictionaryExtnExample nesnesine ek olarak bir işaretleyici dize döndürmesidir. Bu dize, JSON çıktısını JSONDictionaryExtnExample sınıfına aitmiş gibi tanımlar. Bu işaretleyici,
JSON.parse()
sırasında hangi nesne türünün işlendiği konusunda hiçbir şüphe bırakmaz.
package {
// Generic dictionary example:
public class JSONGenericDictExample {
static var revivableObjects = [];
static var nextId = 10000;
public var id;
public var dname:String;
public var birthday;
public function JSONGenericDictExample(name, birthday) {
revivableObjects[nextId] = this;
this.id = "id_class_JSONGenericDictExample_" + nextId;
this.dname = name;
this.birthday = birthday;
nextId++;
}
public function toString():String { return this.dname; }
public static function revive(id:String):JSONGenericDictExample {
var r:RegExp = /^id_class_JSONGenericDictExample_([0-9]*)$/;
var res = r.exec(id);
return JSONGenericDictExample.revivableObjects[res[1]];
}
}
}
package {
import flash.utils.Dictionary;
import flash.utils.ByteArray;
// For this extension of dictionary, we serialize the contents of the
// dictionary by using toJSON
public final class JSONDictionaryExtnExample extends Dictionary {
public function toJSON(k):* {
var contents = {};
for (var a in this) {
contents[a.id] = this[a];
}
// We also wrap the contents in an object so that we can
// identify it by looking for the marking property "class E"
// while in the midst of JSON.parse.
return {"class JSONDictionaryExtnExample": contents};
}
// This is just here for debugging and for illustration
public function toString():String {
var retval = "[JSONDictionaryExtnExample <";
var printed_any = false;
for (var k in this) {
retval += k.toString() + "=" +
"[e="+this[k].earnings +
",v="+this[k].violations + "], "
printed_any = true;
}
if (printed_any)
retval = retval.substring(0, retval.length-2);
retval += ">]"
return retval;
}
}
}
Aşağıdaki çalışma zamanı komut dosyası JSONDictionaryExtnExample nesnesinde
JSON.parse()
öğesini çağırdığında,
reviver
işlevi JSONDictionaryExtnExample öğesindeki her nesnede
JSONGenericDictExample.revive()
öğesini çağırır. Bu çağrı nesne anahtarını temsil eden kimliği ayıklar.
JSONGenericDictExample.revive()
işlevi saklanan JSONDictionaryExtnExample nesnesini özel statik bir diziden almak ve döndürmek için bu kimliği kullanır.
import flash.display.MovieClip;
import flash.text.TextField;
var a_bob1:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("01/02/1934")));
var a_bob2:JSONGenericDictExample = new JSONGenericDictExample("Bob", new Date(Date.parse("05/06/1978")));
var a_jen:JSONGenericDictExample = new JSONGenericDictExample("Jen", new Date(Date.parse("09/09/1999")));
var e = new JSONDictionaryExtnExample();
e[a_bob1] = {earnings: 40, violations: 2};
e[a_bob2] = {earnings: 10, violations: 1};
e[a_jen] = {earnings: 25, violations: 3};
trace("JSON.stringify(e): " + JSON.stringify(e)); // {"class JSONDictionaryExtnExample":
//{"id_class_JSONGenericDictExample_10001":
//{"earnings":10,"violations":1},
//"id_class_JSONGenericDictExample_10002":
//{"earnings":25,"violations":3},
//"id_class_JSONGenericDictExample_10000":
// {"earnings":40,"violations":2}}}
var e_result = JSON.stringify(e);
var e1 = new JSONDictionaryExtnExample();
var e2 = new JSONDictionaryExtnExample();
// It's somewhat easy to convert the string from JSON.stringify(e) back
// into a dictionary (turn it into an object via JSON.parse, then loop
// over that object's properties to construct a fresh dictionary).
//
// The harder exercise is to handle situations where the dictionaries
// themselves are nested in the object passed to JSON.stringify and
// thus does not occur at the topmost level of the resulting string.
//
// (For example: consider roundtripping something like
// var tricky_array = [e1, [[4, e2, 6]], {table:e3}]
// where e1, e2, e3 are all dictionaries. Furthermore, consider
// dictionaries that contain references to dictionaries.)
//
// This parsing (or at least some instances of it) can be done via
// JSON.parse, but it's not necessarily trivial. Careful consideration
// of how toJSON, replacer, and reviver can work together is
// necessary.
var e_roundtrip =
JSON.parse(e_result,
// This is a reviver that is focused on rebuilding JSONDictionaryExtnExample objects.
function (k, v) {
if ("class JSONDictionaryExtnExample" in v) { // special marker tag;
//see JSONDictionaryExtnExample.toJSON().
var e = new JSONDictionaryExtnExample();
var contents = v["class JSONDictionaryExtnExample"];
for (var i in contents) {
// Reviving JSONGenericDictExample objects from string
// identifiers is also special;
// see JSONGenericDictExample constructor and
// JSONGenericDictExample's revive() method.
e[JSONGenericDictExample.revive(i)] = contents[i];
}
return e;
} else {
return v;
}
});
trace("// == Here is an extended Dictionary that has been round-tripped ==");
trace("// == Note that we have revived Jen/Jan during the roundtrip. ==");
trace("e: " + e); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], Bob=[e=10,v=1],
//Jen=[e=25,v=3]>]
trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample <Bob=[e=40,v=2],
//Bob=[e=10,v=1], Jen=[e=25,v=3]>]
trace("Is e_roundtrip a JSONDictionaryExtnExample? " + (e_roundtrip is JSONDictionaryExtnExample)); //true
trace("Name change: Jen is now Jan");
a_jen.dname = "Jan"
trace("e: " + e); //[JSONDictionaryExtnExample <Bob=[e=40,v=2], Bob=[e=10,v=1],
//Jan=[e=25,v=3]>]
trace("e_roundtrip: " + e_roundtrip); //[JSONDictionaryExtnExample <Bob=[e=40,v=2],
//Bob=[e=10,v=1], Jan=[e=25,v=3]>]
|
|
|