Closure Compiler, JavaScript girişinin belirli kısıtlamalara uymasını bekler. Derleyiciden istediğiniz optimizasyon düzeyi ne kadar yüksek olursa derleyici, giriş JavaScript'i üzerinde o kadar fazla kısıtlama uygular.
Bu belgede, her optimizasyon seviyesindeki temel kısıtlamalar açıklanmaktadır. Derleyici tarafından yapılan ek varsayımlar için bu wiki sayfasına da bakın.
Tüm optimizasyon düzeylerindeki kısıtlamalar
Derleyici, işlediği tüm JavaScript'lere tüm optimizasyon seviyeleri için aşağıdaki iki kısıtlamayı uygular:
Derleyici yalnızca ECMAScript'i tanır.
ECMAScript 5, neredeyse her yerde desteklenen JavaScript sürümüdür. Ancak derleyici, ECMAScript 6'daki birçok özelliği de destekler. Derleyici yalnızca resmi dil özelliklerini destekler.
Uygun ECMAScript dil spesifikasyonuna uygun tarayıcıya özgü özellikler derleyiciyle sorunsuz çalışır. Örneğin, ActiveX nesneleri yasal JavaScript söz dizimiyle oluşturulur. Bu nedenle, ActiveX nesneleri oluşturan kod derleyiciyle çalışır.
Derleyici bakımcıları, yeni dil sürümlerini ve özelliklerini desteklemek için aktif olarak çalışır. Projeler,
--language_in
işaretini kullanarak hangi ECMAScript dil sürümünü kullanmak istediklerini belirtebilir.Derleyici, yorumları korumaz.
Tüm Compiler optimizasyon seviyelerinde yorumlar kaldırılır. Bu nedenle, özel olarak biçimlendirilmiş yorumlara dayanan kodlar Compiler ile çalışmaz.
Örneğin, derleyici yorumları korumadığından JScript'in "koşullu yorumlarını" doğrudan kullanamazsınız. Ancak koşullu yorumları
eval()
ifadeleriyle sarmalayarak bu kısıtlamayı aşabilirsiniz. Derleyici, aşağıdaki kodu hata oluşturmadan işleyebilir:x = eval("/*@cc_on 2+@*/ 0");
Not: @preserve ek açıklamasını kullanarak derleyici çıkışının en üstüne açık kaynak lisansları ve diğer önemli metinleri ekleyebilirsiniz.
SIMPLE_OPTIMIZATIONS ile ilgili kısıtlamalar
Basit optimizasyon düzeyi, kod boyutunu küçültmek için işlev parametrelerini, yerel değişkenleri ve yerel olarak tanımlanmış işlevleri yeniden adlandırır. Ancak bazı JavaScript yapıları bu yeniden adlandırma sürecini bozabilir.
SIMPLE_OPTIMIZATIONS
kullanırken aşağıdaki yapılardan ve uygulamalardan kaçının:
with
:with
kullandığınızda derleyici, aynı ada sahip yerel bir değişken ile nesne özelliği arasında ayrım yapamaz ve bu nedenle adın tüm örneklerini yeniden adlandırır.Ayrıca,
with
ifadesi kodunuzun insanlar tarafından okunmasını zorlaştırır.with
ifadesi, ad çözümlemeyle ilgili normal kuralları değiştirir ve kodu yazan programcının bile bir adın neyi ifade ettiğini belirlemesini zorlaştırabilir.eval()
:Derleyici,
eval()
işlevinin dize bağımsız değişkenini ayrıştırmadığından bu bağımsız değişkendeki sembolleri yeniden adlandırmaz.İşlev veya parametre adlarının dize gösterimleri:
Derleyici, işlevleri ve işlev parametrelerini yeniden adlandırır ancak kodunuzdaki işlevlere veya parametrelere adlarıyla atıfta bulunan dizeleri değiştirmez. Bu nedenle, işlev veya parametre adlarını kodunuzda dize olarak göstermemelisiniz. Örneğin, Prototype kitaplığı işlevi
argumentNames()
, bir işlevin parametrelerinin adlarını almak içinFunction.toString()
kullanır. AncakargumentNames()
, kodunuzda bağımsız değişkenlerin adlarını kullanmanıza neden olabilir. Simple mod derlemesi bu tür referansları bozar.
ADVANCED_OPTIMIZATIONS ile ilgili kısıtlamalar
ADVANCED_OPTIMIZATIONS
derleme düzeyi, SIMPLE_OPTIMIZATIONS
ile aynı dönüşümleri gerçekleştirir ve özelliklerin, değişkenlerin ve işlevlerin genel olarak yeniden adlandırılması, kullanılmayan kodların kaldırılması ve özelliklerin düzleştirilmesi işlemlerini de ekler. Bu yeni geçişler, giriş JavaScript'i üzerinde ek kısıtlamalar uygular. Genel olarak, JavaScript'in dinamik özelliklerinin kullanılması kodunuzda doğru statik analiz yapılmasını engeller.
Global değişken, işlev ve özellik yeniden adlandırmanın etkileri:
ADVANCED_OPTIMIZATIONS
'ın küresel olarak yeniden adlandırılması, aşağıdaki uygulamaları tehlikeli hale getirir:
Bildirilmemiş harici referanslar:
Derleyicinin, global değişkenleri, işlevleri ve özellikleri doğru şekilde yeniden adlandırabilmesi için bu global'lere yapılan tüm referansları bilmesi gerekir. Derleyiciye, derlenen kodun dışında tanımlanan semboller hakkında bilgi vermeniz gerekir. Gelişmiş Derleme ve Harici Semboller, harici sembollerin nasıl bildirileceğini açıklar.
Dışa aktarılmamış dahili adları harici kodda kullanma:
Derlenmiş kod, derlenmemiş kodun referans verdiği tüm sembolleri dışa aktarmalıdır. Advanced Compilation and Externs (Gelişmiş Derleme ve Harici Dosyalar) başlıklı makalede, sembollerin nasıl dışa aktarılacağı açıklanmaktadır.
Nesne özelliklerine referans vermek için dize adlarını kullanma:
Derleyici, Gelişmiş modda özellikleri yeniden adlandırır ancak dizeleri asla yeniden adlandırmaz.
var x = { renamed_property: 1 }; var y = x.renamed_property; // This is OK. // 'renamed_property' below doesn't exist on x after renaming, so the // following evaluates to false. if ( 'renamed_property' in x ) {}; // BAD // The following also fails: x['renamed_property']; // BAD
Tırnak içine alınmış bir dize içeren bir özelliğe başvurmanız gerekiyorsa her zaman tırnak içine alınmış bir dize kullanın:
var x = { 'unrenamed_property': 1 }; x['unrenamed_property']; // This is OK. if ( 'unrenamed_property' in x ) {}; // This is OK
Değişkenleri genel nesnenin özellikleri olarak adlandırma:
Derleyici, özellikleri ve değişkenleri bağımsız olarak yeniden adlandırır. Örneğin, derleyici aşağıdaki iki
foo
referansını eşdeğer olmalarına rağmen farklı şekilde ele alır:var foo = {}; window.foo; // BAD
Bu kod şu şekilde derlenebilir:
var a = {}; window.b;
Bir değişkene genel nesnenin özelliği olarak başvurmanız gerekiyorsa her zaman bu şekilde başvurun:
window.foo = {} window.foo;
Implications of dead code elimination
The ADVANCED_OPTIMIZATIONS
compilation level removes code
that is never executed. This elimination of dead code makes the
following practices dangerous:
Calling functions from outside of compiled code:
When you compile functions without compiling the code that calls those functions, the Compiler assumes that the functions are never called and removes them. To avoid unwanted code removal, either:
- compile all the JavaScript for your application together, or
- export compiled functions.
Advanced Compilation and Externs describes both of these approaches in greater detail.
Retrieving functions through iteration over constructor or prototype properties:
To determine whether a function is dead code, the Compiler has to find all the calls to that function. By iterating over the properties of a constructor or its prototype you can find and call methods, but the Compiler can't identify the specific functions called in this manner.
For example, the following code causes unintended code removal:
function Coordinate() { } Coordinate.prototype.initX = function() { this.x = 0; } Coordinate.prototype.initY = function() { this.y = 0; } var coord = new Coordinate(); for (method in Coordinate.prototype) { Coordinate.prototype[method].call(coord); // BAD }
Derleyici,
initX()
veinitY()
yöntemlerininfor
döngüsünde çağrıldığını anlamadığından bu yöntemlerin ikisini de kaldırır.Bir işlevi parametre olarak iletirseniz derleyicinin bu parametreye yapılan çağrıları bulabileceğini unutmayın. Örneğin, Derleyici, aşağıdaki kodu Gelişmiş modda derlerken
getHello()
işlevini kaldırmaz.function alertF(f) { alert(f()); } function getHello() { return 'hello'; } // The Compiler figures out that this call to alertF also calls getHello(). alertF(getHello); // This is OK.
Nesne özelliği düzleştirmenin etkileri
Gelişmiş modda derleyici, ad kısaltmaya hazırlanmak için nesne özelliklerini daraltır. Örneğin, derleyici şunu dönüştürür:
var foo = {}; foo.bar = function (a) { alert(a) }; foo.bar("hello");
şuna dönüştürülür:
var foo$bar = function (a) { alert(a) }; foo$bar("hello");
Bu özellik düzleştirme, daha sonraki yeniden adlandırma adımında daha verimli bir şekilde yeniden adlandırma yapılmasını sağlar. Derleyici, foo$bar
ifadesini tek bir karakterle değiştirebilir.
Ancak mülk düzleştirme, aşağıdaki uygulamaları da tehlikeli hale getirir:
this
'ı oluşturucular ve prototip yöntemleri dışında kullanma:Özellik düzleştirme, bir işlevdeki
this
anahtar kelimesinin anlamını değiştirebilir. Örneğin:var foo = {}; foo.bar = function (a) { this.bad = a; }; // BAD foo.bar("hello");
şu olur:
var foo$bar = function (a) { this.bad = a; }; foo$bar("hello");
Dönüşümden önce
this
içindekifoo.bar
,foo
anlamına gelir. Dönüşümden sonrathis
, genelthis
'yı ifade eder. Bu gibi durumlarda derleyici şu uyarıyı verir:"WARNING - dangerous use of this in static method foo.bar"
Mülk düzleştirmenin
this
referanslarınızı bozmasını önlemek içinthis
yalnızca oluşturucular ve prototip yöntemleri içinde kullanın.this
,new
anahtar kelimesiyle bir oluşturucu çağırdığınızda veyaprototype
öğesinin özelliği olan bir işlevde net bir anlama sahiptir.Hangi sınıfta çağrıldığını bilmeden statik yöntemler kullanma:
Örneğin aşağıdaki özelliklere sahipseniz:
Derleyici, her ikiclass A { static create() { return new A(); }}; class B { static create() { return new B(); }}; let cls = someCondition ? A : B; cls.create();
create
yöntemini (ES6'dan ES5'e dönüştürüldükten sonra) daraltır. Bu nedenlecls.create()
çağrısı başarısız olur. Bu durumu@nocollapse
notuyla önleyebilirsiniz:class A { /** @nocollapse */ static create() { return new A(); } } class B { /** @nocollapse */ static create() { return new A(); } }
Üst sınıfı bilmeden statik bir yöntemde super kullanma:
Derleyici,
super.sayHi()
öğesininParent.sayHi()
öğesini ifade ettiğini bildiği için aşağıdaki kod güvenlidir:class Parent { static sayHi() { alert('Parent says hi'); } } class Child extends Parent { static sayHi() { super.sayHi(); } } Child.sayHi();
Ancak,
myMixin(Parent).sayHi
derlenmemişParent.sayHi
değerine eşit olsa bile özellik düzleştirme işlemi aşağıdaki kodu bozacaktır:class Parent { static sayHi() { alert('Parent says hi'); } } class Child extends myMixin(Parent) { static sayHi() { super.sayHi(); } } Child.sayHi();
/** @nocollapse */
notuyla bu bozulmayı önleyin.Object.defineProperties veya ES6 getter/setters kullanma:
Derleyici bu yapıları iyi anlamıyor. ES6 getter ve setter'ları, dönüştürme işlemiyle Object.defineProperties(...) olarak dönüştürülür. Derleyici şu anda bu yapıyı statik olarak analiz edemiyor ve özelliklere erişimin ve özelliklerin ayarlanmasının yan etkisiz olduğunu varsayıyor. Bu durum tehlikeli sonuçlara yol açabilir. Örneğin:
class C { static get someProperty() { console.log("hello getters!"); } } var unused = C.someProperty;
Şununla derlenir:
C = function() {}; Object.defineProperties(C, {a: // Note someProperty is also renamed to 'a'. {configurable:!0, enumerable:!0, get:function() { console.log("hello world"); return 1; }}});
C.someProperty'nin yan etkisi olmadığı belirlendiği için kaldırıldı.