Rhino çalışma zamanını kullanan mevcut bir komut dosyanız varsa ve V8 söz dizimini ve özelliklerini kullanmak istiyorsanız komut dosyasını V8'e taşımanız gerekir.
Rhino çalışma zamanı kullanılarak yazılan çoğu komut dosyası, herhangi bir ayarlama yapmadan V8 çalışma zamanı kullanılarak çalışabilir. Bir komut dosyasına V8 söz dizimini ve özelliklerini eklemenin tek ön koşulu genellikle V8 çalışma zamanını etkinleştirmektir.
Ancak V8 çalışma zamanını etkinleştirdikten sonra komut dosyasının başarısız olmasına veya beklenmedik şekilde davranmasına neden olabilecek küçük bir uyumsuzluk ve diğer farklılıklar vardır. Bir komut dosyasını V8'i kullanacak şekilde 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 aşağıdaki prosedürü uygulayın:
- Komut dosyası için V8 çalışma zamanını etkinleştirin.
- Aşağıda listelenen uyumsuzlukları dikkatlice inceleyin. Uyumluluk sorunlarından herhangi birinin olup olmadığını belirlemek için komut dosyanızı inceleyin. Bir veya daha fazla uyumluluk sorunu varsa sorunu gidermek veya önlemek için komut dosyası kodunuzu düzenleyin.
- 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. Davranışı düzeltmek için komut dosyanızı ayarlayın.
- Tespit edilen uyumsuzlukları veya diğer farklılıkları düzelttikten sonra, kodunuzu V8 söz dizimini ve diğer özellikleri istediğiniz gibi kullanacak şekilde 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 ayarlarını içeren yeni bir sürüm oluşturmanız gerekir. V8 sürümünün kullanıcılara sunulabilmesi için komut dosyasını bu sürümle yeniden yayınlamanız gerekir.
Uyumsuzluklar
Orijinal Rhino tabanlı Apps Komut Dosyası çalışma zamanı maalesef birkaç standart dışı ECMAScript davranışına izin veriyordu. V8 standartlara uygun olduğundan bu davranışlar taşıma işleminden sonra 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 geçiş sırasında komut dosyanızı 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
için kaldırıldı.
Komut dosyanızı V8'e taşırken for each (variable in object)
statements kullanmaktan kaçının.
Bunun yerine for (variable in object)
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()
, 1900-1999 arasındaki yıllar için iki haneli yıllar, diğer tarihler için ise dört haneli yıllar döndürür. Bu, JavaScript 1.2 ve önceki sürümlerdeki davranıştı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 her zaman Date.prototype.getFullYear()
işlevini kullanın. Bu işlev, tarihten bağımsız olarak dört haneli 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 çoğuna izin veriyordu. Dolayısıyla, kodunuzda bu kelimeler kullanılıyorsa işlevlerinizi veya değişkenlerinizi yeniden adlandırmanız gerekir.
Komut dosyanızı V8'e taşırken ayrılmış anahtar kelimelerden birini kullanarak değişken veya işlev adlandırmaktan kaçının.
Anahtar kelime adını kullanmamak için herhangi bir değişkeni veya işlevi yeniden adlandırın. Anahtar kelimelerin yaygın kullanım şekilleri şunlardır: class
, import
ve export
.
const
değişkenlerini yeniden atamaktan kaçının
Orijinal Rhino çalışma zamanında, const
kullanarak bir değişken tanımlayabilirsiniz. Bu, simgenin değerinin hiçbir zaman değişmediği ve simge için gelecekte yapılacak atamaların yoksayıldığı anlamına gelir.
Yeni V8 çalışma zamanında const
anahtar kelimesi standart uyumludur ve const
olarak tanımlanan bir değişkene atama yapmak 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'e yönelik bu standart dışı uzantı, Apps Script 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ğerleri veya XML nesnesi 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 iteratör işlevleri oluşturmayın
JavaScript 1.7, sınıfın prototipinde bir __iterator__
işlevi tanımlayarak herhangi bir sınıfa özel bir iteratör ekleme olanağı sağlayan bir özellik ekledi. Bu özellik, geliştiricilere kolaylık sağlamak amacıyla Apps Script'in Rhino çalışma zamanında da eklendi. Ancak bu özellik hiçbir zaman ECMA-262 standardının bir parçası olmamıştır ve ECMAScript uyumlu JavaScript motorlarından kaldırılmıştır. V8 kullanan komut dosyaları bu iteratör yapısını kullanamaz.
Komut dosyanızı V8'e taşırken özel iteratör oluşturmak için __iterator__
işlevini kullanmaktan kaçının. Bunun yerine ECMAScript 6 iteratörlerini 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, bir iteratörün Rhino çalışma zamanında nasıl oluşturulabileceğini ve V8 çalışma zamanında nasıl değiştirilen bir iteratör oluşturulabileceğini gösterir:
// 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 yan tümcelerinden kaçının
V8 çalışma zamanı, standartlara uygun olmadığı için catch..if
koşullu yakalama yan tümcelerini desteklemez.
Komut dosyanızı V8'e taşırken, yakalama gövdenizin içindeki tüm 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 zaman 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 başka farklılıklar da vardır.
Aşağıdaki bölümlerde, bu beklenmedik sürprizleri önlemek için komut dosyası kodunuzu nasıl güncelleyeceğiniz açıklanmaktadır.
Yerel ayara özgü tarih ve saat biçimlendirmesini ayarlama
Date
toLocaleString()
, toLocaleDateString()
ve toLocaleTimeString()
yöntemleri, V8 çalışma zamanında Rhino'ya kıyasla farklı davranır.
Rhino'da varsayılan biçim uzun biçimdir ve iletilen 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()
dokümanlarına 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 untime'da standart JavaScript Error
nesnesi, fileName
veya lineNumber
'i oluşturucu parametresi ya da nesne özelliği olarak desteklemez.
Komut dosyanızı V8'e taşırken Error.fileName
ve Error.lineNumber
'e olan tüm bağımlılıkları kaldırın.
Alternatif olarak Error.prototype.stack
kullanılabilir.
Bu yığın da standart değildir ancak hem Rhino hem de V8'de desteklenir. İki platform tarafından oluşturulan 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) |
Dize haline getirilmiş 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 enum nesnesinde aynı yöntemi kullanmak enum adını döndürür.
Kodunuzu V8'e taşırken, kodunuzun enum nesnelerinde JSON.stringify()
değerinin çıkışıyla ilgili beklentilerini test edip 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
parametresi bir yönteme iletildiğinde "undefined"
dizesi bu yönteme iletiliyordu.
V8'de yöntemlere undefined
göndermek, null
göndermeye eşdeğerdir.
Komut dosyanızı V8'e taşırken, kodunuzun undefined
parametreleriyle ilgili beklentilerini test edip düzenleyin:
// 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
öğesinin işlenmesini ayarlama
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
'ten farklı olarak bu gizli 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, this
'ün bu kullanımından hariç tutulur. Bu durum şu JavaScript yapısına benziyordu:
// 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 global değişkenler ve işlevler, yerleşik Apps Komut Dosyası hizmetlerinin ve Math
ile Date
gibi ECMAScript yerleşiklerinin yanında global bağlama yerleştirilir.
Komut dosyanızı V8'e taşırken, kodunuzun this
'un genel bağlamda kullanımıyla ilgili beklentilerini test edip düzenleyin. Çoğu durumda farklılıklar yalnızca kodunuz genel this
nesnesinin anahtarlarını veya mülk adlarını inceliyorsa belirgindir:
// 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 kitaplıkta instanceof
kullanılması yanlış negatif sonuç verebilir. V8 çalışma zamanında, bir proje ve kitaplıkları farklı yürütme bağlamlarında çalıştırılır ve bu nedenle farklı genel değişkenler ve prototip zincirleri vardır.
Bu durumun yalnızca kitaplığınız, projenizde oluşturulmamış bir nesnede instanceof
kullanıyorsa geçerli olduğunu unutmayın. Projenizde oluşturulan bir nesnede (projenizdeki aynı veya farklı bir komut dosyasında) kullanıldığında beklendiği gibi çalışır.
V8 üzerinde ç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
'ün kullanımını düzenleyin ve kullanım alanınıza göre uygun diğer alternatifleri kullanın.
a instanceof b
için bir alternatif, prototip zincirinin tamamını aramanız gerekmeyen ve yalnızca kurucuyu kontrol etmeniz gereken durumlarda a
kurucusunu kullanmak olabilir.
Kullanım: a.constructor.name == "b"
A Projesi'nin B Projesi'ni kitaplık olarak kullandığı A Projesi ile B Projesi'ni 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 } |
Bir başka 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 aktarılmasını ayarlama
Paylaşılmayan bir kaynağı ana komut dosyasından bir kitaplığa aktarma işlemi, V8 çalışma zamanında farklı şekilde çalışır.
Rhino çalışma zamanında, paylaşılmayan bir kaynak iletme işlemi çalışmaz. Kitaplık bunun yerine kendi kaynağını kullanır.
V8 çalışma zamanında, paylaşılmayan bir kaynağı kitaplığa aktarmak işe yarar. Kitaplık, iletilen paylaşılmayan kaynağı kullanır.
Paylaşılmayan kaynakları işlev parametresi olarak iletmeyin. Paylaşılmayan kaynakları her zaman, bunları kullanan komut dosyasında tanımlayın.
A Projesi'nin B Projesi'ni kitaplık olarak kullandığı A Projesi ile B Projesi'ni 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ının tetikleyicilerinin düzgün çalışması için kullanıcılara komut dosyasına en az görüntüleme erişimi sağlamanız gerekir.