Cakupan dan pengangkatan fungsi Javascript

90

Saya baru saja membaca artikel bagus tentang Scoping and Hoisting JavaScript oleh Ben Cherry di mana dia memberikan contoh berikut:

var a = 1;

function b() {
    a = 10;
    return;

    function a() {}
}
b();
alert(a);

Menggunakan kode di atas, browser akan memberi tanda "1".

Saya masih tidak yakin mengapa ini mengembalikan "1". Beberapa hal yang dia katakan muncul di benaknya seperti: Semua deklarasi fungsi diangkat ke atas. Anda dapat mengatur variabel menggunakan fungsi. Masih tidak cocok untuk saya.

dev.e.loper
sumber

Jawaban:

120

Pengangkatan fungsi berarti bahwa fungsi dipindahkan ke atas ruang lingkupnya. Itu adalah,

function b() {  
   a = 10;  
   return;  
   function a() {} 
} 

akan ditulis ulang oleh interpeter untuk ini

function b() {
  function a() {}
  a = 10;
  return;
}

Aneh, ya?

Juga, dalam hal ini,

function a() {}

berperilaku sama seperti

var a = function () {};

Jadi, pada dasarnya, inilah yang dilakukan kode tersebut:

var a = 1;                 //defines "a" in global scope
function b() {  
   var a = function () {}; //defines "a" in local scope 
   a = 10;                 //overwrites local variable "a"
   return;      
}       
b();       
alert(a);                 //alerts global variable "a"
Peter Olson
sumber
2
Jadi semua deklarasi fungsi akhirnya ditugaskan ke variabel?
dev.e.loper
15
@ dev.e.loper Ya, dalam Javascript, fungsi adalah objek kelas satu, seperti string dan angka. Itu berarti mereka didefinisikan sebagai variabel dan dapat diteruskan ke fungsi lain, disimpan dalam array, dan seterusnya.
Peter Olson
4
Fungsi body sama sekali tidak "ditulis ulang". Berbagai standar ECMAScript dengan jelas menyatakan bahwa deklarasi variabel dan fungsi diproses sebelum eksekusi kode dimulai. Artinya, tidak ada yang dipindahkan , ini tentang urutan eksekusi (karena itu saya tidak suka istilah "mengangkat", yang menyimpulkan gerakan atau penataan ulang). Dalam kode yang ditulis ulang Anda, deklarasi var aharus sebelum deklarasi fungsi, dan tugas a = 1harus setelah. Tetapi perhatikan bahwa ini tidak ditentukan untuk benar-benar terjadi oleh parser, tokeniser, interpreter, compiler, apa pun, itu hanya setara.
RobG
3
@RobG Tentu, saya kira Anda bisa menyebut deskripsi kecil "bohong kepada anak-anak" , tetapi pada akhirnya perilakunya sama, apakah kode secara harfiah diatur ulang atau hanya urutan eksekusi yang diatur ulang. Apa yang sebenarnya terjadi di balik layar lebih merupakan masalah akademis, dan bahkan mungkin bergantung pada implementasi.
Peter Olson
7
“Juga, dalam hal ini, function a() {}berperilaku sama seperti var a = function () {};  - ini salah dalam dua cara: pertama, jika ada, akan var a = function a() {};(fungsinya sebenarnya bukan anonim), kedua, kedua bentuk itu tidak dapat dipertukarkan, karena dari var a = function a() {};hanya var a;sebagian yang akan diangkat. Bagian itu a = function a() {};akan tetap berada di balik pernyataan pengembalian. Karena bentuk aslinya adalah deklarasi fungsi dan bukan ekspresi fungsi, ia sebenarnya diangkat secara keseluruhan.
user4642212
6

Apa yang harus Anda ingat adalah bahwa ia mem-parsing seluruh fungsi dan menyelesaikan semua deklarasi variabel sebelum menjalankannya. Begitu....

function a() {} 

benar-benar menjadi

var a = function () {}

var a memaksanya ke dalam lingkup lokal, dan lingkup variabel melalui seluruh fungsi, sehingga variabel global tetap 1 karena Anda telah mendeklarasikan a ke dalam lingkup lokal dengan menjadikannya sebagai fungsi.

kemiller2002
sumber
5

Fungsi adiangkat di dalam fungsi b:

var a = 1; 
function b() { 
   function a() {} 
   a = 10; 
   return;
} 
b(); 
alert(a);

yang hampir seperti menggunakan var:

var a = 1; 
function b() { 
   var a = function () {};
   a = 10; 
   return;
} 
b(); 
alert(a);

Fungsi ini dideklarasikan secara lokal, dan pengaturan ahanya terjadi di lingkup lokal, bukan var global.

Pesawat Digital
sumber
1
baris ini "var a = function () {};" memperjelas semuanya .. pada dasarnya JavaScript adalah bahasa dinamis dan "function" juga merupakan objek dalam JavaScript.
refactor
3
  1. deklarasi fungsi function a(){}diangkat pertama dan berperilaku seperti var a = function () {};, maka dalam lingkup lokal adibuat.
  2. Jika Anda memiliki dua variabel dengan nama yang sama (satu di global dan di lokal), variabel lokal selalu diutamakan daripada variabel global.
  3. Saat Anda menyetel a=10, Anda menyetel variabel lokal a, bukan variabel global.

Oleh karena itu, nilai variabel global tetap sama dan Anda mendapatkan peringatan 1

Jhankar Mahbub
sumber
1

function a() { }adalah pernyataan fungsi, yang membuat avariabel lokal ke bfungsi.
Variabel dibuat ketika suatu fungsi diurai, terlepas dari apakah varpernyataan fungsi atau dijalankan.

a = 10 set variabel lokal ini.

SLaks
sumber
sebenarnya a = 10menyetel variabel dalam cakupan global ketika fungsi bdijalankan kecuali Anda menambahkan "use strict"(dalam lingkungan seperti mendukung direktif itu).
Sean Vieira
@ Sean: Tidak, karena pernyataan fungsi membuat pengenal lokal.
SLaks
... dan .... Anda benar. Tidak menyadari konsekuensi khusus dari fungsi mengangkat. Terima kasih!
Sean Vieira
1

Apa inti perdebatan dalam cuplikan kecil kode ini?

Kasus 1:

Cantumkan function a(){}definisi di dalam body function bsebagai berikut.logs value of a = 1

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Kasus 2

Kecualikan function a(){}definisi di dalam tubuh function bsebagai berikut.logs value of a = 10

var a = 1;
function b() {
  a = 10;  // overwrites the value of global 'var a'
  return;
}
b();
console.log(a); // logs a = 10

Pengamatan akan membantu Anda menyadari bahwa pernyataan console.log(a)mencatat nilai-nilai berikut.

Kasus 1: a = 1

Kasus 2: a = 10

Posisi

  1. var a telah didefinisikan dan dideklarasikan secara leksikal dalam lingkup global.
  2. a=10 Pernyataan ini menetapkan kembali nilai menjadi 10, secara leksikal berada di dalam fungsi b.

Penjelasan dari kedua kasus tersebut

Karena function definition with name propertya sama dengan variable a. Bagian variable adalam function body bmenjadi variabel lokal. Baris sebelumnya menyiratkan bahwa nilai global a tetap utuh dan nilai lokal a diperbarui menjadi 10.

Jadi, yang ingin kami katakan adalah kode di bawah ini

var a = 1;
function b() {
  a = 10;
  return;

  function a() {}
}
b();
console.log(a); // logs a = 1

Ini diinterpretasikan oleh interpreter JS sebagai berikut.

var a = 1;
function b() {
  function a() {}
  a = 10;
  return;


}
b();
console.log(a); // logs a = 1

Namun, ketika kita menghapus function a(){} definition, yang value of 'a'dideklarasikan dan didefinisikan di luar fungsi b, nilai itu ditimpa dan berubah menjadi 10 dalam kasus 2. Nilai ditimpa karena a=10mengacu pada deklarasi global dan jika itu akan dideklarasikan secara lokal kita harus memiliki tertulis var a = 10;.

var a = 1;
function b() {
  var a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;
}
b();
console.log(a); // logs a = 1

Kami dapat mengklarifikasi keraguan kami lebih lanjut dengan mengubah name propertydalam function a(){} definitionke nama lain selain'a'

var a = 1;
function b() {
  a = 10; // here var a is declared and defined locally because it uses a var keyword. 
  return;

  function foo() {}
}
b();
console.log(a); // logs a = 1
Sagar Munjal
sumber
1

Hoisting adalah konsep yang dibuat agar lebih mudah dipahami. Apa yang sebenarnya terjadi adalah deklarasi dilakukan pertama kali sehubungan dengan cakupannya dan penugasan akan dilakukan setelah itu (tidak pada waktu yang sama).

Ketika deklarasi terjadi, var amaka function bdan di dalam bcakupan itu, function adideklarasikan.

Fungsi a ini akan membayangi variabel a yang berasal dari lingkup global.

Setelah deklarasi selesai, nilai yang ditetapkan akan dimulai, global aakan mendapatkan nilai 1dan a insidefunction b akan mendapatkan 10. ketika Anda melakukannya alert(a), itu akan memanggil variabel cakupan global yang sebenarnya. Perubahan kecil pada kode ini akan membuatnya lebih jelas

        var a = 1;

    function b() {
        a = 10;
        return a;

        function a() { }
    }

    alert(b());
    alert(a);
Buzzzzzzz
sumber
1
Sangat mengherankan bahwa begitu banyak ahli bahkan dalam sebuah kursus di codeschool.com mengacu pada pengangkatan yang tidak lebih dari pandangan sederhana tentang apa yang terjadi, sebenarnya pengangkatan tidak terjadi sama sekali. Ref: 1) developer.mozilla.org/en-US/docs/Glossary/Hoisting 2) Bab 5 Rahasia JavaScript Ninja 2 / e oleh john resig, bear bebeault, josip maras
adnan2
1

Anehnya, tidak ada jawaban di sini yang menyebutkan relevansi Konteks Eksekusi dalam Rantai Lingkup.

Mesin JavaScript membungkus kode yang saat ini dijalankan dalam Konteks Eksekusi. Konteks eksekusi dasar adalah Konteks Eksekusi global. Setiap kali fungsi baru dipanggil, Konteks Eksekusi baru dibuat dan diletakkan di Stack Eksekusi. Bayangkan Stack Frame yang ada di Invocation Stack dalam bahasa pemrograman lain. Terakhir masuk pertama keluar. Sekarang setiap Konteks Eksekusi memiliki Variabel Lingkungan dan Lingkungan Luar di JavaScript.

Saya akan menggunakan contoh di bawah ini sebagai demonstrasi.

1) Pertama, kita memasuki Fase Pembuatan Konteks Eksekusi global. Baik Lingkungan Luar dan Lingkungan Variabel dari Lingkungan Leksikal dibuat. Objek Global diatur dan ditempatkan di memori dengan variabel khusus 'ini' yang menunjuk padanya. Fungsi a dan kodenya serta variabel myVar dengan nilai yang tidak ditentukan ditempatkan di memori di Lingkungan Variabel global. penting untuk dicatat bahwa kode fungsi a tidak dijalankan. Itu hanya ditempatkan di memori dengan fungsi a.

2) Kedua, ini adalah Fase Eksekusi dari Konteks Eksekusi. myVar bukan lagi nilai yang tidak ditentukan. Ini diinisialisasi dengan nilai 1, yang disimpan di Lingkungan Variabel global. Fungsi a dipanggil dan Konteks Eksekusi baru dibuat.

3) Dalam Konteks Eksekusi fungsi a, ia melewati Fase Pembuatan dan Eksekusi dari Konteks Eksekusi sendiri. Ia memiliki Lingkungan Luar dan Lingkungan Variabel sendiri, dengan demikian, Lingkungan Leksikal sendiri. Fungsi b dan variabel myVar disimpan di Variable Environment-nya. Lingkungan Variabel ini berbeda dari Lingkungan Variabel global. Karena fungsi a berada secara leksikal (secara fisik dalam kode) pada tingkat yang sama dengan Konteks Eksekusi global, Lingkungan Luarnya adalah Konteks Eksekusi global. Jadi, jika fungsi a merujuk ke variabel yang tidak ada di Lingkungan Variabelnya, ia akan mencari Rantai Lingkup dan mencoba menemukan variabel dalam Lingkungan Variabel dalam Konteks Eksekusi global.

4) Fungsi b dipanggil dalam fungsi a. Konteks Eksekusi baru dibuat. Karena ia duduk secara leksikal dalam fungsi a, Lingkungan Luarnya adalah a. Jadi ketika itu mereferensikan myVar, karena myVar tidak berada dalam Lingkungan Variabel fungsi b, itu akan melihat Lingkungan Variabel fungsi a. Ia menemukannya di sana dan console.log mencetak 2. Tetapi jika variabel tidak berada dalam lingkungan Variabel fungsi a, maka karena Lingkungan Luar fungsi a adalah Konteks Eksekusi global, maka Rantai Lingkup akan terus mencari di sana.

5) Setelah fungsi b dan a selesai dieksekusi, mereka akan muncul dari Stack Eksekusi. Mesin JavaScript single-threaded melanjutkan eksekusi pada Konteks Eksekusi global. Ini memanggil fungsi b. Tetapi tidak ada fungsi b di Lingkungan Variabel global dan tidak ada Lingkungan Luar lainnya yang perlu dicari di Konteks Eksekusi global. Jadi pengecualian dimunculkan oleh JavaScript Engine.

function a(){
  function b(){
    console.log(myVar);
  }

  var myVar = 2;
  b();
}

var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined

Contoh di bawah ini menunjukkan Scope Chain dalam tindakan. Dalam Lingkungan Variabel Konteks Eksekusi fungsi b, tidak ada myVar. Jadi mencari Lingkungan Luarnya, yang fungsinya a. Fungsi a juga tidak memiliki myVar di Variable Environment-nya. Jadi Mesin mencari fungsi Lingkungan Luar, yang merupakan Lingkungan Luar Konteks Eksekusi global dan myVar didefinisikan di sana. Karenanya, console.log mencetak 1.

function a(){
  function b(){
    console.log(myVar);
  }

  b();
}

var myVar = 1;
a();
> 1

Mengenai Konteks Eksekusi dan Lingkungan Leksikal yang terkait dengannya, termasuk Lingkungan Luar dan Lingkungan Variabel, mengaktifkan cakupan variabel di JavaScript. Meskipun Anda memanggil fungsi yang sama beberapa kali, untuk setiap pemanggilan, itu akan membuat Konteks Eksekusi sendiri. Jadi setiap Konteks Eksekusi akan memiliki salinan variabelnya sendiri di Variable Environment-nya. Tidak ada pembagian variabel.

Donato
sumber
0

Hal ini terjadi karena nama Variabelnya sama dengan nama fungsi yang berarti “a”. Jadi karena Javascript mengangkatnya mencoba untuk menyelesaikan konflik penamaan dan itu akan mengembalikan a = 1.

Saya juga bingung tentang ini sampai saya membaca posting ini di "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html

Semoga membantu.

AugustRush
sumber
0

Berikut rekap jawaban saya dengan lebih banyak anotasi dan biola pendamping untuk dimainkan.

// hoisting_example.js

// top of scope ie. global var a = 1
var a = 1;

// new scope due to js' functional (not block) level scope
function b() {
    a = 10; // if the function 'a' didn't exist in this scope, global a = 10
  return; // the return illustrates that function 'a' is hoisted to top
  function a(){}; // 'a' will be hoisted to top as var a = function(){};
}

// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b' 
// and in doing so, created a new named variable 'a' 
// which is a function within b's scope
b();

// a will alert 1, see comment above
alert(a);

https://jsfiddle.net/adjavaherian/fffpxjx7/

4m1r
sumber
0

scpope & closure & hoisting (var / function)

  1. scpope: var global dapat diakses di mana saja (seluruh cakupan file), var lokal hanya dapat diakses oleh lingkup lokal (lingkup fungsi / blok)!
    Catatan: jika variabel lokal tidak menggunakan kata kunci var dalam suatu fungsi, itu akan menjadi variabel global!
  2. closure: sebuah fungsi di dalam fungsi lainnya, yang dapat mengakses cakupan lokal (fungsi induk) & cakupan global, meskipun varsnya tidak dapat diakses oleh orang lain! kecuali, Anda mengembalikannya sebagai nilai pengembalian!
  3. hoisting: pindahkan semua deklarasikan / undeclare vars / function ke atas scope, kemudian berikan nilai atau null!
    Catatan: ini hanya memindahkan deklarasi, bukan memindahkan nilainya!

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

xgqfrms.dll
sumber
0

Mengangkat Dalam JavaScript berarti, deklarasi variabel dieksekusi di seluruh program sebelum kode apa pun dijalankan. Oleh karena itu, mendeklarasikan variabel di mana saja dalam kode sama dengan mendeklarasikannya di awal.

Vishwas SL
sumber
0

Itu semua tergantung pada ruang lingkup variabel 'a'. Izinkan saya menjelaskan dengan membuat cakupan sebagai gambar.

Di sini JavaScript akan membuat 3 cakupan.

i) Ruang lingkup global. ii) Fungsi b () ruang lingkup. iii) Fungsi a () ruang lingkup.

masukkan deskripsi gambar di sini

Jelas ketika Anda memanggil cakupan metode 'alert' milik Global saat itu, sehingga akan mengambil nilai variabel 'a' dari Cakupan global saja yaitu 1.

Sumit Pahuja
sumber
0

Posting Panjang!

Tapi itu akan membersihkan udara!

Cara kerja Java Script adalah melibatkan proses dua langkah:

  1. Kompilasi (boleh dikatakan begitu) - Langkah ini mendaftarkan variabel dan deklarasi fungsi serta cakupannya masing-masing. Ini tidak melibatkan evaluasi ekspresi fungsi: var a = function(){}atau ekspresi variabel (seperti menugaskan 3ke xdalam kasus var x =3;yang tidak lain adalah evaluasi bagian RHS.)

  2. Penerjemah: Ini adalah bagian pelaksanaan / evaluasi.

Periksa output dari kode di bawah ini untuk mendapatkan pemahaman:

//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);

function b() {
  //cannot write the below line:
  //console.log(e); 
  //since e is not declared.
  e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
  console.log("e is " + e) //  works!
  console.log("f is " + f);
  var f = 7;
  console.log("Now f is " + f);
  console.log("d is " + d);
  return;

  function d() {}
}
b();
console.log(a);

Mari kita hancurkan:

  1. Dalam fase kompilasi, 'a' akan didaftarkan dalam lingkup global dengan nilai ' undefined'. Hal yang sama berlaku untuk ' c', nilainya saat ini adalah ' undefined' dan bukan ' function()'. ' b' akan didaftarkan sebagai fungsi dalam lingkup global. Di dalam b's scope', ' f' akan didaftarkan sebagai variabel yang tidak akan ditentukan saat ini dan fungsi ' d' akan didaftarkan.

  2. Ketika interpreter berjalan, variabel yang dideklarasikan dan function()(dan bukan ekspresi) dapat diakses sebelum interpreter mencapai garis ekspresi yang sebenarnya. Jadi, variabel akan dicetak ' undefined' dan fungsi anonim yang dideklarasikan dapat dipanggil lebih awal. Namun, mencoba mengakses variabel yang tidak dideklarasikan sebelum inisialisasi ekspresinya akan menghasilkan kesalahan seperti:

console.log(e)
e = 3;

Sekarang, apa yang terjadi jika Anda memiliki deklarasi variabel dan fungsi dengan nama yang sama.

Jawabannya adalah - fungsi selalu diangkat sebelumnya dan jika variabel nama yang sama dideklarasikan, itu diperlakukan sebagai duplikat dan diabaikan. Ingat, ketertiban tidak masalah. Fungsi selalu diutamakan. Tetapi selama fase evaluasi Anda dapat mengubah referensi variabel ke apa pun (Ini menyimpan apa pun yang merupakan tugas terakhir). Lihat kode di bawah ini:

var a = 1;
console.log("a is " + a);

function b() {
  console.log("a inside the function b is " + a); //interpreter finds                                'a' as function() in current scope. No need to go outside the scope to find 'a'.
  a = 3; //a changed
  console.log("Now a is " + a);
  return;

  function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.

pragun
sumber
0

Mengangkat adalah konsep perilaku JavaScript. Hoisting (katakanlah pindah) adalah konsep yang menjelaskan bagaimana dan dimana variabel harus dideklarasikan.

Dalam JavaScript, variabel dapat dideklarasikan setelah digunakan karena deklarasi Fungsi dan deklarasi variabel selalu dipindahkan ("diangkat") secara tidak terlihat ke bagian atas cakupannya oleh interpreter JavaScript.

Kami menemukan dua jenis pengangkatan dalam banyak kasus.

1. Deklarasi variabel mengangkat

Mari kita pahami ini dengan potongan kode ini.

 a = 5; // Assign 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
 var a; // Declare a
  //output-> 5

Di sini deklarasi variabel a akan dihosting ke atas tanpa terlihat oleh penerjemah javascript pada saat kompilasi. Jadi kami bisa mendapatkan nilai a. Tetapi pendekatan deklarasi variabel ini tidak direkomendasikan karena kita harus mendeklarasikan variabel ke atas seperti ini.

 var a = 5; // Assign and declare 5 to a
 elem = document.getElementById("demo"); // Find an element 
 elem.innerHTML = a;                     // Display a in the element
  // output -> 5

pertimbangkan contoh lain.

  function foo() {
     console.log(x)
     var x = 1;
 }

sebenarnya ditafsirkan seperti ini:

  function foo() {
     var x;
     console.log(x)
     x = 1;
  }

Dalam kasus ini x tidak akan ditentukan

Tidak masalah jika kode telah dieksekusi yang berisi deklarasi variabel. Pertimbangkan contoh ini.

  function foo() {
     if (false) {
         var a = 1;
     }
     return;
     var b = 1;
  }

Fungsi ini ternyata seperti ini.

  function foo() {
      var a, b;
      if (false) {
        a = 1;
     }
     return;
     b = 1;
  }

Dalam deklarasi variabel hanya kerekan definisi variabel, bukan penugasan.

  1. Deklarasi fungsi mengangkat

Berbeda dengan variabel yang mengangkat tubuh fungsi atau nilai yang ditetapkan juga akan diangkat. Pertimbangkan kode ini

 function demo() {
     foo(); // this will give error because it is variable hoisting
     bar(); // "this will run!" as it is function hoisting
     var foo = function () {
         alert("this would not run!!");
     }
     function bar() { 
         alert("this will run!!");
     }
 }
 demo();

Sekarang setelah kita memahami variabel dan fungsi mengangkat, mari kita pahami kode ini sekarang.

var a = 1;
function b() {
  a = 10;
  return;
   function a() {}
}
b();
alert(a);

Kode ini akan berubah menjadi seperti ini.

var a = 1;                 //defines "a" in global scope
 function b() {  
   var a = function () {}; //defines "a" in local scope 
    a = 10;                 //overwrites local variable "a"
    return;      
 }       
 b();       
 alert(a); 

Fungsi a () akan memiliki cakupan lokal di dalam b (). a () akan dipindahkan ke atas saat menafsirkan kode dengan definisinya (hanya dalam kasus pengangkatan fungsi) sehingga sekarang akan memiliki cakupan lokal dan oleh karena itu tidak akan mempengaruhi ruang lingkup global sementara memiliki ruang lingkup sendiri di dalam fungsi b () .

Mustkeem K
sumber
0

Dari pengetahuan saya, pengangkatan terjadi dengan deklarasi variabel dan deklarasi fungsi, misalnya:

a = 7;
var a;
console.log(a) 

Apa yang terjadi di dalam mesin JavaScript:

var a;
a = 7;
console.log(a);
// 7

Atau:

console.log(square(7)); // Output: 49
function square(n) { return n * n; }

Itu akan menjadi:

function square(n) { return n * n; }
console.log(square(7)); // 49

Tetapi tugas seperti penetapan variabel, penetapan ekspresi fungsi tidak akan diangkat: Misalnya:

console.log(x);
var x = 7; // undefined

Mungkin menjadi seperti ini:

var x;
console.log(x); // undefined
x = 7;
Nam V. Do
sumber
0

Untuk menggambarkan hosting dalam javascript dalam satu kalimat adalah variabel dan fungsi diangkat ke atas ruang lingkup yang dideklarasikan.

masukkan deskripsi gambar di sini

Saya berasumsi Anda adalah seorang pemula, untuk memahami hoisting dengan benar pada awalnya kita telah memahami perbedaan antara undefined dan ReferenceError

 var v;
 console.log(v);
 console.log(abc);
/*
The output of the above codes are:
undefined
ReferenceError: abc is not defined*/

sekarang di kode di bawah apa yang kita lihat? variabel dan ekspresi fungsi adalah decleard.

<script>
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
</script>

tetapi gambaran nyata dengan bukti bahwa variabel dan fungsi diangkat di atas ruang lingkup:

console.log(totalAmo);
console.log(getSum(8,9));
var totalAmo = 8;
var getSum = function(a, b){
      return a+b;
}
console.log(totalAmo);
console.log(getSum(9,7));

Output dari dua log pertama tidak ditentukan dan TypeError: getSum bukanlah fungsi karena var totalAmo dan getSum dipasang di bagian atas cakupannya seperti di bawah

 <script>
        var totalAmo;
        var getSum;

        console.log(totalAmo);
        console.log(getSum(8,9));
        var totalAmo = 8;
        var getSum = function(a, b){
            return a+b;
        }
        console.log(totalAmo);
        console.log(getSum(9,7));
    </script>

Tetapi untuk deklarasi fungsi, seluruh fungsi dikibarkan di atas ruang lingkupnya.

console.log(getId());
function getId(){
   return 739373;
}
/* output: 739373, because the whole function hoisted on the top of the scope.*/

Sekarang logika yang sama berlaku untuk variabel tersebut, eksperimen fungsi, dan deklarasi fungsi yang dideklarasikan di dalam cakupan fungsional. Poin utama: mereka tidak akan diangkat di atas file ;

function functionScope(){
            var totalAmo;
            var getSum;

            console.log(totalAmo);
            console.log(getSum(8,9));
            var totalAmo = 8;
            var getSum = function(a, b){
                return a+b;
            }
        }

Jadi, ketika Anda menggunakan kata kunci var , variabel dan fungsi diangkat di atas ruang lingkup (lingkup global dan lingkup fungsi). Bagaimana dengan let dan const , const dan let masih sama-sama mengetahui cakupan global dan cakupan fungsi seperti var, tetapi variabel const dan let juga mengetahui cakupan lain yang disebut cakupan diblokir. cakupan blok hadir setiap kali ada blok kode, seperti for loop, if else statement, while loop dll.

Ketika kita menggunakan const dan membiarkan untuk mendeklarasikan variabel dalam lingkup blok ini, deklarasi variabel hanya akan diangkat di atas blok itu, dan tidak akan diangkat di atas fungsi induk atau di atas cakupan global yang diangkat.

 function getTotal(){
            let total=0;
            for(var i = 0; i<10; i++){
                let valueToAdd = i;
                var multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }

Variabel dalam contoh abobe akan dikibarkan seperti di bawah ini

 function getTotal(){
            let total;
            var multiplier;
            total = 0;
            for(var i = 0; i<10; i++){
                let valueToAdd;
                valueToAdd = i;
                multiplier = 2;
                total += valueToAdd*multiplier;
            }
            return total;
        }
Tuan
sumber
0

ES5: mengangkat fungsi & mengangkat variabel

function hoistingprioritas adalah greaterdarivariable hoisting

"use strict";

/**
 *
 * @author xgqfrms
 * @license MIT
 * @copyright xgqfrms
 * @created 2016-06-01
 * @modified
 *
 * @description function-hoisting.js
 * @augments
 * @example
 * @link
 *
 */

(function() {
  const log = console.log;

  var a = 1;
  function b() {
    a = 10;
    log(`local a`, a)
    return;
    // function hoisting priority is greater than variable hoisting
    function a() {}
  }
  b();
  log(`global a`, a);
  // local a 10
  // global a 1
})();



yang sama dengan

(function() {
  const log = console.log;

  // define "a" in global scope
  var a = 1;
  function b() {
    // define "a" in local scope
    var a ;
    // assign function to a
    a = function () {};
    // overwrites local variable "a"
    a = 10;
    log(`local a`, a);
    return;
  }

  b();
  // log global variable "a"
  log(`global a`, a);

  // local a 10
  // global a 1
})();

alasan di balik pengangkatan

var a = 1;                
//"a" is global scope
function b() {  
   var a = function () {}; 
   //"a" is local scope 
   var x = 12; 
   //"x" is local scope 
   a = 10;
   //global variable "a" was overwrited by the local variable "a"  
   console.log("local a =" + a);
   return console.log("local x = " + x);
}       
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x = 
console.log(x);
// ReferenceError: x is not defined

/**
 *  scpope & closure & hoisting (var/function)
 *  
 * 1. scpope : the global var can be access in any place(the whole file scope), local var only can be accessed by the local scope(function/block scope)!
 * Note: if a local variable not using var keywords in a function, it will become a global variable!
 * 
 * 2. closure : a function inner the other function, which can access local scope(parent function) & global scope, howerver it's vars can't be accessed by others! unless, your return it as return value!
 * 
 * 3. hoisting : move all declare/undeclare vars/function to the scope top, than assign the value or null!
 * Note: it just move the declare, not move the value!
 * 
 */

ES6 let, consttidak ada yang mengangkat

(() => {
  const log = console.log;
  log(a)
  // Error: Uncaught ReferenceError: Cannot access 'a' before initialization
  let a = 1;
})();



(() => {
  const log = console.log;
  log(b)
  // Error: Uncaught ReferenceError: Cannot access 'b' before initialization
  const b = 1;
})();

ref

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const

xgqfrms.dll
sumber