Rumah >hujung hadapan web >tutorial js >Mendedahkan keajaiban javascript

Mendedahkan keajaiban javascript

Lisa Kudrow
Lisa Kudrowasal
2025-02-21 09:38:10646semak imbas

Mendedahkan keajaiban javascript

Kami menggunakan banyak alat setiap hari. Perpustakaan dan rangka kerja yang berbeza adalah sebahagian daripada pekerjaan harian kami. Kami menggunakannya kerana kami tidak mahu mencipta semula roda untuk setiap projek, walaupun kami tidak memahami apa yang berlaku di bawah tudung. Dalam artikel ini, kami akan mendedahkan beberapa proses ajaib yang berlaku di perpustakaan yang paling popular. Kami juga akan melihat jika kita dapat meniru tingkah laku mereka.

Takeaways Key

    perpustakaan JavaScript seperti jQuery memudahkan manipulasi DOM, seperti membuat unsur -unsur dari rentetan, dengan mengendalikan kes -kes yang kompleks seperti elemen bersarang dengan betul.
  • sistem suntikan pergantungan AngularJS secara ajaib menguruskan kebergantungan tanpa lulus eksplisit, menggunakan corak penyuntik untuk memberikan ketergantungan secara dinamik pada masa runtime.
  • Ember.js meningkatkan objek JavaScript dengan sifat -sifat yang dikira, yang membolehkan sifat berkelakuan seperti fungsi, mengemas kini secara automatik apabila kebergantungan berubah.
  • sintaks JSX React membolehkan membenamkan HTML dalam JavaScript, yang kemudian diproses oleh pengubah JSX React untuk membuat komponen UI dinamik.
  • Artikel ini menunjukkan penyelesaian tersuai untuk suntikan ketergantungan dan sifat -sifat yang dikira, menunjukkan bagaimana pemaju dapat melaksanakan fungsi yang sama dalam projek mereka.
  • Memahami mekanik asas kerangka JavaScript yang popular dapat memberi kuasa kepada pemaju untuk menulis kod yang lebih efisien dan dikekalkan.
Membuat elemen dom dari rentetan

Dengan kebangkitan aplikasi halaman tunggal, kami melakukan banyak perkara dengan JavaScript. Sebahagian besar logik aplikasi kami telah dipindahkan ke pelayar. Ia adalah tugas yang sama untuk menjana atau menggantikan elemen pada halaman. Kod yang serupa dengan apa yang ditunjukkan di bawah telah menjadi sangat biasa.

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>
Hasilnya adalah elemen
baru yang ditambahkan ke dalam badan dokumen. Operasi mudah ini dilakukan dengan hanya satu baris jQuery. Tanpa jQuery, kod itu sedikit lebih kompleks, tetapi tidak banyak:

<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>
Kami menentukan kaedah utiliti kami sendiri StringTodom yang mencipta elemen
sementara. Kami menukar harta InnerHTML dan pada akhirnya kami hanya mengembalikan anak pertama yang dalam praktiknya adalah apa yang kami perlukan. Ia berfungsi dengan cara yang sama. Walau bagaimanapun, kami akan melihat hasil yang berbeza dengan kod berikut:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>
secara visual, pada halaman, tidak ada perbezaan. Walau bagaimanapun, jika kita menyemak markup yang dihasilkan dengan alat pemaju Chrome, kita akan mendapat hasil yang menarik:

Ia kelihatan seperti fungsi StringTodom kami yang dibuat hanya nod teks dan bukan tag

sebenar. Tetapi pada masa yang sama, jQuery entah bagaimana berjaya melakukannya. Masalahnya ialah rentetan yang mengandungi elemen HTML dijalankan melalui parser dalam penyemak imbas. Parser itu mengabaikan tag yang tidak diletakkan dalam konteks yang betul, dan kami hanya mendapat nod teks. Baris meja tanpa jadual tidak sah untuk penyemak imbas.

JQuery berjaya menyelesaikan masalah dengan mewujudkan konteks yang betul dan mengekstrak hanya bahagian yang diperlukan. Jika kita menggali sedikit ke dalam kod perpustakaan kita akan melihat peta seperti ini:

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

Setiap elemen yang memerlukan rawatan khas mempunyai array yang diberikan. Idea ini adalah untuk membina elemen DOM yang betul dan bergantung kepada tahap sarang untuk mengambil apa yang kita perlukan. Sebagai contoh, untuk elemen

kita perlu membuat jadual dengan kanak -kanak . Jadi, kami mempunyai dua tahap bersarang.

Mempunyai peta, kita perlu mengetahui jenis tag yang kita mahu pada akhirnya. Kod berikut mengekstrak TR dari

teks mudah
<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

selebihnya mencari konteks yang betul dan mengembalikan elemen DOM. Berikut adalah varian akhir fungsi StringTodom:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>

Perhatikan bahawa kami sedang menyemak jika terdapat tag dalam rentetan - padanan! = Null. Jika tidak kita hanya mengembalikan nod teks. Masih terdapat penggunaan sementara

, tetapi kali ini kami melewati tag yang betul supaya penyemak imbas dapat membuat pokok DOM yang sah. Pada akhirnya dengan menggunakan gelung sementara kita akan lebih mendalam dan lebih mendalam sehingga kita mencapai tag yang dikehendaki.

Berikut adalah codepen yang menunjukkan pelaksanaan kami:

Lihat pena XLCGN oleh Krasimir Tsonev (@Krasimir) pada codepen.

mari kita teruskan dengan meneroka suntikan ketergantungan AngularJS yang indah.

mendedahkan suntikan ketergantungan angularjs

Apabila kita mula menggunakan AngularJS, ia mengesankan dengan mengikat data dua hala. Perkara kedua yang kami perhatikan ialah suntikan pergantungan ajaibnya. Berikut adalah contoh mudah:

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>

Itulah pengawal AngularJS yang tipikal. Ia melakukan permintaan HTTP, mengambil data dari fail JSON, dan lulus ke skop semasa. Kami tidak melaksanakan fungsi Todoctrl - kami tidak mempunyai peluang untuk lulus sebarang hujah. Rangka kerja itu. Jadi, di manakah skop $ ini dan pembolehubah HTTP $ datang? Ia adalah ciri super sejuk, yang sangat menyerupai sihir hitam. Mari kita lihat bagaimana ia dilakukan.

Kami mempunyai fungsi JavaScript yang memaparkan pengguna dalam sistem kami. Fungsi yang sama memerlukan akses kepada elemen DOM untuk meletakkan HTML yang dihasilkan, dan pembungkus Ajax untuk mendapatkan data. Untuk memudahkan contoh, kami akan mengejek data dan HTTP meminta.

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

Kami akan menggunakan tag

sebagai pemegang kandungan. AjaxWrapper adalah objek yang mensimulasikan permintaan dan Datamockup adalah array yang mengandungi pengguna kami. Inilah fungsi yang akan kita gunakan:
<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

Dan tentu saja, jika kita menjalankan paparan (badan, ajaxwrapper) kita akan melihat tiga nama yang dipaparkan pada halaman dan /API /pengguna yang diminta dalam konsol kami. Kita boleh mengatakan bahawa kaedah kita mempunyai dua kebergantungan - badan dan AjaxWrapper. Oleh itu, sekarang idea itu adalah untuk membuat fungsi berfungsi tanpa lulus argumen, iaitu kita perlu mendapatkan hasil yang sama dengan memanggil hanya displayusers (). Sekiranya kita berbuat demikian dengan kod setakat ini, hasilnya akan menjadi:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>

dan itu normal kerana parameter Ajax tidak ditakrifkan.

Kebanyakan rangka kerja yang menyediakan mekanisme untuk suntikan ketergantungan mempunyai modul, biasanya dinamakan penyuntik . Untuk menggunakan kebergantungan, kita perlu mendaftarkannya di sana. Kemudian, pada satu ketika, sumber kami diberikan kepada logik aplikasi dengan modul yang sama.

mari buat penyuntik kami:

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>

kita hanya memerlukan dua kaedah. Yang pertama, mendaftar, menerima sumber (kebergantungan) kami dan menyimpannya secara dalaman. Yang kedua menerima sasaran suntikan kami - fungsi yang mempunyai kebergantungan dan perlu menerimanya sebagai parameter. Momen utama di sini ialah penyuntik tidak boleh memanggil fungsi kami. Itulah tugas kita dan kita harus dapat mengawalnya. Apa yang boleh kita lakukan dalam kaedah penyelesaian adalah untuk mengembalikan penutupan yang membungkus sasaran dan memanggilnya. Contohnya:

<span>var match = <span>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
</span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>
Menggunakan pendekatan itu, kita akan berpeluang memanggil fungsi dengan kebergantungan yang diperlukan. Dan pada masa yang sama kita tidak mengubah aliran kerja permohonan. Penyuntik masih sesuatu yang bebas dan tidak memegang fungsi berkaitan logik.

Sudah tentu, lulus fungsi Displayusers ke kaedah penyelesaian tidak membantu.

<span>var stringToDom = function(str) {
</span>  <span>var wrapMap = {
</span>    <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>    <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>    <span>area: [1, '<map>', '</map>'],
</span>    <span>param: [1, '<object>', '</object>'],
</span>    <span>thead: [1, '<table>', '</table>'],
</span>    <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>    <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>    <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>    <span>_default: [1, '<div>', '</div>']
</span>  <span>};
</span>  wrapMap<span>.optgroup = wrapMap.option;
</span>  wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>  wrapMap<span>.th = wrapMap.td;
</span>  <span>var element = document.createElement('div');
</span>  <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str);
</span>
  <span>if(match != null) {
</span>    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');
</span>    <span>var map = wrapMap[tag] || wrapMap._default, element;
</span>    str <span>= map[1] + str + map[2];
</span>    element<span>.innerHTML = str;
</span>    <span>// Descend through wrappers to the right content
</span>    <span>var j = map[0]+1;
</span>    <span>while(j--) {
</span>      element <span>= element.lastChild;
</span>    <span>}
</span>  <span>} else {
</span>    <span>// if only text is passed
</span>    element<span>.innerHTML = str;
</span>    element <span>= element.lastChild;
</span>  <span>}
</span>  <span>return element;
</span><span>}</span>
Kami masih mendapat ralat yang sama. Langkah seterusnya adalah untuk mengetahui keperluan sasaran yang diluluskan. Apakah kebergantungannya? Dan inilah bahagian rumit yang dapat kita pakai dari AngularJS. Saya, sekali lagi, menggali sedikit ke dalam kod rangka kerja dan mendapati ini:

<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) {
</span>  $http<span>.get('users/users.json').success(function(data) {
</span>    $scope<span>.users = data;
</span>  <span>});
</span><span>}</span>
Kami sengaja melangkau beberapa bahagian, kerana mereka lebih seperti butiran pelaksanaan. Itulah kod yang menarik untuk kami. Fungsi Annotate adalah seperti kaedah penyelesaian kami. Ia menukarkan fungsi sasaran yang diluluskan ke rentetan, menghilangkan komen (jika ada), dan mengekstrak argumen. Mari kita gunakan dan lihat hasilnya:

<span>var dataMockup = ['John', 'Steve', 'David'];
</span><span>var body = document.querySelector('body');
</span><span>var ajaxWrapper = {
</span>  <span>get: function(path<span>, cb</span>) {
</span>    <span>console.log(path + ' requested');
</span>    <span>cb(dataMockup);
</span>  <span>}
</span><span>}</span>
inilah output dalam konsol:

Jika kita mendapat elemen kedua array argdecl kita akan dapati nama -nama kebergantungan yang diperlukan. Itulah yang kita perlukan, kerana mempunyai nama -nama kita akan dapat menyampaikan sumber dari penyimpanan penyuntik. Berikut adalah versi yang berfungsi dan berjaya merangkumi matlamat kami:

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

Perhatikan bahawa kami menggunakan .split (/,?/g) untuk menukar rentetan domel, ajax ke array. Selepas itu kami menyemak jika kebergantungan didaftarkan dan jika ya kami lulus mereka ke fungsi sasaran. Kod di luar penyuntik kelihatan seperti itu:

<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

manfaat pelaksanaan sedemikian adalah bahawa kita boleh menyuntik elemen DOM dan pembalut Ajax dalam banyak fungsi. Kami juga boleh mengedarkan konfigurasi aplikasi kami seperti itu. Tidak perlu lulus objek dari kelas ke kelas. Ia hanya mendaftar dan menyelesaikan kaedah.

Sudah tentu penyuntik kami tidak sempurna. Masih terdapat beberapa ruang untuk penambahbaikan, seperti contoh sokongan definisi skop. Fungsi sasaran sekarang dipanggil dengan skop yang baru dibuat, tetapi biasanya kita akan mahu lulus sendiri. Kami harus menyokong juga menghantar hujah -hujah tersuai bersama -sama dengan kebergantungan.

Penyuntik menjadi lebih rumit jika kita mahu menyimpan kod kita selepas minifikasi. Seperti yang kita tahu minifiers menggantikan nama -nama fungsi, pembolehubah dan juga argumen kaedah. Dan kerana logik kita bergantung pada nama -nama ini kita perlu memikirkan penyelesaian. Satu penyelesaian yang mungkin sekali lagi datang dari AngularJS:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>

bukannya hanya displayusers kita lulus nama dependensi sebenar.

Contoh kami dalam tindakan:

Lihat pena bxdar oleh Krasimir Tsonev (@krasimir) pada codepen.

Mengadopsi Properties Computed Ember

Ember adalah salah satu rangka kerja yang paling popular pada masa kini. Ia mempunyai banyak ciri berguna. Terdapat satu yang sangat menarik - sifat yang dikira. Ringkasnya, sifat yang dikira adalah fungsi yang bertindak sebagai sifat. Mari kita lihat contoh mudah yang diambil dari dokumentasi Ember:

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>

Terdapat kelas yang mempunyai NameName dan LastName Properties. FullName harta yang dikira mengembalikan rentetan yang disatukan yang mengandungi nama penuh orang itu. Perkara yang pelik adalah bahagian di mana kita menggunakan kaedah .property terhadap fungsi yang digunakan untuk FullName. Saya secara peribadi tidak melihatnya di tempat lain. Dan, sekali lagi, melihat kod rangka kerja yang cepat mendedahkan sihir:

<span>var match = <span>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
</span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>

Perpustakaan tweak prototaip objek fungsi global dengan menambahkan harta baru. Ia adalah pendekatan yang bagus untuk menjalankan beberapa logik semasa definisi kelas.

Ember menggunakan getters dan setters untuk beroperasi dengan data objek. Itu memudahkan pelaksanaan sifat -sifat yang dikira kerana kita mempunyai satu lagi lapisan sebelum mencapai pembolehubah sebenar. Walau bagaimanapun, ia akan menjadi lebih menarik jika kita dapat menggunakan sifat yang dikira dengan objek JavaScript biasa. Seperti contohnya:

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

Nama digunakan sebagai harta biasa tetapi dalam amalan adalah fungsi yang mendapat atau menetapkan nama pertama dan lastname.

Terdapat ciri pembina JavaScript yang dapat membantu kita merealisasikan idea itu. Lihat coretan berikut:

<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

Kaedah Object.Defineproperty boleh menerima skop, nama harta, getter, dan setter. Apa yang perlu kita lakukan ialah menulis badan kedua -dua kaedah. Dan itu sahaja. Kami akan dapat menjalankan kod di atas dan kami akan mendapat hasil yang diharapkan:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>

Object.Defineproperty adalah apa yang kita perlukan, tetapi kita tidak mahu memaksa pemaju untuk menulisnya setiap kali. Kita mungkin perlu menyediakan polyfill, menjalankan logik tambahan, atau sesuatu seperti itu. Dalam kes yang ideal, kami ingin menyediakan antara muka yang serupa dengan Ember. Hanya satu fungsi adalah sebahagian daripada definisi kelas. Dalam bahagian ini, kami akan menulis fungsi utiliti yang dipanggil mengira yang akan memproses objek kami dan entah bagaimana akan menukar fungsi nama ke harta dengan nama yang sama.

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>

Kami mahu menggunakan kaedah nama sebagai setter, dan pada masa yang sama sebagai getter. Ini serupa dengan sifat -sifat yang dikira oleh Ember.

Sekarang mari kita tambahkan logik kita sendiri ke dalam prototaip objek fungsi:

<span>var match = <span>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
</span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>

Sebaik sahaja kita menambah baris di atas, kita akan dapat menambah. Komput () hingga akhir setiap definisi fungsi:

<span>var stringToDom = function(str) {
</span>  <span>var wrapMap = {
</span>    <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>    <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>    <span>area: [1, '<map>', '</map>'],
</span>    <span>param: [1, '<object>', '</object>'],
</span>    <span>thead: [1, '<table>', '</table>'],
</span>    <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>    <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>    <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>    <span>_default: [1, '<div>', '</div>']
</span>  <span>};
</span>  wrapMap<span>.optgroup = wrapMap.option;
</span>  wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>  wrapMap<span>.th = wrapMap.td;
</span>  <span>var element = document.createElement('div');
</span>  <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str);
</span>
  <span>if(match != null) {
</span>    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');
</span>    <span>var map = wrapMap[tag] || wrapMap._default, element;
</span>    str <span>= map[1] + str + map[2];
</span>    element<span>.innerHTML = str;
</span>    <span>// Descend through wrappers to the right content
</span>    <span>var j = map[0]+1;
</span>    <span>while(j--) {
</span>      element <span>= element.lastChild;
</span>    <span>}
</span>  <span>} else {
</span>    <span>// if only text is passed
</span>    element<span>.innerHTML = str;
</span>    element <span>= element.lastChild;
</span>  <span>}
</span>  <span>return element;
</span><span>}</span>

Akibatnya, harta nama tidak mengandungi fungsi lagi, tetapi objek yang telah mengira harta yang sama dengan harta yang benar dan func yang diisi dengan fungsi lama. Keajaiban sebenar berlaku dalam pelaksanaan pembantu mengira. Ia melalui semua sifat objek dan menggunakan objek.defineproperty di mana kita telah mengira sifat:

<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) {
</span>  $http<span>.get('users/users.json').success(function(data) {
</span>    $scope<span>.users = data;
</span>  <span>});
</span><span>}</span>

Perhatikan bahawa kami memadamkan nama harta asal. Dalam beberapa objek penyemak imbas.Defineproperty hanya berfungsi pada sifat yang belum ditakrifkan.

di sini adalah versi akhir objek pengguna yang menggunakan.

Fungsi yang mengembalikan nama penuh digunakan untuk menukar nama firstName dan lastName. Itulah idea di sebalik pemeriksaan hujah -hujah yang diluluskan dan memproses yang pertama. Sekiranya ada, kita memisahkannya dan menggunakan nilai -nilai kepada sifat -sifat biasa.
<span>var dataMockup = ['John', 'Steve', 'David'];
</span><span>var body = document.querySelector('body');
</span><span>var ajaxWrapper = {
</span>  <span>get: function(path<span>, cb</span>) {
</span>    <span>console.log(path + ' requested');
</span>    <span>cb(dataMockup);
</span>  <span>}
</span><span>}</span>

Kami sudah menyebut penggunaan yang dikehendaki, tetapi mari kita lihat sekali lagi:

codepen berikut menunjukkan kerja kami dalam amalan:
<span>var displayUsers = function(domEl<span>, ajax</span>) {
</span>  ajax<span>.get('/api/users', function(users) {
</span>    <span>var html = '';
</span>    <span>for(var i=0; i < users.length; i++) {
</span>      html <span>+= '<p>' + users[i] + '</p>';
</span>    <span>}
</span>    domEl<span>.innerHTML = html;
</span>  <span>});
</span><span>}</span>

Lihat pena ahpqo oleh Krasimir Tsonev (@Krasimir) di Codepen.

Templat React Crazy

Anda mungkin pernah mendengar tentang Rangka Kerja Facebook. Ia dibina di sekitar idea bahawa semuanya adalah komponen. Apa yang menarik ialah definisi komponen. Mari kita lihat contoh berikut:

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

Perkara pertama yang kita mulakan adalah bahawa ini adalah JavaScript, tetapi ia adalah yang tidak sah. Terdapat fungsi render, dan ia mungkin akan membuang kesilapan. Walau bagaimanapun, silap mata ialah kod ini dimasukkan ke dalam tag dengan atribut jenis tersuai. Pelayar tidak memprosesnya yang bermaksud bahawa kita selamat dari kesilapan. React mempunyai parser sendiri yang menerjemahkan kod yang ditulis oleh kami kepada JavaScript yang sah. Pemaju di Facebook memanggil XML seperti bahasa jsx . Pengubah JSX mereka adalah 390K dan mengandungi kira -kira 12000 baris kod. Jadi, ia agak kompleks. Dalam bahagian ini, kita akan mencipta sesuatu yang mudah, tetapi masih cukup kuat. Kelas JavaScript yang mengepam templat HTML dalam gaya React.

Pendekatan yang diambil Facebook adalah untuk mencampur kod JavaScript dengan markup HTML. Oleh itu, katakanlah bahawa kita mempunyai templat berikut:

<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

dan komponen yang menggunakannya:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>

Ideanya ialah kami menunjukkan ID templat dan menentukan data yang perlu digunakan. Sekeping pelaksanaan terakhir kami adalah enjin sebenar yang menggabungkan kedua -dua elemen tersebut. Mari kita panggil enjin dan mulakannya seperti itu:

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>

Kami mendapat kandungan tag

Sekarang, mari tulis fungsi parse kami. Tugas pertama kami adalah untuk membezakan HTML dari ekspresi. Dengan ungkapan, kami bermaksud rentetan yang diletakkan di antara . Kami akan menggunakan regex untuk mencari mereka dan gelung semasa yang mudah untuk melalui semua perlawanan:

<span>var match = <span>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
</span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>

Hasil dari kod di atas adalah seperti berikut:

<span>var stringToDom = function(str) {
</span>  <span>var wrapMap = {
</span>    <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>    <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>    <span>area: [1, '<map>', '</map>'],
</span>    <span>param: [1, '<object>', '</object>'],
</span>    <span>thead: [1, '<table>', '</table>'],
</span>    <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>    <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>    <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>    <span>_default: [1, '<div>', '</div>']
</span>  <span>};
</span>  wrapMap<span>.optgroup = wrapMap.option;
</span>  wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>  wrapMap<span>.th = wrapMap.td;
</span>  <span>var element = document.createElement('div');
</span>  <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str);
</span>
  <span>if(match != null) {
</span>    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');
</span>    <span>var map = wrapMap[tag] || wrapMap._default, element;
</span>    str <span>= map[1] + str + map[2];
</span>    element<span>.innerHTML = str;
</span>    <span>// Descend through wrappers to the right content
</span>    <span>var j = map[0]+1;
</span>    <span>while(j--) {
</span>      element <span>= element.lastChild;
</span>    <span>}
</span>  <span>} else {
</span>    <span>// if only text is passed
</span>    element<span>.innerHTML = str;
</span>    element <span>= element.lastChild;
</span>  <span>}
</span>  <span>return element;
</span><span>}</span>

Hanya ada satu ungkapan dan kandungannya adalah tajuk. Pendekatan intuitif pertama yang boleh kita ambil ialah menggunakan fungsi pengganti JavaScript dan menggantikan dengan data dari objek Comp yang diluluskan. Walau bagaimanapun, ini akan berfungsi hanya dengan sifat mudah. Bagaimana jika kita mempunyai objek bersarang atau bahkan jika kita mahu menggunakan fungsi. Seperti contohnya:

<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) {
</span>  $http<span>.get('users/users.json').success(function(data) {
</span>    $scope<span>.users = data;
</span>  <span>});
</span><span>}</span>

Daripada membuat parser kompleks dan hampir mencipta bahasa baru kita boleh menggunakan JavaScript tulen. Satu -satunya perkara yang perlu kita lakukan ialah menggunakan sintaks fungsi baru.

<span>var dataMockup = ['John', 'Steve', 'David'];
</span><span>var body = document.querySelector('body');
</span><span>var ajaxWrapper = {
</span>  <span>get: function(path<span>, cb</span>) {
</span>    <span>console.log(path + ' requested');
</span>    <span>cb(dataMockup);
</span>  <span>}
</span><span>}</span>

kita dapat membina badan fungsi yang kemudian dilaksanakan. Jadi, kita tahu kedudukan ekspresi kita dan apa yang sebenarnya berdiri di belakang mereka. Jika kita menggunakan array sementara dan kursor kita sementara kitaran akan kelihatan seperti itu:

<span>var text = $('<div>Simple text</div>');
</span>
<span>$('body').append(text);</span>

output dalam konsol menunjukkan bahawa kita berada di landasan yang betul:

<span>var stringToDom = function(str) {
</span>  <span>var temp = document.createElement('div');
</span>
  temp<span>.innerHTML = str;
</span>  <span>return temp.childNodes[0];
</span><span>}
</span><span>var text = stringToDom('<div>Simple text</div>');
</span>
<span>document.querySelector('body').appendChild(text);</span>

Arahan kod harus diubah menjadi rentetan yang akan menjadi badan fungsi. Contohnya:

<span>var tableRow = $('<tr><td>Simple text</td></tr>');
</span><span>$('body').append(tableRow);
</span>
<span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>');
</span><span>document.querySelector('body').appendChild(tableRow);</span>
Ia agak mudah untuk mencapai hasil ini. Kami boleh menulis gelung yang melalui semua elemen array kod dan cek jika item itu adalah rentetan atau objek. Walau bagaimanapun, ini sekali lagi merangkumi sebahagian daripada kes. Bagaimana jika kita mempunyai templat berikut:

<span>var wrapMap = {
</span>  <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>  <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>  <span>area: [1, '<map>', '</map>'],
</span>  <span>param: [1, '<object>', '</object>'],
</span>  <span>thead: [1, '<table>', '</table>'],
</span>  <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>  <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>  <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>  <span>_default: [1, '<div>', '</div>']
</span><span>};
</span>wrapMap<span>.optgroup = wrapMap.option;
</span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>wrapMap<span>.th = wrapMap.td;</span>
kita tidak boleh menggabungkan ungkapan dan mengharapkan warna yang disenaraikan. Oleh itu, bukannya memasuki rentetan untuk rentetan, kami akan mengumpulnya dalam array. Berikut adalah versi terkini fungsi parse:

<span>var match = <span>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
</span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>
Setelah array kod diisi, kami mula membina badan fungsi. Setiap baris templat akan disimpan dalam r. Jika garis adalah rentetan, kami membersihkannya sedikit dengan melepaskan petikan dan mengeluarkan baris dan tab baru. Ia ditambah kepada array melalui kaedah push. Jika kita mempunyai coretan kod maka kita periksa sama ada ia bukan pengendali JavaScript yang sah. Jika ya maka kita tidak menambahkannya ke array tetapi hanya menjatuhkannya sebagai garis baru. Konsol.log pada output akhir:

<span>var stringToDom = function(str) {
</span>  <span>var wrapMap = {
</span>    <span>option: [1, '<select multiple="multiple">', '</select>'],
</span>    <span>legend: [1, '<fieldset>', '</fieldset>'],
</span>    <span>area: [1, '<map>', '</map>'],
</span>    <span>param: [1, '<object>', '</object>'],
</span>    <span>thead: [1, '<table>', '</table>'],
</span>    <span>tr: [2, '<table><tbody>', '</tbody></table>'],
</span>    <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
</span>    <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'],
</span>    <span>_default: [1, '<div>', '</div>']
</span>  <span>};
</span>  wrapMap<span>.optgroup = wrapMap.option;
</span>  wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
</span>  wrapMap<span>.th = wrapMap.td;
</span>  <span>var element = document.createElement('div');
</span>  <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str);
</span>
  <span>if(match != null) {
</span>    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');
</span>    <span>var map = wrapMap[tag] || wrapMap._default, element;
</span>    str <span>= map[1] + str + map[2];
</span>    element<span>.innerHTML = str;
</span>    <span>// Descend through wrappers to the right content
</span>    <span>var j = map[0]+1;
</span>    <span>while(j--) {
</span>      element <span>= element.lastChild;
</span>    <span>}
</span>  <span>} else {
</span>    <span>// if only text is passed
</span>    element<span>.innerHTML = str;
</span>    element <span>= element.lastChild;
</span>  <span>}
</span>  <span>return element;
</span><span>}</span>
Bagus, bukan? JavaScript yang berfungsi dengan betul, yang dilaksanakan dalam konteks komponen kami akan menghasilkan markup HTML yang dikehendaki.

perkara terakhir yang tersisa adalah berjalan sebenar fungsi kami yang hampir dibuat:

<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) {
</span>  $http<span>.get('users/users.json').success(function(data) {
</span>    $scope<span>.users = data;
</span>  <span>});
</span><span>}</span>
Kami membungkus kod kami dengan pernyataan untuk menjalankannya dalam konteks komponen. Tanpa itu kita perlu menggunakan ini.Title dan this.colors dan bukannya tajuk dan warna.

Berikut adalah codepen yang menunjukkan hasil akhir:

Lihat pena gahej oleh Krasimir Tsonev (@krasimir) pada codepen.

Ringkasan

Di sebalik kerangka besar dan perpustakaan adalah pemaju pintar. Mereka mendapati dan menggunakan penyelesaian rumit yang tidak remeh, dan bahkan agak ajaib. Dalam artikel ini, kami mendedahkan beberapa sihir itu. Adalah baik bahawa di dunia JavaScript kita dapat belajar dari yang terbaik dan menggunakan kod mereka.

kod dari artikel ini tersedia untuk dimuat turun dari GitHub

Soalan Lazim (Soalan Lazim) Mengenai Keajaiban JavaScript

Apakah kaedah sihir dalam JavaScript dan bagaimana mereka berfungsi? Mereka tidak dipanggil secara langsung tetapi dipanggil apabila tindakan tertentu dilakukan. Sebagai contoh, kaedah ToString () adalah kaedah sihir yang secara automatik dipanggil apabila objek perlu diwakili sebagai nilai teks. Contoh lain ialah kaedah ValueOf (), yang dipanggil apabila objek diwakili sebagai nilai primitif.

Bagaimana saya boleh menggunakan kaedah sihir dalam javascript?

Kaedah sihir dalam JavaScript boleh digunakan dengan menentukannya dalam objek atau kelas anda. Sebagai contoh, anda boleh menentukan kaedah ToString () dalam objek anda untuk menyesuaikan bagaimana objek anda akan diwakili sebagai rentetan. Berikut adalah contoh mudah:

biarkan person = {
firstName: "John",
lastName: "doe",
toString: function () {
kembali ini.firstname " "this.lastName;
}
};
console.log (person.toString ()); // "John Doe"

Apakah kepentingan fungsi sihir dalam JavaScript? Mereka boleh menjadikan kod anda lebih intuitif dan lebih mudah difahami, serta menyediakan cara untuk merangkum dan melindungi data anda. Berikut adalah beberapa contoh fungsi sihir dalam JavaScript:

1. toString (): Kaedah ini mengembalikan rentetan yang mewakili objek. valueof (): Kaedah ini mengembalikan nilai primitif objek. HasownProperty (): Kaedah ini mengembalikan boolean yang menunjukkan sama ada objek mempunyai harta yang ditentukan. Kaedah sihir boleh menjadi sangat berguna, mereka juga mempunyai beberapa batasan. Untuk satu, mereka boleh membuat kod anda lebih kompleks dan lebih sukar untuk debug, terutamanya jika anda tidak biasa dengan cara mereka bekerja. Mereka juga boleh membawa kepada tingkah laku yang tidak dijangka jika tidak digunakan dengan betul.

Bagaimanakah JavaScript mengendalikan kaedah sihir berbanding dengan bahasa pengaturcaraan lain? "Kaedah Magic". Walau bagaimanapun, ia mempunyai kaedah tertentu yang berkelakuan sama, seperti ToString () dan ValueOf (). Kaedah ini secara automatik dipanggil dalam situasi tertentu, seperti kaedah sihir dalam bahasa lain. Sertakan pemahaman bila dan mengapa menggunakannya, menggunakannya dengan berhati -hati untuk mengelakkan kerumitan, dan sentiasa menguji kod anda dengan teliti untuk memastikan ia berkelakuan seperti yang diharapkan.

Bolehkah kaedah sihir digunakan dengan kerangka JavaScript seperti React atau Vue? Walau bagaimanapun, cara mereka digunakan mungkin berbeza -beza bergantung kepada rangka kerja. Selalu terbaik untuk merujuk kepada dokumentasi rangka kerja khusus untuk panduan.

Bagaimana saya boleh mengetahui lebih lanjut mengenai kaedah sihir dalam JavaScript? Anda boleh bermula dengan dokumentasi JavaScript rasmi, serta tutorial dan kursus dalam talian. Anda juga boleh mengamalkan menggunakannya dalam projek anda sendiri untuk mendapatkan pengalaman tangan. Alat yang boleh membantu menggunakan kaedah sihir dalam JavaScript. Sebagai contoh, Lodash adalah perpustakaan utiliti JavaScript yang popular yang menyediakan kaedah yang berguna untuk bekerja dengan array, objek, dan jenis data lain.

Atas ialah kandungan terperinci Mendedahkan keajaiban javascript. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel sebelumnya:Membuat Switcher Gaya MudahArtikel seterusnya:Membuat Switcher Gaya Mudah