Yazar | Situ Zhengmei
Baş Editör | Guo Rui
Üretildi | CSDN (ID: CSDNnews)
JavaScript'in mevcut seviyeye geliştirilmesinde birçok iniş ve çıkış yaşanmıştır.Erken doğumun neden olduğu bazı kusurlar kalıcıdır, bu nedenle tarayıcıların JavaScript'i devre dışı bırakma seçeneği vardır. JQuery çağında bile, birisi jQuery veya JavaScript gibi daha hızlı bir soru sordu? Babel.js çıkmadan önce, her zaman JavaScript'in yerine VBScript ve Coffee ile ve daha sonra Dartjs ve WebAssembly ile değiştirilecek yeni bir dil kodu icat etme çağrıları vardı. Tüm tarayıcılarda yerleşik olan komut dosyası dili olmasaydı, ölmüş olabilir. Tarayıcı, zengin kayınvalidesi. Ek olarak, sürekli sınıf kütüphanesi çerçevesi, kendisini en alttan devrim yaratan cephaneliğidir. Neden öyle diyorsun?
JavaScript, diğer dillerin devasa SDK'sına sahip değildir. Belirli bir alan için, Prototype.js tarafından eklenen 20'den fazla olmayan dizi yöntemleri ve dize yöntemleri gibi çok az yöntem vardır. JavaScript, sayfa dinamiklerini elde etmek için DOM ve BOM gerektirir, ancak tarayıcılar birbirleriyle rekabet eder ve bu da tutarsız API'lerle sonuçlanır. Bunu yapan jQuery idi ve zincir çağrıları ve IIFE gibi yeni programlama becerileri de getirdi. Büyük ölçekli bir programlama modeline sahip olmadığında, diğer dillerden yabancılar ona MVC ve MVVM getirmişlerdir ... İçindeki pek çok şey zamanla dilin yerleşik özellikleri haline gelmiştir, Prototype.js, jQuery tarafından getirilen prototip yöntemi gibi MVVM'nin getirdiği seçici yöntemi, büyük ölçekli programlama için gerekli olan vazgeçilmez nesne öznitelik iç gözlem mekanizmasını (alıcı, ayarlayıcı, Yansıtma, Proxy), sınıfları ve modülleri gerçekleştirir.
Bu makale, bu yeni özellikleri aşağıdaki yönlerden tanıtacaktır: JavaScript'i silahlandıran ve onu ortodoks, sihirli bir dil yapan onlardır.
Büyük prototip yöntem zenginliği;
Sınıfların ve modüllerin standardizasyonu;
Asenkron mekanizmanın evrimi;
Blok düzeyinde kapsamın tamamlanması;
Temel türlerde artış;
Yansıma mekanizmasının iyileştirilmesi;
Daha uygun sözdizimsel şeker.
Prototip yöntemlerinin büyük zenginliği
Prototype.js ortaya çıktığından beri, prototip yöntemi sürekli olarak resmi bir API olarak işe alındı. Temel olarak, iki ana dizi ve dizide genişler.Günlük işlerde sürekli kullanılırlar, bu nedenle sürekli olarak tekerlekleri değiştirip yeniden yaratırlar, bu nedenle resmileştirmeyi bekliyorlar.
JavaScript sürüm açıklaması:
Bu prototip yöntemler o kadar kullanışlıdır ki röportajlarda sık sık sorulur, dizenin her iki tarafındaki boşlukları kaldırırsanız bir dizi nasıl düzleştirilir?
Sınıfların ve modüllerin standardizasyonu
Sınıfların olmadığı çağda, her popüler çerçeve sınıf oluşturmak için bir yöntem getirecektir.Prototiplerin yeniden kullanım mekanizmasına herkesin katılmadığı görülebilir.
Aşağıda, prototip ve sınıf yazımı arasında bir karşılaştırma verilmiştir:
function Kişi (ad) {
this.name = isim;
}
// Bir yöntem tanımlayın ve onu kurucunun prototipine atayın
Kişi.prototype.sayName = function {
this.name döndür;
};
var p = new Kişi ('yakut');
console.log (p.sayName) // ruby
class Person {
yapıcı (ad) {
this.name = isim
}
sayName {
this.name döndür;
}
}
var p = new Kişi ('yakut');
console.log (p.sayName) // ruby
Es6'nın tanımının çok basit olduğunu ve kullandığı nesne anahtarı tanımlama yönteminden farklı olduğunu görebiliriz. Nesne steno Yöntemi açıklamak için. Standart bir nesne tanımlama yöntemi ise, şu şekilde olmalıdır:
// Aşağıdakiler yasal değil
class Person {
yapıcı: işlev (ad) {
this.name = isim
}
sayName: function {
this.name döndür;
}
}
Bir ebeveyn sınıfından miras almak istiyorsak, bu da çok basit:
class Person, Animal {
yapıcı: işlev (ad) {
Süper;
this.name = isim
}
sayName: function {
this.name döndür;
}
}
Ek olarak, ondan sonra öznitelik başlatma sözdizimi, statik öznitelik ve yöntem sözdizimi ve özel öznitelik sözdizimi olmak üzere ilgili üç gramer eklenir. Şu anki özel öznitelik sözdizimi çok tartışmalı, ancak yine de standartlaştırılmıştır. Her ne kadar özel, halka açık ve korumalı gibi yazı tipleri, arka uçtan geçiş yapan insanların zevklerine daha uygun olsa da, bugün babel her şeye kadirdir, en sevdiğimiz yazıyı kullanabiliriz.
Sınıfın yanı sıra, bir sınıftan daha büyük bir çoğullama birimi olan bir modül de bulunmaktadır ve isteğe bağlı olarak bir dosya ile taşıyıcı olarak yüklenebilmektedir. Tabii ki, ana işlevi küresel kirliliği azaltmaktır. JQuery çağında, bu belirti IIFE aracılığıyla azaltılmıştır, ancak JS dosyaları için tek tip bir yazım özelliği yoktur, bu da onları birlikte paketlemenin çok zor olduğu ve yalnızca aşağıdaki gibi döşenebileceği anlamına gelir. Bu dosyaların bağımlılıkları, birkaç tur geliştirmeden sonra sadece ilk kişilerin bildiği bir saatli bomba gibidir. Ayrıca unutma, < senaryo > Standartlar ayrıca sayfa oluşturma sıkışmalarına ve beyaz ekranlara da neden olabilir.
< script src = "zepto.js" > < /senaryo >
< script src = "jhash.js" > < /senaryo >
< komut dosyası src = "fastClick.js" > < /senaryo >
< script src = "iScroll.js" > < /senaryo >
< script src = "undercore.js" > < /senaryo >
< script src = "handlebar.js" > < /senaryo >
< script src = "datacenter.js" > < /senaryo >
< script src = "util / wx bridge.js " > < /senaryo >
< script src = "util / login.js" > < /senaryo >
< script src = "util / base.js" > < /senaryo >
Bu nedenle, jQuery sonrası dönemde, Çin'de üç modül mekanizması popülerdir, ana gövde olarak seajs ile CMD, ana gövde olarak needj'ler ile AMD ve nodejs ile Commonjs. Tabii ki, üçü bir arada bir çözüm UMD'si (AMD, Commonjs ve es6 modülleri) de vardı.
Needjs tanımı ve kullanımı:
define (, function ($) {
// biraz kod
var mod = required ("./ göreli / ad");
dönüş {
// biraz kod
} // Dönüş değeri bir nesne, işlev vb. Olabilir.
})
required (, function (cores1, cores2, utils1, utils2) {
// biraz kod
})
Requirejs, dünyanın ilk evrensel modül yükleyicisidir, özellikle de kendi şim mekanizmasıdır, böylece birçok unmodel JS dosyası da yükleme sistemine dahil edilebilir.
define (function (required) {
var $ = required ("jquery");
$ ("# kapsayıcı"). html ("merhaba, seajs");
var service = required ("./ service")
var s = yeni hizmet;
s.hello;
});
// Başka bir bağımsız dosya service.js
define (function (require, export, module) {
function Service {
console.log ("bu hizmet modülüdür");
}
Service.prototype.hello = function {
console.log ("bu bir merhaba hizmetidir");
bunu geri ver;
}
module.exports = Hizmet;
});
Seajs, Alibaba'nın büyük Niu Yubojia'sının yükleyicisi. Requiejs'in birçok işlevini ödünç aldı ve performansının ve titizliğinin öncekini aştığını duydum. Şu anda, tanımlı geri aramadaki gereksinim ifadesini doğru bir şekilde analiz etmek için, yerli uzmanların becerilerini göstermesine izin vermek için 100 dolarlık bir ödül kampanyası başlatıldı.
https: // github .com / seajs / seajs / konular / 478
image_1doan2vfl17ld1nin1hbm 182 c9b9p.png-72.9kB
Nispeten konuşursak, nodejs modül sistemi çok daha basittir, özellikle kullanıcı kodunu sarmak için bir tanımlama yöntemine sahip değildir ve bağımlılıkları açık bir şekilde bildirmesi gerekmez.
//world.js
export.world = function {
console.log ('Merhaba Dünya');
}
//main.js
let dünya = gerekli ('./ world.js')
dünya;
function Merhaba {
var adı;
this.setName = function (thyName) {
isim = thyName;
};
this.sayHello = function {
console.log ('Merhaba' + ad);
};
};
module.exports = Merhaba;
Resmi es6 modülleri, yöntemlerinin ve nesnelerinin anahtar kelimelere dönüştürülmesi dışında nodejs modül sistemine çok benzer.
//test.js veya test.mjs
'./ test'ten test olarak içe aktar *;
//aaa.js veya aaa.mjs
{aaa} dosyasını "./aaa" içinden içe aktar
const arr =;
const obj = {
a: 0,
b: işlev {}
}
ihracat const foo = = > {
const a = 0;
const b = 20;
a + b döndür;
}
varsayılan ver {
num,
arr,
obj,
foo
}
Bu nasıl kullanılır? Spesifikasyona göre, tarayıcıların bu yeni özelliği desteklemek için etiketleri ve komut dosyası etiketlerini bağlamak için yeni öznitelikler veya öznitelik değerleri eklemesi gerekir. (Bakınız: https: // www .jianshu .com / p / f7db50cf956f)
< link rel = "modulepreload" href = "lib.mjs" >
< link rel = "modulepreload" href = "main.mjs" >
< script type = "modül" src = "main.mjs" > < /senaryo >
< script nomodule src = "fallback.js" > < /senaryo >
Ancak ne yazık ki, modül sistemi için tarayıcı desteği çok gecikiyor ve en son tarayıcı desteklese bile, yine de eski tarayıcıyla uyumlu olmamız gerekiyor. Bu bağlamda, webpack'i yalnızca güçlü bir araç olarak geliştirebiliriz. Bu bir ön uç mühendisliği ustasıdır.Kodumuzu çeşitli yükleyiciler / eklentiler aracılığıyla ana tarayıcılar tarafından tanınan JavaScript sözdizimine paketleyebilir ve en ilkel şekilde asabilir. Yükleyin.
Eşzamansız mekanizmaların evrimi
JavaScript'in büyük ölçekli uygulamasından önce, zaman uyumsuzluğun kullanıldığı tek yerler ajax istekleri ve animasyonlardı.İsteğin ve animasyonun sonunda yapılması gerekenler klasik geri çağırmadır.
Geri aramak
JavaScript tek iş parçacıklı olduğundan, yöntemimiz aşağıdaki gibi tek tek eşzamanlıdır:
A;
B;
C;
Eşzamansızlık tetiklendiğinde tahmin edilemez:
A;
// şimdi istek gönder
ajax ({
url: url,
veri: {},
başarı: işlev (res) {
// gelecekte bir noktada yürütün
B (öz)
}
})
C;
// Uygulama sırası: A- > C- > B
Geri çağırma işlevi, ana işlevin ardıl yöntemidir ve temelde ana işlevin çalıştırılmasının ardından bir süre sonra bir kez çalıştırılabileceğini garanti eder. Ancak işlevlerin bozulmasıyla, WeChat Applet'ler Veya hızlı uygulama, üçe ayrılırlar, yani bir yöntem ve ardından üç geri çağırma.
// https://doc.quickapp.cn/features/system/share.html
paylaşım'@system.share 'adresinden içe aktar
Paylaş Paylaş({
type: 'text / html',
veri: ' < b > cesur < / b > ',
başarı: işlev {},
başarısız: işlev {},
tamamlandı: işlev {}
})
Nodejs'de, yerleşik eşzamansız yöntemlerin tümü Error-first adlı bir geri çağrı modu kullanır.
fs.readFile ('/ foo.txt', function (err, data) {
// TODO: Hataların Giderilmesi Hala Gerekiyor!
console.log (veri);
});
Arka uçta, GÇ işlemlerinin varlığı nedeniyle, birçok eşzamansız işlem vardır ve eşzamansız eşzamansız kümeler kolayca geri arama cehennemine neden olabilir. Yani başka bir mod var, Event Center, EventBus veya EventEmiiter.
var EventEmitter = gerektirir ('olaylar'). EventEmitter;
var ee = yeni EventEmitter;
ee.on ('some_events', function (foo, bar) {
console.log ("İlk izleme olayı, foo =" + foo + "parametresi, bar =" + bar);
});
console.log ('İlk tur');
ee.emit ('some_events', 'Wilson', 'Zhong');
console.log ('İkinci tur');
ee.emit ('some_events', 'Wilson', 'Z');
Olay bir kez bağlanabilir ve birden çok kez tetiklenebilir ve orijinal dahili geri arama, geri arama cehenneminden etkili bir şekilde kaçınarak dışarı sürüklenebilir. Ancak olay merkezi, aynı davranış için her zaman bir geri aramayı yayınlar. Applet'ler Geri arama çok net. Böylece jQuery, Promise'ı tanıttı.
Söz vermek
Promise başlangıçta Python'un Twisted çerçevesinden tanıtılan Defered olarak adlandırıldı. Eşzamansız bir şekilde sınıfların yapımını tamamlar ve zincir aramalar yoluyla geri arama cehennemi sorununu çözer.
var p = new Promise (function (çözümleme, reddetme) {
console.log ("========")
setTimeout (function {
çözmek (1)
},300)
setTimeout (function {
// reddet ve çöz sadece birini seçebilir
reddetmek (1)
}, 400)
});
console.log ("Önce bunu çalıştır")
p.then (function (sonuç) {
console.log ('Başarı:' + sonuç);
})
.catch (function (neden) {
console.log ('Başarısız:' + neden);
}). nihayet (işlev {
console.log ("Her zaman çalıştır")
})
Neden öyle diyorsun? Yukarıdaki örneğe baktığımızda, yeni Söz (uygulayıcı) Yürütme yönteminde o zamana kadar çalıştırılmaz, catch, nihayet ve diğer yöntemler eklenir, asenkrondur. Ve sonra, yakalayın ve sonunda başarı, başarısızlık ve tamamlamanın üç geri çağrısına karşılık gelir. Promise'a zincirleme bir şekilde birden çok yöntem ekleyebiliriz.
Yakalama yazmak istemiyorsanız, son teknoloji tarayıcı aynı zamanda birleşik işleme için yeni bir etkinlik sağlar:
window.a gg EventListener ('unhandledrejection', function (event) {
// olay nesnesinin iki özel özelliği vardır:
alert (event.promise); // - Hatayı yaratan söz
alert (event.reason); // Hata: Hata! -İşlenmemiş hata nesnesi
});
yeni Promise (function {
yeni Hata at ("Hata!");
}); // Hataları işleyecek yakalama yok
nodejs de aynı olaya sahiptir:
process.on ('unhandledRejection', (sebep, vaat) = > {
console.log ('İşlenmemiş ret:', söz, 'neden:', neden);
// Günlükleri kaydedin, hataları veya başka bir mantığı atın.
});
Esma2020 ayrıca Promise'a üç statik yöntem ekledi: Promise.all ve Promise.race, Promise.allSettled.
Aslında, krom 60 zaten mevcut.
Promise.all (yinelenebilir) yöntemi bir Promise örneğini döndürür, yinelenebilir parametrede bu örnek tüm sözler "çözümlenir" veya parametre sözü içermez, geri çağırma tamamlanır (çözümlenir); parametrede verilen sözlerden biri başarısız olursa (reddedilirse) ), bu örnek geri araması başarısız oldu (reddedildi), başarısızlığın nedeni ilk başarısız sözün sonucudur.
var promise1 = Promise.resolve (3);
var promise2 = 42;
var promise3 = new Promise (function (çözümleme, reddetme) {
setTimeout (çözümleme, 100, 'foo');
});
Promise.all (). Sonra (function (değerler) {
console.log (değerler);
});
// beklenen çıktı: Dizi
Bu yöntem jQuery.when yöntemine benzer ve özellikle eşzamanlı işlemleri işlemek için kullanılır.
Promise.race (yinelenebilir) yöntemi bir söz verir. Yineleyicideki bir söz çözüldüğünde veya reddedildiğinde, iade edilen söz çözülür veya reddedilir. Bu yöntem yarış koşullarında kullanılır.
Promise.allSettled (yinelenebilir) yöntemi, verilen tüm sözler çözüldükten veya reddedildikten sonra çözülen bir söz verir ve her nesne, her bir sözün sonucunu açıklar. Promise.all'a benzer, ancak bir reddetme nedeniyle sonraki geri aramaları gerçekleştirmez ve tüm sözler yerine getirilmelidir.
Promise, EventBus, geri çağırmalardan vb. Daha iyi değildir, ancak ön uç API için bir çubuk sağlar ve daha sonra eşzamansız işlem, bir Promise döndürmektir. Daha sonra eşzamansız / beklemenin yolunu açın.
Oluşturucu
Jeneratör jeneratörü, asenkron problemi çözmek için doğmadı, ancak koa'nın popülaritesiyle birleştiğinde asenkronun karmaşıklığını ayırabilen bir özelliğe sahipti, insanlar orijinal jeneratörün hala bu şekilde kullanılabileceğini buldular, bu yüzden popüler hale geldi.
Üreteçlerin anlamını anlamak için önce yineleyicileri anlamamız gerekir Yineleyicideki yineleme, döngünün anlamıdır. Örneğin, es5'teki forEach, map ve filter yineleyicilerdir.
let sayılar =;
for (let i = 0; i < sayılar.length; i ++) {
console.log (sayılar );
}
// Yukarıdakinden daha akıcı
numbers.forEach (function (el) {
console.log (el);
})
Ama forEach tüm unsurları aynı anda geçecek ve onları tek tek işlemeyi sever miyiz? O zaman elle bir yineleyici yazmalıyız.
function makeIterator (dizi) {
var nextIndex = 0;
dönüş {
sonraki: function {
nextIndex < array.length?
{değer: dizi, tamamlandı: yanlış}:
{bitti: doğru};
}
};
}
var it = makeIterator ()
console.log (it.next); // {değer: 1, tamamlandı: yanlış}
console.log (it.next); // {değer: 2, tamamlandı: yanlış}
console.log (it.next); // {değer: 3, tamamlandı: yanlış}
console.log (it.next); // {bitti: doğru}
Jeneratör, tıpkı bir sınıf oluşturmak gibi, yineleyiciler oluşturmanın ortak modelini resmileştiriyor, ancak anahtar kelimesi olan bir sınıfın aksine, biraz tuhaf yazılıyor ve Promise gibi bir sınıfı yok.
// İdeal olarak böyle
Yineleyici {
exector {
verim 1;
verim 2;
verim 3;
}
}
// Gerçek böyle
function * Yineleyici {
verim 1;
verim 2;
verim 3;
}
Aslında, Promise gibi bir sınıf yapmak en iyisidir, o zaman simüle etmek için hazır sözdizimini de kullanabiliriz, ancak şimdi yeni bir anahtar kelime verimi olan oluşturucu, bunu bir dönüş ifadesi olarak ele alabilirsiniz. Jeneratör çalıştırıldıktan sonra, bir nesne üretecek, bir sonraki metodu var, bir sonraki yöntemin kaç kez çalıştırıldığı, getiri değerinin döndürülecek dönüşüdür.
function * Yineleyici {
verim 1;
verim 2;
verim 3;
}
let it = Yineleyici;
console.log (it.next); // {değer: 1, tamamlandı: yanlış}
console.log (it.next); // {değer: 2, tamamlandı: yanlış}
console.log (it.next); // {değer: 3, tamamlandı: yanlış}
console.log (it.next); // {değer: tanımsız, tamamlandı: doğru}
Yazma yöntemi görece mürted olduğu için, genellikle sınıf kitaplığı çerçevesinde görülür ve işte çok az kişi onu kullanır. Getiri ve getirinin karışık kullanımı gibi birçok detayı içerir.
fonksiyon üreticisi {
verim 1;
return 2; // Bu, 2 sonucuna dönüştürülür ve hemen bitti olarak ayarlanır: doğru
verim 3; // bu göz ardı edilir
}
let it = oluşturucu;
console.log (it.next); // {değer: 1, tamamlandı: yanlış}
console.log (it.next); // {değer: 2, tamamlandı: doğru}
console.log (it.next); // {değer: tanımsız, tamamlandı: doğru}
image_1doda17jkj7kl4u1qru1era2m316.png-322.9kB
Ama bu kadar çok şey söyledim, bunun eşzamansızlıkla ne alakası var? Geri aramalara, olaylara ve Promises'e ihtiyaç duymamızın nedeni, aslında eşzamanlı kod biçiminde eşzamansız mantığı uygulamaktır. Verim, programın yürütülmesini kesintiye uğratabilecek bir kesme noktasıdır. Yani asenkron mantık şu şekilde yazılabilir:
fonksiyon üreticisi {
verim setTimeout (işlev {console.log ("111"), 200})
verim setTimeout (işlev {console.log ("222"), 100})
}
let it = oluşturucu;
console.log (it.next); // 1 Tarayıcıya bağlıdır
console.log (it.next); // 2 tarayıcıya bağlı olarak
Verim yoksa, önce 222, sonra 111 oynamalısınız.
Eşzamansız kod çıktısını eşzamanlı kod sırasına göre elde ettikten sonra, bir sonraki yöntemi manuel olarak yürütme sorunuyla uğraşıyoruz. Bu da basittir, bir yöntem yazın ve bunları bir programda çalıştırın.
function timeout (data, time) {
yeni Promise (işlev (çözümleme) {
setTimeout (function {
console.log (veriler, yeni Tarih-0)
çözümlemek (veri)
},zaman)
})
}
fonksiyon üreticisi{
let p1 = verim zaman aşımı (1, 2000)
console.log (p1)
let p2 = verim zaman aşımı (2, 3000)
console.log (p2)
p3 = verim zaman aşımına izin verin (3, 2000)
console.log (p3)
dönüş 2;
}
// 12 3 sırasına göre çıktı
/ * Yürütülecek gen'i aktar * /
/ * Aslında tüm evrelerde döngü (işlevin özyinelemesi)
Sonuncunun çalıştırılıp çalıştırılmayacağını belirlemek için next'in dönüş değerinde yapılan eleyin,
Sonuncuysa atla * /
function run (fn) {
var gen = fn;
sonraki işlev (veri) {
// gen.next'i çalıştırın, ilk veriler tanımsızdır
var sonuç = gen.next (veri)
// sonuç.done doğruysa
eğer (sonuç.done) {
return result.value
}Başka{
// sonuç.değer vaattir
result.value.then (val = > {
sonraki (val)
})
}
}
// önceki sonraki yöntemi çağır
Sonraki;
}
çalıştır (jeneratör)
koa Önceki sürümün dayandığı ortak kitaplık, eşzamansız sorunu çözmek için yukarıdaki ilkeye dayanıyordu. İlgilenen öğrenciler gelip bakabilirler.
eşzamansız / bekleyin
Önceki bölümdeki jeneratör mükemmel bir şekilde çözüldü Eşzamansız mantık eşzamanlı kodla yazılır Sorun şu ki, bir istisna varsa, doğrudan catch'i deneyebilir ve başarılı olursa doğrudan aşağı inebilirsiniz.En sonunda ifadesini her zaman çalıştırabilirsiniz. Buradaki sorun, yöntemi verdikten sonra değiştirip Promise olarak değiştirmeniz gerektiğidir (bu aynı zamanda doğrudan nodejs içinde bir kitaplığa sahiptir Yerleşik util.promisefy). Daha sonra manuel yerine bir çalıştırma yöntemine ihtiyaç vardır. Öyleyse, dil tedarik zincirinin üst akışındaki büyük adamlar, bu iki adım doğrudan inşa edilebilir mi diye düşündüler. Öyleyse kabul edilmiş bir grameri paketleyip dünyayı hiç görmemiş ön uç mühendislere sunmak mı? Tekrar aradılar ve gerçekten bu şey vardı. Yani C # eşzamansız / beklemeye sahiptir.
// C # kodu
genel statik zaman uyumsuz Görev < int > Bir gg Eşzamansız (int n, int m) {
int val = Task.Run (= > Bir gg (n, m));
dönüş değeri;
}
Öğrenme maliyeti olmayan bu tür bir dilbilgisi hızla JS'ye taşınır. Async anahtar sözcüğü, bir jeneratör işlevine ve kendi kendine yürütme işlevimize eşdeğerdir. Await anahtar sözcüğü verim ile eşdeğerdir, ancak yalnızca bir Promise izlediğinde kesintiye uğrar. Süreç yürütme. Eşzamansız işlev sonunda, external await anahtar sözcüğü tarafından kullanılabilen bir Promise döndürecektir.
// javascript kodu
eşzamansız işlev a gg Görev {
yeni Promise'i bekliyoruz (function (resol) {
setTimeout (işlev {console.log ("111"); çözümleme, 200})
})
console.log ('222')
yeni Promise'i bekliyoruz (function (resol) {
setTimeout (işlev {console.log ("333"); çözümleme, 200})
})
console.log ('444')
}
var p = a gg Görev
console.log (p)
image_1do gg 79 nc1imnnm91q1b1p7qhdp1j.png-6,1kB
Bir döngüde zaman uyumsuz / beklemeyi kullanın:
const dizi =
function getNum (num) {
yeni Promise (işlev (çözümleme) {
setTimeout (function {
çözümlemek (num)
}, 300)
})
}
async function asyncLoop {
console.log ("başlat")
for (let i = 0; i < dizi.length; i ++) {
const num = await getNum (dizi );
console.log (num, new Date-0)
}
console.log ("son")
}
asyncLoop
Eşzamansız işlevdeki hatalar ayrıca try catch ile sarılabilir veya yukarıda belirtilen işlenmemiş ret yöntemi de kullanılabilir.
eşzamansız işlev a gg Görev {
Deneyin{
bekle ...
console.log ('222')
} catch (e) {
console.log (e)
}
}
Ek olarak, es2018, çeşitli asenkron senaryoları daha rahat işlememizi sağlayan asenkron yineleyici ve asenkron jeneratör işlevleri de ekler:
// Eşzamansız yineleyici
const ruby = {
: = > {
const öğeler =;
dönüş {
sonraki: = > Promise.resolve ({
done: items.length === 0,
değer: items.shift
})
}
}
}
for await (const item of ruby) {
console.log (öğe)
}
// Eşzamansız üreteç işlevi, eşzamansız işlev ve üreteç işlevinin bir karışımı
eşzamansız işlev * readLines (yol) {
let file = await fileOpen (yol);
Deneyin {
while (! file.EOF) {
verim await file.readLine;
}
} en sonunda {
file.close bekleyin;
}
}
Blok düzeyinde kapsamın tamamlanması
Eylemin kapsamından bahsetmişken, herkes genellikle JavaScript'in yalnızca global bir kapsamı ve bir işlev kapsamı olduğunu düşünür, ancak es3 çağında, catch deyimi ve with ifadesi aracılığıyla yine de blok düzeyinde bir kapsam oluşturabilir.
Deneyin{
var name = 'global' // Global kapsam
} catch (e) {
var b = "xxx"
console.log (b) // xxx
}
console.log (b)
var obj = {
ad: "blok"
}
ile (obj) {
console.log (ad); // Blok bloğundaki ad bloğu
}
console.log (ad) // global
Ancak catch deyimi yürütüldükten sonra, yine de dış kapsamı kirletecektir ve catch, çok performans tüketir. Bahsetmiyorum bile, belirsizliğe neden olacak ve es5 katı modu tarafından yasaklanmıştır.
Yine, blok kapsamına ihtiyaç duyulmasının nedeni es3'ün iki kötü tasarımını çözmektir, biri değişken terfi, diğeri ise ekip çalışmasına ve seri üretime elverişli olmayan tekrarlı tanımlamadır.
var x = 1;
function rain {
alert (x); // 1 yerine 'tanımsız' açılır
var x = 'yağmur-adam';
alert (x); // 'yağmur adamı' açılır
}
yağmur;
Dolayısıyla es6'da blok düzeyinde kapsam elde etmek için let ve const anahtar sözcükleri eklenir. Var ile karşılaştırıldığında, bu iki anahtar kelime aşağıdaki özelliklere sahiptir:
Kapsam yereldir ve kapsam, onu çevreleyen iki kaşlı ayraç arasındadır, yani için{} , süre{} , Eğer{} Ve basit {} .
Kapsamın tepesine yükseltilmeyecek ve üstten tanıma kadar olan satıra "geçici ölü bölge" adı verilir. Şu anda bir hata bildirecektir.
Değişken let veya const olarak bildirildikten sonra tekrar tanımlanamaz, aksi takdirde bir hata bildirilir. Bu katı hata istemi, hata ayıklamamız için çok yararlıdır.
let a = "hey ben dışarıdayım";
Eğer doğruysa){
// Burada geçici bir ölü bölge var
console.log (a); // Yakalanmamış ReferenceError: a tanımlı değil
let a = "hey ben içerideyim";
}
// let ve const'ın değişken yükseltmesi yoktur
console.log (a); // Yakalanmamış ReferenceError: a tanımlı değil
console.log (b); // Yakalanmamış Referans Hatası: b tanımlı değil
let a = 1; // Yakalanmamış SyntaxError: Identifier'a 'zaten bildirilmiş
const b = 2;
// Değişken yükseltme yoktur, bu nedenle blok düzeyi kapsamın dış katmanına erişilemez
Eğer doğruysa){
var bar = "bar";
let baz = "baz";
const qux = "qux";
}
console.log (bar); // bar
console.log (baz); // baz tanımlı değil
console.log (qux); // qux tanımlı değil
Const bildiriminin let bildiriminden bir tane daha işlevi vardır, böylece hedef değişkenin değeri yeniden değiştirilemez, yani diğer dillerin sabiti.
Temel türlerde artış
JavaScript'te nesne türlerini typeof ve Object.prototype.toString.call ile ayırt edebiliriz Geçmişte her zaman 7 tür vardı: undefined ,, string, number, boolean, function, object. Şimdi iki tür daha var, biri es6 tarafından sunulan Symbol ve diğeri es2019'dan bBigInt.
console.log (typeof 9007 199 254740991n); // "bigint"
console.log (typeof Symbol ("aaa")); // "sembol"
Sembolün üç özelliği vardır, oluşturulan değer benzersizdir, ekli nesne çapraz geçiş yapılamaz ve örtük dönüştürmeyi desteklemez. Ayrıca, nesneye daha fazla işlev genişletmek için Symbol'de başka statik yöntemler de vardır.
Önce benzersiz bir özellik değerini nasıl temsil ettiğine bakarız. Sembol olmadan, sabitleri temsil etmenin her zamanki yolu güvenilmezdir.
const COLOR_GREEN = 1
const COLOR_RED = 2
const LALALA = 1;
function isSafe (değiştirgeler) {
eğer (args === COLOR_RED) yanlış döndürürse
eğer (args === COLOR_GREEN) true döndürürse
yeni Hata oluştur (`Geçersiz parametre geçişi: $ {args}`)
}
console.log (isSafe (COLOR_GREEN)) // doğru
console.log (isSafe (COLOR_RED)) // yanlış
console.log (isSafe (LALALA)) // doğru
Sembol ise beklentilerimizi karşılar:
const COLOR_GREEN = Sembol ("1") // Aktarılan parametre dize, sayı, boole veya boş olabilir
const COLOR_RED = Sembol ("2")
const LALALA = Sembol ("1")
function isSafe (değiştirgeler) {
eğer (args === COLOR_RED) yanlış döndürürse
eğer (args === COLOR_GREEN) true döndürürse
yeni Hata oluştur (`Geçersiz parametre geçişi: $ {args}`)
}
console.log (isSafe (COLOR_GREEN)) // doğru
console.log (isSafe (COLOR_RED)) // yanlış
console.log (COLOR_GREEN == LALALA) // false
console.log (isSafe (LALALA)) // hatası at
Symbol'ün bir kurucu olmadığını ve yeni olamayacağını unutmayın. yeni Symbel ("222") Bir hata yapacak.
İkinci nokta, geçmiş nesne özelliklerinin tümünün dize türleri olmasıdır. İşleme için Object.defineProperty kullanmazsak, doğrudan kullanılabilirler. için Dışarı çıkın. Symbol niteliği farklıdır ve değiştirilemez, bu nedenle nesnenin özel bir niteliği olarak uygundur, çünkü ona yalnızca adını biliyorsanız erişebilirsiniz.
var a = {
b: 11,
c: 22
}
var d = Sembol;
a = 33
for (i in a) {
console.log (i, a ) // sadece b, c
}
Üçüncü nokta, önceki veri türlerinin bir dizeye eklenebilmesi veya bir sayının çıkarılıp ardından dolaylı olarak bir sayıya dönüştürülebilmesidir; Symbol doğrudan bir hata atarken.
ar d = Sembol ("11")
console.log (d-1)
Statik yöntemine tekrar bakalım:
Symbol.for
Bu bir Sembole benzer, ancak benzersiz bir değeri temsil etmez. Symbol.for ile bir sembol oluşturulursa, bir dahaki sefere aynı parametrelerle erişilirse aynı sembolü döndürür.
Symbol.for ("foo"); // Bir sembol oluşturun ve onu sembol kayıt defterine koyun, anahtar "foo"
Symbol.for ("foo"); // sembol kayıt defterinden "foo" anahtarlı sembolü oku
Symbol.for ("bar") === Symbol.for ("bar"); // true, yukarıdakileri kanıtlar
Symbol ("bar") === Symbol ("bar"); // false, Symbol işlevi her defasında yeni bir sembol döndürür
var sym = Symbol.for ("mario");
sym.toString;
Yukarıdaki örnek, resmi Firefox belgelerinden alınmıştır.Kayıt defteri gibi şeylerden bahseder.Başka bir deyişle, Symbol.for tarafından oluşturulan tüm sembollerimiz dahili bir nesne tarafından yönetilir.
Symbol.keyFor
Symbol.keyFor yöntemi, kayıtlı bir sembol türü değerinin anahtarını döndürür. Anahtar, aynı zamanda sembolün açıklama niteliği ile aynı olan parametremizdir.
let s1 = Symbol.for ("111");
console.log (Symbol.keyFor (s1)) // "111"
console.log (s1.description) // "111"
let s2 = Sembol ("222");
console.log (Symbol.keyFor (s2)) // tanımsız
console.log (s2.description) // "222"
let s3 = Symbol.for (111);
console.log (Symbol.keyFor (s3)) // "111"
console.log (s3.description) // "111"
Symbol.for tarafından Symbol değeri için kaydedilen adın global ortamda olduğu ve aynı değerin farklı iframe veya servis çalışanlarında elde edilebileceği unutulmamalıdır.
iframe = document.createElement ('iframe');
iframe.src = Dize (window.location);
document.body.appendChild (iframe);
iframe.contentWindow.Symbol.for ('111') === Symbol.for ('111') // true
Symbol.iterator
Es6 eklendi için Döngü, göreceli için Döngü, değeri doğrudan çaprazlamaktır. Bunun nedeni, yerleşik bir yineleyici olan dizi prototipine Symbol.iterator'ın eklenmesi ve için Yürütme işlevinin sözdizimidir. Diziler, dizeler, bağımsız değişkenler, NodeList, TypeArray, Set, Map, WeakSet, WeatMap prototipleri gibi Symbol.iterator eklenir, böylece hepsi kullanılabilir için döngü.
console.log (Yeni Dizede Symbol.iterator ('sss')) // basit türleri kullanmak için nesnelere sarın
console.log (Symbol.iterator içinde)
console.log (Yeni Kümede Symbol.iterator ())
for ("123" değişken i) {
console.log (i) // 1,23
}
Ama yapıyoruz için Döngü bir istisna ile karşılaşır ve bunu kendimiz eklememiz gerekir.
Object.prototype = function {
var anahtarlar = Nesne.keys (bu);
var indeksi = 0;
dönüş {
sonraki: = > {
var obj = {
değer: bu,
bitti: dizin + 1 > keys.length
};
indeks ++;
obj iad;
}
};
};
var a = {
isim: 'yakut',
yaş: 13,
ana sayfa: "Guangdong"
}
for (a'nın değişkeni) {
console.log (val);
}
Symbol.asyncIterator
Symbol.asyncIterator ve beklemek için Döngüyü birlikte kullanın, yukarıdaki eşzamansız bölüme bakın.
Symbol.replace, ara, ayır
Bu statik özelliklerin tümü düzenlilikle ilgilidir.Bu yöntem adının dizede aynı yüze sahip olduğunu bulacağız.Bu yöntemlerin davranışını, bir nesneyi alabilmeleri için değiştirecekler ve bu nesnelerin karşılık gelen sembol koruma yöntemleri var. Ayrıntılar için aşağıdaki örneğe bakın:
sınıf Arama1 {
yapıcı (değer) {
this.value = değer;
}
(string) {
dönüş string.indexOf (this.value);
}
}
console.log ('foobar'.search (yeni Arama1 (' bar ')));
sınıf Replace1 {
yapıcı (değer) {
this.value = değer;
}
(string) {
"s / $ {string} / $ {this.value} / g` döndür;
}
}
console.log ('foo'.replace (yeni Replace1 (' bar ')));
class Split1 {
yapıcı (değer) {
this.value = değer;
}
(string) {
var index = string.indexOf (this.value);
this.value + string.substr (0, dizin) + "/" döndür
+ string.substr (dizin + this.value.length);
}
}
console.log ('foobar'.split (yeni Split1 (' foo ')));
Symbol.toStringTag
Özel sınıfın Object.prototype.toString.call sonucunu belirleyebilirsiniz:
class ValidatorClass {
almak {
return'Validator ';
}
}
console.log (Object.prototype.toString.call (yeni ValidatorClass));
// beklenen çıktı: ""
Ek olarak, temel dilin daha rafine bir formülasyonunu yapmamız için uygun olan birçok statik özellik vardır. Tek tek Listelenmiş.
BigInt'e tekrar bakarsak, o kadar da karmaşık değil. JavaScript'in ilk dönemlerinde, tamsayı aralığı 2 üzeri 53 üssü eksi bir artı veya eksi idi. Bu aralığı aşarsa, değer yanlış olacaktır.
console.log (1234567890123456789 * 123) // Bu açıkça yanlış
Bu nedenle, böyle bir veri türüne çok ihtiyacımız var, ortaya çıkmadan önce, simüle etmek için sadece string kullanabiliriz. Daha sonra chrome67'de bu tür zaten yerleşiktir. Kullanmak istiyorsanız, numaranın hemen arkasına bir n ekleyebilir veya BigInt'i oluşturmak için kullanabilirsiniz.
const theBiggestInt = 9007 199 254740991n;
const alsoHuge = BigInt (9007 199 254740991);
// 9007 199 254740991n
const hugeString = BigInt ("9007 199 254740991 ");
// 9007 199 254740991n
const hugeHex = BigInt ("0x1fffffffffffff");
// 9007 199 254740991n
const hugeBin = BigInt ("0b111111111111111111111111111111111111111111111111111111111");
console.log (typeof hugeBin) // bigint
Yansıma mekanizmasının iyileştirilmesi
Yansıma mekanizması, programın çalışırken kendi bilgilerini elde edebileceği anlamına gelir. Örneğin, bir nesne çalışma zamanında hangi özelliklerin gerçekleştirildiğini ve hangi işlemlerin gerçekleştirildiğini bilebilir.
Gözümüze çarpan ilk şey, IE8'in getirdiği get ve set anahtar kelimeleriydi. Bu, diğer dillerin alıcısıdır. Tek bir nitelik gibi görünüyor, ama aslında iki yöntem.
var iç = 0;
var obj = {
set a (val) {
console.log ("set a")
iç = değer
},
bir {
console.log ("get a")
dönüş +2
}
}
console.log (obj)
obj.a = 111
console.log (obj.a) // 113
image_1dojfhdi1vqbdqg1hr4mkt52h9.png-11.9kB
Ancak babel.js doğmadan önceki çağda, yeni sözdiziminin ayakta kalması zordur, bu nedenle IE8 ayarlayıcıları ve alıcıları tanımlamak için iki benzer API yaptı: Object.defineProperty ve Object.defineProperties. İkincisi, birincisinin gelişmiş bir versiyonudur.
var iç = 0;
var obj = {}
Object.defineProperty (obj, 'a', {
set: function (val) {
console.log ("set a")
iç = değer
},
get: function {
console.log ("get a")
dönüş +2
}
})
console.log (obj)
obj.a = 111
console.log (obj.a) // 113
Standart tarayıcı ne olacak? IE8 döneminde, firefox ayrıca buna karşılık gelen özel bir uygulamaya sahiptir: __defineGetter__ , __defineSetter__ , Nesnenin prototip zincirinde asılı duruyorlar.
var iç = 0;
var obj = {}
obj .__ defineSetter __ ("a", function (val) {
console.log ("set a")
iç = değer
})
obj .__ defineGetter __ ("a", function {
console.log ("get a")
dönüş + 4
})
console.log (obj)
obj.a = 111
console.log (obj.a) // 115
Üç ana çerçevenin yükselişinden önce, MVVM'nin karnaval çağıydı.Avalon gibi çerçeveler, bu yöntemleri MVVM'de VM'leri uygulamak için kullandı.
Ayarlayıcılar ve alıcılar, IE'nin on yıldan uzun süredir durgunluğuna eklenen önemli bir özelliktir ve JavaScript'i modern ve daha büyülü kılar.
Ancak sadece nesne özniteliğinin atama değerini izleyebilirler.Bir nesne ilk başta tanımlanmazsa, daha sonra eklenirse izlenmez; bir nesne özniteliğini silersek, izleyemeyiz; bir elemana yapılan bir diziyi izleyemeyiz. Her sınıfın somutlaştırılması izlenemiyor ... Kısacası, sınırlama hala çok büyük. Bu nedenle, belirli bir Chrome sürümü, nesnelerin çeşitli eylemlerinin eşzamansız olarak izlenmesini destekleyen Object.observe ekledi ("a gg "," güncelle "," sil "," yeniden yapılandır "," setPrototype "," preventExtensions "), ancak diğer tarayıcılar bunu desteklemiyor, bu nedenle esma komitesi başka bir Proxy ile meşgul olmak için birleşti.
Vekil
Bu es6'nın ünlü sihirli proxy nesnesidir. Object.defineProperty gibi, eski yöntemle simüle edilemez.
Aşağıdakiler kullanımı ve engelleyicisi tarafından temsil edilen işlemlerdir:
let p = new Proxy ({}, {// Yakalayan nesne, üzerinde şu engelleyiciler var
get: function (hedef, ad) {
// obj.aaa
},
set: function (hedef, ad, değer) {
// obj.aaa = bbb
},
construct: function (hedef, değiştirgeler) {
//yeni
},
apply: function (target, thisArg, args) {
// Bir yöntemi yürütün
},
defineProperty: function (hedef, ad, tanımlayıcı) {
// Object.defineProperty
},
deleteProperty: function (hedef, ad) {
// sil
},
has: function (hedef, ad) {
// içinde
},
ownKeys: function (hedef, ad) {
// Object.getOwnPropertyNames
// Object.getOwnPropertySymbols
// Object.keys Reflect.ownKeys
},
isExtensible: function (hedef) {
// Object.isExtensible.
},
preventExtensions: function (hedef) {
// Object.preventExtensions
},
getOwnPropertyDescriptor: function (hedef, prop) {
// Object.getOwnPropertyDescriptor
},
getPrototypeOf: function (hedef) {
// Object.getPrototypeOf,
// Reflect.getPrototypeOf,
// __proto__
// Object.prototype.isPrototypeOf ve instanceof
},
setPrototypeOf: function (hedef, prototip) {
// Object.setPrototypeOf.
}
});
Bu nesne vue3, mobx'te yaygın olarak kullanılmaktadır.
Yansıt
Reflect Proxy ile birlikte piyasaya sürüldü.Reflect üzerindeki metot, Proxy'nin yakalayıcısı ile aynı isme sahip ve bazı Object.xxx işlemleri ve in, new ve delete gibi anahtar işlemleri için kullanılıyor (bu sefer onları sadece fonksiyonel metotlara çevirin). Başka bir deyişle, Proxy canlı olarak almaktır, Reflect çalışmaktır, Firefox'un resmi web sitesindeki örnek de bunu yansıtır.
var p = new Proxy ({
a: 11
}, {
deleteProperty: function (hedef, ad) {
console.log (bağımsız değişkenler)
return Reflect.deleteProperty(target, name)
}
})
delete p.a
Object.xxx Object.defineProperty ObjectReflect
Reflect13
Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)
JavaScriptparser
functionthisreturn
for of for in
, 1_222_333
hello ${world}
**
let x = foo?.bar.baz;
, let x = foo ?? bar;
sonuç olarak
ECMAScript babel https:// www .babeljs.cn/docs/pluginsJavaScript
JavaScriptmassAvalonnanachi Applet'ler
SON