Closure Compiler, JavaScript girişinin birkaç kısıtlamaya uymasını bekler. Derleyici'den gerçekleştirmesini istediğiniz optimizasyon düzeyi ne kadar yüksek olursa Derleyici'nin giriş JavaScript'ine o kadar fazla kısıtlaması olur.
Bu dokümanda, her optimizasyon düzeyi için temel kısıtlamalar açıklanmaktadır. Derleyicinin varsayımları için bu wiki sayfasına bakın.
Tüm optimizasyon seviyeleri için kısıtlamalar
Derleyici, tüm optimizasyon seviyeleri için işlediği tüm JavaScript'e aşağıdaki iki kısıtlamayı yerleştirir:
Derleyen yalnızca ECMAScript'i tanır.
ECMAScript 5, hemen her yerde desteklenen JavaScript sürümüdür. Ancak derleyici, ECMAScript 6'daki birçok özelliği de desteklemektedir. Derleyici yalnızca resmi dil özelliklerini destekler.
Uygun ECMAScript dil spesifikasyonuna uyan tarayıcıya özel özellikler, derleyici ile sorunsuz bir şekilde çalışır. Örneğin, ActiveX nesneleri yasal JavaScript söz dizimiyle oluşturulur. Bu nedenle, ActiveX nesneleri oluşturan kod derleyici ile çalışır.
Derleyici bakım görevlileri, yeni dil sürümlerini ve özelliklerini desteklemek için aktif şekilde çalışır. Projeler,
--language_in
işaretini kullanarak hangi ECMAScript dil sürümünü istediklerini belirtebilir.Derleyen, yorumları korumaz.
Tüm Derleyici optimizasyon seviyeleri yorumları kaldırır. Bu nedenle, özel olarak biçimlendirilmiş yorumlara bağlı olan kodlar Derleyici ile çalışmaz.
Örneğin, Derleyici yorumları saklamadığı için, JScript'in "koşullu yorumlarını" doğrudan kullanamazsınız. Bununla birlikte, koşullu yorumları
eval()
ifadeleri içinde sarmalayarak bu kısıtlamayı aşabilirsiniz. Derleyen, herhangi bir hata oluşturmadan aşağıdaki kodu işleyebilir:x = eval("/*@cc_on 2+@*/ 0");
Not: Açık kaynak lisansları ve diğer önemli metinleri, @preserve ek açıklamasını kullanarak Derleyici çıkışının en üstüne ekleyebilirsiniz.
SIMPLE_OPTIMIZATIONS için kısıtlamalar
Basit optimizasyon düzeyi, kod boyutunu azaltmak için işlev parametrelerini, yerel değişkenleri ve yerel olarak tanımlanan 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
:Derleyici,
with
kullandığınızda yerel bir değişken ile aynı ada sahip bir nesne özelliğini ayırt edemediği için adın tüm örneklerini yeniden adlandırır.Ayrıca
with
ifadesi, kodunuzu insanların okumasını zorlaştırır.with
ifadesi, ad çözümleme için normal kuralları değiştirir ve kodu yazan programcının bir adı ne ifade ettiğini belirlemeyi daha da zorlaştırabilir.eval()
:Derleyici,
eval()
dizesinin bağımsız değişkenini ayrıştırmaz. Bu nedenle, bu bağımsız değişken içindeki hiçbir sembolü yeniden adlandırmaz.İşlev veya parametre adlarının dize temsilleri:
Derleyici, işlevleri ve işlev parametrelerini yeniden adlandırır. Ancak kodunuzdaki işlevlere veya parametrelere atıfta bulunan hiçbir dizeyi değiştirmez. Bu nedenle, işlev veya parametre adlarını kodunuzda dize olarak temsil etmekten kaçınmalısınız. Örneğin,
argumentNames()
Prototip kitaplığı işlevi bir işlevin parametrelerinin adlarını almak içinFunction.toString()
kullanır. AncakargumentNames()
, kodunuzdaki bağımsız değişken adlarını kullanmaya teşvik edebilir ancak Basit mod derlemesi bu tür bir referansı bozar.
ADVANCED_OPTIMIZATIONS için kısıtlamalar
ADVANCED_OPTIMIZATIONS
derleme düzeyi, SIMPLE_OPTIMIZATIONS
ile aynı dönüşümleri gerçekleştirir ve ayrıca özelliklerin, değişkenlerin ve işlevlerin yeniden adlandırılmasını, geçersiz kodların ortadan kaldırılmasını ve mülkün düzleştirilmesini de sağlar. Bu yeni kartlar, giriş JavaScript'ine ek kısıtlamalar uyguluyor. Genel olarak, JavaScript'in dinamik özelliklerini kullanmak, kodunuzda doğru statik analizi engeller.
Genel değişken, işlev ve mülkün yeniden adlandırılmasının etkileri:
ADVANCED_OPTIMIZATIONS
alanının genel olarak yeniden adlandırılması aşağıdaki uygulamaları tehlikeli kılıyor:
Beyan edilmemiş harici referanslar:
Derleyicinin, değişkenleri, işlevleri ve özellikleri doğru şekilde yeniden adlandırmak için Derleyici'nin bu global referansların tümü hakkında bilgi sahibi olması gerekir. Derleyen'e, derlenen kodun dışında tanımlanan simgeler hakkında bilgi vermelisiniz. Gelişmiş Derleme ve İstisnalar, harici simgelerin nasıl belirtileceğini açıklar.
Harici kodda dışa aktarılmayan dahili adları kullanma:
Derlenen kod, derlenmemiş kodla ilgili tüm simgeleri dışa aktarmalıdır. Gelişmiş Derleme ve İstisnalar, simgelerin nasıl dışa aktarılacağını açıklar.
Nesne özelliklerini belirtmek için dize adlarını kullanma:
Derleyici, Gelişmiş modda özellikleri yeniden adlandırır ancak dizeleri hiçbir zaman 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ış dize içeren bir mülke referans vermeniz 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 tanımlama:
Derleyici, özellikleri ve değişkenleri bağımsız olarak yeniden adlandırır. Örneğin Derleyici, aşağıdaki iki referansı aynı şekilde
foo
olsa da farklı şekilde ele alır:var foo = {}; window.foo; // BAD
Bu kod şu konuma derlenebilir:
var a = {}; window.b;
Bir değişkeni, genel nesnenin özelliği olarak belirtmeniz gerekirse her zaman şu şekilde başvuruda bulunun:
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()
öğelerininfor
döngüsünde çağrıldığını anlayamadığı için bu yöntemlerin ikisini de kaldırır.Bir işlevi parametre olarak geçirirseniz Derleyici'nin 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 birleştirmenin etkileri
Derleyici, Gelişmiş modda nesne özelliklerini daraltarak ad kısaltmaya hazır olur. Örneğin, Derleyici bunu dönüştürür:
var foo = {}; foo.bar = function (a) { alert(a) }; foo.bar("hello");
bunun için:
var foo$bar = function (a) { alert(a) }; foo$bar("hello");
Bu mülkün daha sonra yeniden adlandırılması, daha sonra yeniden adlandırma kartına daha verimli bir şekilde yeniden ad verme olanağı sağlar. Derleyici, örneğin foo$bar
ifadesini tek bir karakterle değiştirebilir.
Ancak mülk birleştirme aşağıdaki uygulamaları da tehlikeli hale getirir:
Oluşturucuların ve prototip yöntemlerinin dışında
this
kullanma:Özellik düzleştirme, bir işlev içindeki
this
anahtar kelimesinin anlamını değiştirebilir. Örneğin:var foo = {}; foo.bar = function (a) { this.bad = a; }; // BAD foo.bar("hello");
şu hale gelir:
var foo$bar = function (a) { this.bad = a; }; foo$bar("hello");
Dönüşümden önceki
this
,foo.bar
içindefoo
anlamına gelir. Dönüşümden sonrathis
, globalthis
anlamına gelir. Derleyici bu gibi durumlarda şu uyarıyı oluşturur:"WARNING - dangerous use of this in static method foo.bar"
Mülk birleştirmenin
this
referanslarınıza zarar vermesini önlemek için yalnızca oluşturucuların ve prototip yöntemlerinin içindethis
kullanın.this
anahtar kelimesinin anlamı,new
anahtar kelimesiyle bir oluşturucuyu veyaprototype
özelliği olan bir işlevin içindeyken belirtilir.Statik yöntemleri, hangi sınıfta çağrıldıklarını bilmeden kullanmak:
Örneğin, aşağıdaki yöntemlerden birini kullanıyorsanız:
class A { static create() { return new A(); }}; class B { static create() { return new B(); }}; let cls = someCondition ? A : B; cls.create();
derleyici,create
yöntemini (ES6'dan ES5'e dönüşümden sonra) daraltır. Bu nedenlecls.create()
çağrısı başarısız olur. Bu durumu@nocollapse
ek açıklamasıyla önleyebilirsiniz:class A { /** @nocollapse */ static create() { return new A(); } } class B { /** @nocollapse */ static create() { return new A(); } }
Süper sınıfı bilmeden statik bir yöntemde süper kullanma:
Derleyici,
super.sayHi()
özelliğininParent.sayHi()
anlamına geldiğ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 mülk birleştirme,
myMixin(Parent).sayHi
derlenmemişParent.sayHi
değerine eşit olsa bile aşağıdaki kodu bozar:class Parent { static sayHi() { alert('Parent says hi'); } } class Child extends myMixin(Parent) { static sayHi() { super.sayHi(); } } Child.sayHi();
/** @nocollapse */
ek açıklamasıyla bu bölünmeyi önleyin.Object.defineProperties veya ES6 getter/setter öğelerini kullanma:
Derleyici bu yapıları iyi anlamıyor. ES6 alıcı ve setleri, harf çevirisi aracılığıyla Object.defineProperties(...) biçimine dönüştürülür. Şu anda derleyici bu yapıyı statik olarak analiz edememektedir ve özelliklere erişimin ve setlerin yan etkisi olmadığını varsayar. Bu durum tehlikeli sonuçlara yol açabilir. Örneğin:
class C { static get someProperty() { console.log("hello getters!"); } } var unused = C.someProperty;
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'in yan etkisi olmadığı tespit edildiğinden kaldırıldı.