JavaScript neden günümüze kadar yaşıyor?

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

    Ünlü kozmetiklerin raf ömrü sadece 3 ay mı? Son kullanma tarihi geçmiş kozmetikler kullanıp kullanmadığınızı görün
    önceki
    Avrupa tarzı büyük göz makyajını açmanın doğru yolu budur.
    Sonraki
    Her şeyin birbirine bağlanmasını hızlandırmak için 5G + bulut ağ entegrasyonu
    Güzel resimlerin takdir edilmesi Hangzhou Mao Geping resim tasarımı öğrencilerinin mükemmel çalışmaları
    Size üç güzel ve zarif küçük peri örgülü saçları öğretin, düşünmek ya da düşünmek zor
    Muhteşem bir moda grafik yaratıcı makyajı gişe rekorları kıran filmi paylaşın! Makyaj sanatçısı kabul etmelidir
    İlk bakışta harika hissetmek ister misiniz? Sadece bu göz makyajını seç
    Göz makyajını böyle uygulamak modaya uygun ve kadınsıdır ve onu kim sürerse güzelleşir.
    Double Eleven, bina oynamayın, doğrudan fiyatı düşürün
    sadece! Anhui, ağır kirlilik hava durumu uyarı bilgilerini kaldırdı
    Gözlerinizi daha belirgin hale getirmek istiyorsanız yoğun makyaj ve hafif uygulama yapmadan yapabilirsiniz.
    Kalp kırıklığı! Sina Yıllık Raporu: 90'lar sonrası programcıların aylık maaşı 20.000, kız arkadaşı yok
    Shenzhen Mao Geping Görüntü Tasarımı | Makyaj Modelleme Öğrencilerinin Mükemmel Çalışmaları
    Bu Mori gelin görünümünü öğrenmeyin çünkü çok güzel ve tehlikeli
    To Top