Rhino çalışma zamanını kullanan mevcut bir komut dosyanız varsa ve V8 söz dizimi ile özelliklerinden yararlanmak istiyorsanız komut dosyasını V8'e taşımanız gerekir.
Rhino çalışma zamanı kullanılarak yazılan çoğu komut dosyası, ayarlama yapılmadan bir V8 çalışma zamanı kullanarak çalışabilir. Genellikle bir komut dosyasına V8 söz dizimi ve özellik eklemenin tek ön koşulu, V8 çalışma zamanını etkinleştirmektir.
Bununla birlikte, V8 çalışma zamanı etkinleştirildikten sonra komut dosyasının başarısız olmasına veya beklenmedik şekilde davranmasına neden olabilecek küçük bir grup uyumsuzluk ve başka farklılıklar da vardır. Bir komut dosyasını V8 kullanmak üzere taşırken, komut dosyası projesinde bu sorunları aramanız ve bulduğunuz sorunları düzeltmeniz gerekir.
V8 taşıma prosedürü
Bir komut dosyasını V8'e taşımak için şu prosedürü uygulayın:
- Komut dosyası için V8 çalışma zamanını etkinleştirin.
- Aşağıda listelenen uyumsuzlukları dikkatlice inceleyin. Herhangi bir uyumsuzluk olup olmadığını belirlemek için komut dosyanızı inceleyin. Bir veya daha fazla uyumsuzluk varsa sorunu gidermek ya da önlemek için komut dosyası kodunuzu ayarlayın.
- Aşağıda listelenen diğer farklılıkları dikkatlice inceleyin. Listelenen farklılıklardan herhangi birinin kodunuzun davranışını etkileyip etkilemediğini belirlemek için komut dosyanızı inceleyin. Komut dosyanızı bu davranışı düzeltecek şekilde düzenleyin.
- Tespit edilen uyumsuzlukları veya diğer farklılıkları düzelttikten sonra, V8 söz dizimini ve diğer özellikleri istediğiniz gibi kullanmak için kodunuzu güncellemeye başlayabilirsiniz.
- Kod ayarlamalarını bitirdikten sonra, beklendiği gibi çalıştığından emin olmak için komut dosyanızı kapsamlı bir şekilde test edin.
- Komut dosyanız bir web uygulaması veya yayınlanmış eklenti ise V8 düzenlemeleriyle komut dosyasının yeni bir sürümünü oluşturmanız gerekir. Kullanıcıların V8 sürümünü kullanabilmesini sağlamak için komut dosyasını bu sürümle yeniden yayınlamanız gerekir.
Uyumsuzluklar
Rhino tabanlı orijinal Apps Komut Dosyası çalışma zamanı maalesef bazı standart olmayan ECMAScript davranışlarına izin veriyordu. V8 standartlara uygun olduğundan taşıma işleminden sonra bu davranışlar desteklenmez. Bu sorunların düzeltilmemesi, V8 çalışma zamanı etkinleştirildikten sonra hatalara veya bozuk komut dosyası davranışına neden olur.
Aşağıdaki bölümlerde bu davranışların her biri ve V8'e taşıma sırasında komut dosyası kodunuzu düzeltmek için uygulamanız gereken adımlar açıklanmaktadır.
for each(variable in object)
kullanmaktan kaçının
for each (variable in object)
ifadesi JavaScript 1.6'ya eklendi ve for...of
'in lehine kaldırıldı.
Komut dosyanızı V8'e taşırken for each (variable in object)
ifadeleri kullanmaktan kaçının.
Bunun yerine for (variable in object)
işlevini kullanın:
// Rhino runtime var obj = {a: 1, b: 2, c: 3}; // Don't use 'for each' in V8 for each (var value in obj) { Logger.log("value = %s", value); } |
// V8 runtime var obj = {a: 1, b: 2, c: 3}; for (var key in obj) { // OK in V8 var value = obj[key]; Logger.log("value = %s", value); } |
Date.prototype.getYear()
kullanmaktan kaçının
Orijinal Rhino çalışma zamanında Date.prototype.getYear()
işlevi, 1900-1999 arasındaki yıllar için iki basamaklı yılları, JavaScript 1.2 ve önceki sürümlerde kullanılan diğer tarihler için ise dört basamaklı yıl olarak döndürür.
V8 çalışma zamanında Date.prototype.getYear()
, ECMAScript standartlarının gerektirdiği şekilde yıl eksi 1900 değerini döndürür.
Komut dosyanızı V8'e taşırken daima Date.prototype.getFullYear()
kullanın. Bu işlem, tarihten bağımsız olarak dört basamaklı bir yıl döndürür.
Ayrılmış anahtar kelimeleri ad olarak kullanmaktan kaçının
ECMAScript, işlev ve değişken adlarında belirli ayrılmış anahtar kelimelerin kullanılmasını yasaklar. Rhino çalışma zamanı bu kelimelerin birçoğuna izin veriyordu. Bu nedenle, kodunuzda bu kelimelerin kullanılması durumunda işlevlerinizi veya değişkenlerinizi yeniden adlandırmanız gerekir.
Komut dosyanızı V8'e taşırken değişkeni veya işlevleri ayrılmış anahtar kelimelerden birini kullanarak adlandırmaktan kaçının.
Anahtar kelime adını kullanmaktan kaçınmak için değişkenleri veya işlevleri yeniden adlandırın. Anahtar kelimelerin yaygın kullanım şekilleri şunlardır: class
, import
ve export
.
const
değişkenini yeniden atamaktan kaçının
Orijinal Rhino çalışma zamanında, const
kullanarak bir değişken bildirebilirsiniz. Bu, simgenin değerinin hiçbir zaman değişmediği ve sembole ileride yapılacak atamalar yoksayılacağı anlamına gelir.
Yeni V8 çalışma zamanında const
anahtar kelimesi standart uyumludur ve const
olarak bildirilen bir değişkene atamak TypeError: Assignment to constant variable
çalışma zamanı hatasına neden olur.
Komut dosyanızı V8'e taşırken bir const
değişkeninin değerini yeniden atamayı denemeyin:
// Rhino runtime const x = 1; x = 2; // No error console.log(x); // Outputs 1 |
// V8 runtime const x = 1; x = 2; // Throws TypeError console.log(x); // Never executed |
Değişmez XML değerlerinden ve XML nesnesinden kaçının.
ECMAScript'in bu standart dışı uzantısı, Apps Komut Dosyası projelerinin doğrudan XML söz dizimini kullanmasına olanak tanır.
Komut dosyanızı V8'e taşırken doğrudan XML değişmez değerlerini veya XML nesnesini kullanmaktan kaçının.
Bunun yerine, XML'i ayrıştırmak için XmlService'i kullanın:
// V8 runtime var incompatibleXml1 = <container><item/></container>; // Don't use var incompatibleXml2 = new XML('<container><item/></container>'); // Don't use var xml3 = XmlService.parse('<container><item/></container>'); // OK |
__iterator__
kullanarak özel yineleme işlevleri derlemeyin
JavaScript 1.7'de, ilgili sınıfın prototipinde bir __iterator__
işlevi tanımlayarak tüm sınıflara özel iteratörler eklemeye olanak tanıyan bir özellik eklendi. Bu özellik, geliştiricilere kolaylık sağlamak amacıyla Apps Komut Dosyası'nın Rhino çalışma zamanına da eklendi. Ancak bu özellik hiçbir zaman ECMA-262 standardının bir parçası değildi ve ECMAScript uyumlu JavaScript motorlarında kaldırılmıştı. V8 kullanan komut dosyaları,
bu yineleme yapısını kullanamaz.
Komut dosyanızı V8'e taşırken özel yinelemeler oluşturmak için __iterator__
işlevinden kaçının. Bunun yerine ECMAScript 6 yinelemelerini kullanın.
Şu dizi yapısını göz önünde bulundurun:
// Create a sample array var myArray = ['a', 'b', 'c']; // Add a property to the array myArray.foo = 'bar'; // The default behavior for an array is to return keys of all properties, // including 'foo'. Logger.log("Normal for...in loop:"); for (var item in myArray) { Logger.log(item); // Logs 0, 1, 2, foo } // To only log the array values with `for..in`, a custom iterator can be used. |
Aşağıdaki kod örnekleri, Rhino çalışma zamanında bir iteratörün nasıl oluşturulabileceğini ve V8 çalışma zamanında yedek bir iteratörün nasıl oluşturulacağını göstermektedir:
// Rhino runtime custom iterator function ArrayIterator(array) { this.array = array; this.currentIndex = 0; } ArrayIterator.prototype.next = function() { if (this.currentIndex >= this.array.length) { throw StopIteration; } return "[" + this.currentIndex + "]=" + this.array[this.currentIndex++]; }; // Direct myArray to use the custom iterator myArray.__iterator__ = function() { return new ArrayIterator(this); } Logger.log("With custom Rhino iterator:"); for (var item in myArray) { // Logs [0]=a, [1]=b, [2]=c Logger.log(item); } |
// V8 runtime (ECMAScript 6) custom iterator myArray[Symbol.iterator] = function() { var currentIndex = 0; var array = this; return { next: function() { if (currentIndex < array.length) { return { value: "[${currentIndex}]=" + array[currentIndex++], done: false}; } else { return {done: true}; } } }; } Logger.log("With V8 custom iterator:"); // Must use for...of since // for...in doesn't expect an iterable. for (var item of myArray) { // Logs [0]=a, [1]=b, [2]=c Logger.log(item); } |
Koşullu yakalama ifadeleri kullanmaktan kaçının
V8 çalışma zamanı, standartlarla uyumlu olmadığı için catch..if
koşullu yakalama deyimlerini desteklemez.
Komut dosyanızı V8'e taşırken, yakalama gövdesindeki yakalama koşullarını taşıyın:
// Rhino runtime try { doSomething(); } catch (e if e instanceof TypeError) { // Don't use // Handle exception } |
// V8 runtime try { doSomething(); } catch (e) { if (e instanceof TypeError) { // Handle exception } } |
Object.prototype.toSource()
kullanmaktan kaçının
JavaScript 1.3, hiçbir ECMAScript standardının parçası olmayan bir Object.prototype.toSource() yöntemi içeriyordu. V8 çalışma zamanında desteklenmez.
Komut dosyanızı V8'e taşırken kodunuzdan tüm Object.prototype.toSource() kullanımlarını kaldırın.
Diğer farklılıklar
Komut dosyası hatalarına neden olabilecek yukarıdaki uyumsuzluklara ek olarak, düzeltilmezse beklenmedik V8 çalışma zamanı komut dosyası davranışına neden olabilecek birkaç farklılık daha vardır.
Aşağıdaki bölümlerde, bu beklenmedik sürprizlerden kaçınmak için komut dosyası kodunuzu nasıl güncelleyeceğiniz açıklanmaktadır.
Yerel ayara özel tarih ve saat biçimlendirmesini ayarla
Date
toLocaleString()
, toLocaleDateString()
ve toLocaleTimeString()
yöntemleri, V8 çalışma zamanında Rhino'dan farklı davranır.
Rhino'da varsayılan biçim uzun biçimdir ve geçirilen tüm parametreler yoksayılır.
V8 çalışma zamanında varsayılan biçim kısa biçimdir ve iletilen parametreler ECMA standardına göre işlenir (ayrıntılar için toLocaleDateString()
belgelerine bakın).
Komut dosyanızı V8'e taşırken kodunuzun yerel ayara özel tarih ve saat yöntemlerinin çıkışına ilişkin beklentilerini test edin ve ayarlayın:
// Rhino runtime var event = new Date( Date.UTC(2012, 11, 21, 12)); // Outputs "December 21, 2012" in Rhino console.log(event.toLocaleDateString()); // Also outputs "December 21, 2012", // ignoring the parameters passed in. console.log(event.toLocaleDateString( 'de-DE', { year: 'numeric', month: 'long', day: 'numeric' })); |
// V8 runtime var event = new Date( Date.UTC(2012, 11, 21, 12)); // Outputs "12/21/2012" in V8 console.log(event.toLocaleDateString()); // Outputs "21. Dezember 2012" console.log(event.toLocaleDateString( 'de-DE', { year: 'numeric', month: 'long', day: 'numeric' })); |
Error.fileName
ve Error.lineNumber
kullanmaktan kaçının
V8 zamanlamasında standart JavaScript Error
nesnesi, kurucu parametre veya nesne özelliği olarak fileName
ya da lineNumber
öğelerini desteklemez.
Komut dosyanızı V8'e taşırken Error.fileName
ve Error.lineNumber
öğelerine olan tüm bağımlılıkları kaldırın.
Alternatif olarak Error.prototype.stack
kullanılabilir.
Bu yığın da standart dışıdır ancak hem Rhino hem de V8'de desteklenir. Bu iki platformun oluşturduğu yığın izlemenin biçimi biraz farklıdır:
// Rhino runtime Error.prototype.stack // stack trace format at filename:92 (innerFunction) at filename:97 (outerFunction) |
// V8 runtime Error.prototype.stack // stack trace format Error: error message at innerFunction (filename:92:11) at outerFunction (filename:97:5) |
Dizeleştirilmiş enum nesnelerinin işlenmesini ayarlama
Orijinal Rhino çalışma zamanında, bir numaralandırma nesnesinde JavaScript JSON.stringify()
yöntemi yalnızca {}
değerini döndürür.
V8'de, bir numaralandırma nesnesinde aynı yöntemin kullanılması enum adını geri alır.
Komut dosyanızı V8'e taşırken kodunuzun enum nesnelerinde JSON.stringify()
çıkışıyla ilgili beklentilerini test edin ve düzenleyin:
// Rhino runtime var enumName = JSON.stringify(Charts.ChartType.BUBBLE); // enumName evaluates to {} |
// V8 runtime var enumName = JSON.stringify(Charts.ChartType.BUBBLE); // enumName evaluates to "BUBBLE" |
Tanımlanmamış parametrelerin işlenmesini ayarlayın
Orijinal Rhino çalışma zamanında, undefined
parametresinin parametre olarak bir yönteme geçirilmesi, "undefined"
dizesinin söz konusu yönteme iletilmesiyle sonuçlandı.
V8'de, undefined
yönteminin yöntemlere aktarılması, null
değerinin iletilmesiyle eşdeğerdir.
Komut dosyanızı V8'e taşırken kodunuzun undefined
parametreleriyle ilgili beklentilerini test edin ve ayarlayın:
// Rhino runtime SpreadsheetApp.getActiveRange() .setValue(undefined); // The active range now has the string // "undefined" as its value. |
// V8 runtime SpreadsheetApp.getActiveRange() .setValue(undefined); // The active range now has no content, as // setValue(null) removes content from // ranges. |
Global this
için işlenmeyi ayarlayın
Rhino çalışma zamanı, bunu kullanan komut dosyaları için örtülü özel bir bağlam tanımlar.
Komut dosyası kodu, gerçek global this
'den farklı olarak bu örtülü bağlamda çalışır. Yani koddaki "global this
" referansları, yalnızca komut dosyasında tanımlanan kodu ve değişkenleri içeren özel bağlamı değerlendirir. Yerleşik Apps Komut Dosyası hizmetleri ve ECMAScript nesneleri bu this
kullanımından hariç tutulur. Bu durum şu JavaScript yapısına
benzeriydi:
// Rhino runtime // Apps Script built-in services defined here, in the actual global context. var SpreadsheetApp = { openById: function() { ... } getActive: function() { ... } // etc. }; function() { // Implicit special context; all your code goes here. If the global this // is referenced in your code, it only contains elements from this context. // Any global variables you defined. var x = 42; // Your script functions. function myFunction() { ... } // End of your code. }(); |
V8'de, örtülü özel bağlam kaldırılır. Komut dosyasında tanımlanan genel değişkenler ve işlevler, genel bağlama, yerleşik Apps Komut Dosyası hizmetlerinin ve Math
ile Date
gibi ECMAScript yerleşiklerinin yanına yerleştirilir.
Komut dosyanızı V8'e taşırken kodunuzun küresel bağlamda this
kullanımına ilişkin beklentilerini test edin ve ayarlayın. Çoğu durumda farklılıklar yalnızca kodunuzda global this
nesnesinin anahtarları veya özellik adları incelendiğinde görülür:
// Rhino runtime var myGlobal = 5; function myFunction() { // Only logs [myFunction, myGlobal]; console.log(Object.keys(this)); // Only logs [myFunction, myGlobal]; console.log( Object.getOwnPropertyNames(this)); } |
// V8 runtime var myGlobal = 5; function myFunction() { // Logs an array that includes the names // of Apps Script services // (CalendarApp, GmailApp, etc.) in // addition to myFunction and myGlobal. console.log(Object.keys(this)); // Logs an array that includes the same // values as above, and also includes // ECMAScript built-ins like Math, Date, // and Object. console.log( Object.getOwnPropertyNames(this)); } |
instanceof
öğesinin kitaplıklarda işlenmesini düzenleyin
Başka bir projedeki işlevde parametre olarak iletilen bir nesnede instanceof
özelliğinin kullanılması yanlış negatif sonuçlar verebilir. V8 çalışma zamanında bir proje ve kitaplıkları farklı yürütme bağlamlarında çalıştırıldığından farklı global anahtarlar ve prototip zincirleri bulunur.
Bu durumun yalnızca kitaplığınız projenizde oluşturulmamış bir nesnede instanceof
kullandığında geçerli olduğunu unutmayın. Projenizde oluşturulan bir nesnede, ister aynı ister farklı bir komut dosyası içinde olsun, bu komutun beklendiği gibi çalışması beklenir.
V8'de çalışan bir proje, komut dosyanızı kitaplık olarak kullanıyorsa komut dosyanızın başka bir projeden aktarılacak bir parametrede instanceof
kullanıp kullanmadığını kontrol edin. instanceof
kullanımını ayarlayın ve kullanım alanınıza uygun diğer alternatifleri kullanın.
Prototip zincirinin tamamını aramanıza gerek olmadığı ve sadece oluşturucuyu kontrol etmenizin gerekmediği durumlarda, a instanceof b
için a
oluşturucusunu kullanmak da bir alternatif olabilir.
Kullanım: a.constructor.name == "b"
A Projesi’nin kitaplık olarak kullanıldığı A ve B projelerini düşünün.
//Rhino runtime //Project A function caller() { var date = new Date(); // Returns true return B.callee(date); } //Project B function callee(date) { // Returns true return(date instanceof Date); } |
//V8 runtime //Project A function caller() { var date = new Date(); // Returns false return B.callee(date); } //Project B function callee(date) { // Incorrectly returns false return(date instanceof Date); // Consider using return (date.constructor.name == // “Date”) instead. // return (date.constructor.name == “Date”) -> Returns // true } |
Başka bir alternatif de, ana projede instanceof
öğesini kontrol eden bir işlev sunmak ve bir kitaplık işlevini çağırırken diğer parametrelere ek olarak bu işlevi iletmek de olabilir. İletilen işlev, daha sonra kitaplıkta instanceof
öğesini kontrol etmek için kullanılabilir.
//V8 runtime //Project A function caller() { var date = new Date(); // Returns True return B.callee(date, date => date instanceof Date); } //Project B function callee(date, checkInstanceOf) { // Returns True return checkInstanceOf(date); } |
Paylaşılmayan kaynakların kitaplıklara iletimini ayarlama
Paylaşılmayan bir kaynağın ana komut dosyasından kitaplığa iletilmesi, V8 çalışma zamanında farklı şekilde çalışır.
Rhino çalışma zamanında paylaşılmayan bir kaynağın iletilmesi işe yaramaz. Kitaplık bunun yerine kendi kaynağını kullanır.
V8 çalışma zamanında, paylaşılmayan bir kaynağın kitaplığa aktarılması işe yarar. Kitaplık, iletilen paylaşılmayan kaynağı kullanır.
Paylaşılmayan kaynakları işlev parametreleri olarak iletmeyin. Paylaşılmayan kaynakları her zaman, onları kullanan aynı komut dosyasında bildirin.
A Projesi’nin kitaplık olarak kullanıldığı A ve B projelerini düşünün. Bu örnekte, PropertiesService
paylaşılmayan bir kaynaktır.
// Rhino runtime // Project A function testPassingNonSharedProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-A'); B.setScriptProperties(); // Prints: Project-B Logger.log(B.getScriptProperties( PropertiesService, 'project')); } |
// V8 runtime // Project A function testPassingNonSharedProperties() { PropertiesService.getScriptProperties() .setProperty('project', 'Project-A'); B.setScriptProperties(); // Prints: Project-A Logger.log(B.getScriptProperties( PropertiesService, 'project')); } |
Bağımsız komut dosyalarına erişimi güncelleme
V8 çalışma zamanında çalışan bağımsız komut dosyalarında, komut dosyası tetikleyicilerinin düzgün çalışması için kullanıcılara en azından komut dosyası görüntüleme erişimi sağlamanız gerekir.