藤本  結衣

藤本 結衣

1638270720

JavaScriptのメモリライフサイクル、ヒープ、スタック、およびコールスタック

JavaScriptには、開発者としてあなたが知らないかもしれないトピックがあります。これらのトピックについて知っていると、より良いコードを書くのに役立ちます。メモリライフサイクル、ヒープ、スタック、およびコールスタックはそれらの一部です。このチュートリアルでは、これらのトピックとJavaScriptのしくみについて少し学びます。
 

簡単な紹介

JavaScriptは非常に寛容なプログラミング言語です。それはあなたが多くの方法で多くをすることを可能にします。それはまたあなたのためにたくさんの仕事をします。メモリ管理はこれらの1つです。自問してみてください。変数や関数にメモリを割り当てることを何回考えなければなりませんでしたか?

それらの変数や関数が不要になったときに、そのメモリを解放することを何回考えなければなりませんでしたか?チャンスは一度もありません。同じことが、ヒープ、スタック、およびコールスタックがどのように機能するか、あるいはそれが何であるかを知ることにも当てはまります。それでも、JavaScriptを使用することはできます。あなたはまだ毎日働くコードを書くことができます。

これらのことはあなたが知る必要はありません。また、それらは必要ありません。ただし、それらとそれらがどのように機能するかを知ることは、JavaScriptがどのように機能するかを理解するのに役立ちます。これにより、より優れたコードを記述し、より優れたJavaScriptになることができます。

メモリライフサイクル

最も簡単な部分から始めましょう。メモリライフサイクルとは何ですか、それは何についてであり、JavaScriptでどのように機能しますか?メモリライフサイクルとは、プログラミング言語がメモリとどのように連携するかを指します。言語に関係なく、メモリのライフサイクルはほとんど常に同じです。それは3つのステップで構成されています。

最初のステップはメモリ割り当てです。変数を割り当てたり、関数やオブジェクトを作成したりするときは、ある程度のメモリを割り当てる必要があります。2番目のステップはメモリの使用です。コード内のデータを処理するとき、読み取りまたは書き込みを行うときは、メモリを使用しています。変数からの読み取りまたは値の変更は、メモリからの読み取りおよびメモリへの書き込みです。

3番目のステップはメモリの解放です。一部の関数またはオブジェクトを使用しなくなると、そのメモリは解放されます。リリースされると、再び使用できます。これは一言で言えばメモリのライフサイクルです。JavaScriptの良いところは、これらの3つのステップを実行できることです。

JavaScriptは、必要に応じてメモリを割り当てます。割り当てられたメモリを簡単に操作できるようになります。最後に、それはまた、ヒービングリフティングを行い、すべての混乱をクリーンアップします。ガベージコレクションを使用してメモリを継続的にチェックし、使用されなくなったときに解放します。結果?

JavaScript開発者は、変数や関数にメモリを割り当てることを心配する必要はありません。また、読み取る前に正しいメモリアドレスを選択することを心配する必要はありません。また、過去に使用したメモリを解放することを心配する必要はありません。

スタックとメモリヒープ

これで、メモリライフサイクルのステップについて理解できました。あなたはメモリの割り当て、使用、解放について知っています。あなたが尋ねるかもしれない1つの質問は、それらの変数、関数、オブジェクトが実際にどこに保存されているかということです。答えは:それは異なります。JavaScriptは、これらすべてを同じ場所に保存するわけではありません。

JavaScriptが代わりに行うことは、2つの場所を使用することです。これらの場所はスタックとメモリヒープです。これらの場所のどれが使用されるかは、現在作業している場所によって異なります。

スタック

スタックは、JavaScriptが静的データのみを格納するために使用する場所です。これには、プリミティブデータ型の値が含まれます。たとえば、数値、文字列、ブール値、undefinedおよびnull。これらの静的データには参照も含まれます。これらの参照は、作成したオブジェクトと関数を指します。

これらのデータには1つの共通点があります。これらのデータのサイズは固定されており、JavaScriptはコンパイル時にこのサイズを認識します。これは、JavaScriptが割り当てる必要のあるメモリの量を認識し、その量を割り当てることも意味します。このタイプのメモリ割り当ては、「静的メモリ割り当て」と呼ばれます。これは、コードが実行される直前に発生します。

静的データとメモリについて重要なことが1つあります。これらのプリミティブ値の大きさには制限があります。これは、スタック自体にも当てはまります。それにも限界があります。これらの制限の高さは、特定のブラウザとエンジンによって異なります。

// Declare and assign some variables
// and assign them primitive data types
// All these variables are stored in stack
const firstName = 'Jill'
const lastName = 'Stuart'
const age = 23
const selfEmployed = true
const dateOfMarriage = null

// The stack after declaring
// and assigning those variables:
// dateOfMarriage = null
// selfEmployed = true
// age = 23
// lastName = 'Stuart'
// firstName = 'Jill'

メモリヒープ

JavaScriptがデータを格納できる2番目の場所は、メモリヒープです。このストレージはより動的です。メモリヒープに関しては、JavaScriptは一定量のメモリを割り当てません。代わりに、現時点で必要に応じてメモリを割り当てます。このタイプのメモリ割り当ては、「動的メモリ割り当て」と呼ばれます。

どのデータがメモリヒープに保存されますか?スタックはJavaScriptが静的データを格納する場所ですが、メモリヒープはJavaScriptがオブジェクトと関数を格納する場所です。したがって、プリミティブを使用して作成する場合は、静的データを使用していることを忘れないでください。JavaScriptは、これらの静的データをスタックに格納します。

これらのデータは常に割り当てられたメモリを固定しています。一方、オブジェクトまたは関数を作成すると、JavaScriptはそれらをメモリヒープに格納します。これらに割り当てられたメモリは固定されていません。必要に応じて動的に割り当てられます。

// Declare a variable and assign it an object
const terryP = {
  firstName: 'Terry',
  lastName: 'Pratchett',
  profession: 'author'
}

function introduceTerry() {
  return `Hi, my name is ${terryP.firstName}.`
}

const series = ['Discworld', 'Johnny Maxwell', 'Long Earth']

const isDone = true

// Stack:
// isDone = true
// introduceTerry (reference to function)
// terryP (reference to "terryP" object)
// series (reference to "series" array)


// Memory heap:
//  {
//    firstName: 'Terry',
//    lastName: 'Pratchett',
//    profession: 'author
//  }
//  function introduceTerry() {
//    return `Hi, my name is ${terryP.firstName}.`
// }
//  ['Discworld', 'Johnny Maxwell', 'Long Earth']

// NOTE:
// the "terryP" in stack points
// to the "terryP" object in memory heap
// the "introduceTerry" in stack points
// to introduceTerry() function in memory heap
// the "series" in stack points
// to the "series" array in memory heap
// arrays are objects in JavaScript

スタック、ヒープ、および参照

変数を作成してプリミティブ値を割り当てると、スタックに格納されます。同じことをオブジェクトで試してみると、何か違うことが起こります。変数を宣言してオブジェクトを割り当てると、2つのことが起こります。まず、JavaScriptはその変数のスタックにメモリを割り当てます。

オブジェクト自体に関しては、JavaScriptはそれをメモリヒープに格納します。スタックに存在するその変数は、メモリヒープ内のこのオブジェクトのみを指します。その変数は、このオブジェクトへの参照になります。参照は、既存のもののショートカットまたはエイリアスと考えることができます。

これらの参照はそれ自体ではありません。それらはそれらの「本物の」ものへのリンクにすぎません。それらのリンクを使用して、それらが参照する(リンクされている)ものにアクセスし、それらを操作することができます。

// Declare variable and assign it an object
// The "cat" variable will be stored in stack
// It will hold the reference to the "cat" object
const cat = {
  name: 'Kitty'
  breed: 'Abyssinian'
}

// The "cat" object itself will be stored in memory heap

// Memory heap:
//  {
//    name: 'Kitty',
//    breed: 'Abyssinian'
//  }

オブジェクトとプリミティブのコピー

これが、JavaScriptでオブジェクトのコピーを作成することが実際にはそれほど単純ではない理由でもあります。変数に格納されているオブジェクトのコピーを参照して作成しようとしても、実際のコピーは作成されません。オブジェクト自体はコピーされません。そのオブジェクトへの参照のみをコピーします。これは浅いコピーと呼ばれます

その後、元のオブジェクトを変更すると、コピーも変更されます。これは、オブジェクトがまだ1つしかないためです。ただし、その1つのオブジェクトへの参照(エイリアスまたはリンク)は2つあります。これらの参照の1つを使用してオブジェクトを変更しても、他の参照は同じオブジェクト、つまり変更したばかりのオブジェクトを指します。

// Declare a variable and assign it an object
const bookShelf = {
  read: 'Colour Of Magic',
  reading: 'Night Watch',
  toRead: 'Going Postal'
}

// Create a copy of the "bookShelf"
const newBookShelf = bookShelf

// Update the "bookShelf"
bookShelf.reading = 'Mort'
bookShelf.justFinished = 'Night Watch'

// Log the value of "bookShelf"
console.log(bookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

// Log the value of "newBookShelf"
// Since "newBookShelf" and "bookShelf"
// points to the same object
// the output will be the same
console.log(newBookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

プリミティブ値をコピーしようとすると、これは発生しません。プリミティブ値をコピーしようとしたときに元の値を変更しても、コピーは変更されません。理由:参照がありません。あなたは実際のコピーを作成していて、それらのコピーを直接操作しています。

// Declare a variable with some primitive value
let book = 'Guards! Guards! (Paperback)'

// Create a copy of the "book"
const bookToRead = book

// Update the value of "book"
book = 'Guards! Guards! (Kindle Edition)'

// Log the value of "book"
// This will log the updated value
console.log(book)
// Output:
// 'Guards! Guards! (Kindle Edition)'

// Log the value of "bookToRead"
// This will log the old value because the "bookToRead"
// is a real copy of "book"
console.log(bookToRead)
// Output:
// 'Guards! Guards! (Paperback)'

実際のコピーであるディープコピーの作成は、もう少し複雑です。効果の低い1つのオプションは、そのオブジェクトを最初から作成することです。もう1つのオプションは、Object.assign()を使用することです。もう1つは、JSON.parse()との組み合わせを使用することですJSON.stringify()

// Declare a variable and assign it an object
const bookShelf = {
  read: 'Colour Of Magic',
  reading: 'Night Watch',
  toRead: 'Going Postal'
}

// Create a copy of the "bookShelf"
const newBookShelf = Object.assign({}, bookShelf)

// Update the "bookShelf"
bookShelf.reading = 'Mort'
bookShelf.justFinished = 'Night Watch'

// Log the value of "bookShelf"
console.log(bookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

// Log the value of "newBookShelf"
// The output will be different this time
// because the "newBookShelf" points
// to a different object than the "bookShelf"
console.log(newBookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Night Watch',
//   toRead: 'Going Postal'
// }

コールスタック

「コールスタック」と呼ばれるものについては、すでに聞いたことがあるでしょう。これは、このチュートリアルで前に説明したスタックと同じではありません。ご存知のように、スタックはJavaScriptがプリミティブ値が割り当てられた変数を格納するために使用する場所です。コールスタックは何か違うものです。

コールスタックは、JavaScriptが関数を追跡するために使用するメカニズムです。関数を呼び出すと、JavaScriptはその関数を呼び出しスタックに追加します。この関数が別の関数を呼び出す場合、JavaScriptはその関数を最初の関数の上にある呼び出しスタックにも追加します。

このプロセスは、前の関数によって呼び出される他の関数で繰り返されます。1つの関数が終了すると、JavaScriptはその関数を呼び出しスタックから削除します。2つの重要なことがあります。まず、スタック内のすべての新しい関数が呼び出しスタックの一番上に追加されます。

2つ目は、コールスタックが上から下に実行されることです。スタックに追加された最後の関数が最初に実行されます。スタックに追加された最初の関数は、最後に実行されます。これは、LIFOの原則(後入れ先出し)とも呼ばれます。これを1つの簡単な例のコードで説明しましょう。

function myFuncOne() {
  return 'This is the end.'
}

function myFuncTwo() {
  myFuncOne()

  return 'Knock knock.'
}

// Call stack is still empty here

myFuncTwo()

// Call stack:
// Step 1: myFuncTwo() is invoked
// Step 2: myFuncTwo() added to the call stack
// Step 3: myFuncTwo() calls myFuncOne()
// Step 4: myFuncOne() is added to the call stack
// Step 5: myFuncOne(), is executed
// Step 6: myFuncOne() removed from the stack
// Step 7: JavaScript goes back to myFuncTwo()
// Step 8: any code left inside myFuncTwo() after myFuncOne() call is executed
// Step 9: myFuncTwo() is removed from the stack
// Step 10: call stack is empty

結論:JavaScriptのメモリライフサイクル、ヒープ、スタック、およびコールスタック

メモリライフサイクル、ヒープ、スタック、およびコールスタックは、それほど頻繁に説明されていないトピックです。それらについてもっと学ぶために使用できる資料はあまりありません。このチュートリアルが、メモリライフサイクル、ヒープ、スタック、およびコールスタックとは何か、およびそれらがどのように機能するかを理解するのに役立つことを願っています。

この記事が気に入ったら、今後の投稿を見逃さないように購読してください。


リンク:  https://blog.alexdevero.com/memory-life-cycle-heap-stack-javascript/

#javascript 

What is GEEK

Buddha Community

JavaScriptのメモリライフサイクル、ヒープ、スタック、およびコールスタック
藤本  結衣

藤本 結衣

1638270720

JavaScriptのメモリライフサイクル、ヒープ、スタック、およびコールスタック

JavaScriptには、開発者としてあなたが知らないかもしれないトピックがあります。これらのトピックについて知っていると、より良いコードを書くのに役立ちます。メモリライフサイクル、ヒープ、スタック、およびコールスタックはそれらの一部です。このチュートリアルでは、これらのトピックとJavaScriptのしくみについて少し学びます。
 

簡単な紹介

JavaScriptは非常に寛容なプログラミング言語です。それはあなたが多くの方法で多くをすることを可能にします。それはまたあなたのためにたくさんの仕事をします。メモリ管理はこれらの1つです。自問してみてください。変数や関数にメモリを割り当てることを何回考えなければなりませんでしたか?

それらの変数や関数が不要になったときに、そのメモリを解放することを何回考えなければなりませんでしたか?チャンスは一度もありません。同じことが、ヒープ、スタック、およびコールスタックがどのように機能するか、あるいはそれが何であるかを知ることにも当てはまります。それでも、JavaScriptを使用することはできます。あなたはまだ毎日働くコードを書くことができます。

これらのことはあなたが知る必要はありません。また、それらは必要ありません。ただし、それらとそれらがどのように機能するかを知ることは、JavaScriptがどのように機能するかを理解するのに役立ちます。これにより、より優れたコードを記述し、より優れたJavaScriptになることができます。

メモリライフサイクル

最も簡単な部分から始めましょう。メモリライフサイクルとは何ですか、それは何についてであり、JavaScriptでどのように機能しますか?メモリライフサイクルとは、プログラミング言語がメモリとどのように連携するかを指します。言語に関係なく、メモリのライフサイクルはほとんど常に同じです。それは3つのステップで構成されています。

最初のステップはメモリ割り当てです。変数を割り当てたり、関数やオブジェクトを作成したりするときは、ある程度のメモリを割り当てる必要があります。2番目のステップはメモリの使用です。コード内のデータを処理するとき、読み取りまたは書き込みを行うときは、メモリを使用しています。変数からの読み取りまたは値の変更は、メモリからの読み取りおよびメモリへの書き込みです。

3番目のステップはメモリの解放です。一部の関数またはオブジェクトを使用しなくなると、そのメモリは解放されます。リリースされると、再び使用できます。これは一言で言えばメモリのライフサイクルです。JavaScriptの良いところは、これらの3つのステップを実行できることです。

JavaScriptは、必要に応じてメモリを割り当てます。割り当てられたメモリを簡単に操作できるようになります。最後に、それはまた、ヒービングリフティングを行い、すべての混乱をクリーンアップします。ガベージコレクションを使用してメモリを継続的にチェックし、使用されなくなったときに解放します。結果?

JavaScript開発者は、変数や関数にメモリを割り当てることを心配する必要はありません。また、読み取る前に正しいメモリアドレスを選択することを心配する必要はありません。また、過去に使用したメモリを解放することを心配する必要はありません。

スタックとメモリヒープ

これで、メモリライフサイクルのステップについて理解できました。あなたはメモリの割り当て、使用、解放について知っています。あなたが尋ねるかもしれない1つの質問は、それらの変数、関数、オブジェクトが実際にどこに保存されているかということです。答えは:それは異なります。JavaScriptは、これらすべてを同じ場所に保存するわけではありません。

JavaScriptが代わりに行うことは、2つの場所を使用することです。これらの場所はスタックとメモリヒープです。これらの場所のどれが使用されるかは、現在作業している場所によって異なります。

スタック

スタックは、JavaScriptが静的データのみを格納するために使用する場所です。これには、プリミティブデータ型の値が含まれます。たとえば、数値、文字列、ブール値、undefinedおよびnull。これらの静的データには参照も含まれます。これらの参照は、作成したオブジェクトと関数を指します。

これらのデータには1つの共通点があります。これらのデータのサイズは固定されており、JavaScriptはコンパイル時にこのサイズを認識します。これは、JavaScriptが割り当てる必要のあるメモリの量を認識し、その量を割り当てることも意味します。このタイプのメモリ割り当ては、「静的メモリ割り当て」と呼ばれます。これは、コードが実行される直前に発生します。

静的データとメモリについて重要なことが1つあります。これらのプリミティブ値の大きさには制限があります。これは、スタック自体にも当てはまります。それにも限界があります。これらの制限の高さは、特定のブラウザとエンジンによって異なります。

// Declare and assign some variables
// and assign them primitive data types
// All these variables are stored in stack
const firstName = 'Jill'
const lastName = 'Stuart'
const age = 23
const selfEmployed = true
const dateOfMarriage = null

// The stack after declaring
// and assigning those variables:
// dateOfMarriage = null
// selfEmployed = true
// age = 23
// lastName = 'Stuart'
// firstName = 'Jill'

メモリヒープ

JavaScriptがデータを格納できる2番目の場所は、メモリヒープです。このストレージはより動的です。メモリヒープに関しては、JavaScriptは一定量のメモリを割り当てません。代わりに、現時点で必要に応じてメモリを割り当てます。このタイプのメモリ割り当ては、「動的メモリ割り当て」と呼ばれます。

どのデータがメモリヒープに保存されますか?スタックはJavaScriptが静的データを格納する場所ですが、メモリヒープはJavaScriptがオブジェクトと関数を格納する場所です。したがって、プリミティブを使用して作成する場合は、静的データを使用していることを忘れないでください。JavaScriptは、これらの静的データをスタックに格納します。

これらのデータは常に割り当てられたメモリを固定しています。一方、オブジェクトまたは関数を作成すると、JavaScriptはそれらをメモリヒープに格納します。これらに割り当てられたメモリは固定されていません。必要に応じて動的に割り当てられます。

// Declare a variable and assign it an object
const terryP = {
  firstName: 'Terry',
  lastName: 'Pratchett',
  profession: 'author'
}

function introduceTerry() {
  return `Hi, my name is ${terryP.firstName}.`
}

const series = ['Discworld', 'Johnny Maxwell', 'Long Earth']

const isDone = true

// Stack:
// isDone = true
// introduceTerry (reference to function)
// terryP (reference to "terryP" object)
// series (reference to "series" array)


// Memory heap:
//  {
//    firstName: 'Terry',
//    lastName: 'Pratchett',
//    profession: 'author
//  }
//  function introduceTerry() {
//    return `Hi, my name is ${terryP.firstName}.`
// }
//  ['Discworld', 'Johnny Maxwell', 'Long Earth']

// NOTE:
// the "terryP" in stack points
// to the "terryP" object in memory heap
// the "introduceTerry" in stack points
// to introduceTerry() function in memory heap
// the "series" in stack points
// to the "series" array in memory heap
// arrays are objects in JavaScript

スタック、ヒープ、および参照

変数を作成してプリミティブ値を割り当てると、スタックに格納されます。同じことをオブジェクトで試してみると、何か違うことが起こります。変数を宣言してオブジェクトを割り当てると、2つのことが起こります。まず、JavaScriptはその変数のスタックにメモリを割り当てます。

オブジェクト自体に関しては、JavaScriptはそれをメモリヒープに格納します。スタックに存在するその変数は、メモリヒープ内のこのオブジェクトのみを指します。その変数は、このオブジェクトへの参照になります。参照は、既存のもののショートカットまたはエイリアスと考えることができます。

これらの参照はそれ自体ではありません。それらはそれらの「本物の」ものへのリンクにすぎません。それらのリンクを使用して、それらが参照する(リンクされている)ものにアクセスし、それらを操作することができます。

// Declare variable and assign it an object
// The "cat" variable will be stored in stack
// It will hold the reference to the "cat" object
const cat = {
  name: 'Kitty'
  breed: 'Abyssinian'
}

// The "cat" object itself will be stored in memory heap

// Memory heap:
//  {
//    name: 'Kitty',
//    breed: 'Abyssinian'
//  }

オブジェクトとプリミティブのコピー

これが、JavaScriptでオブジェクトのコピーを作成することが実際にはそれほど単純ではない理由でもあります。変数に格納されているオブジェクトのコピーを参照して作成しようとしても、実際のコピーは作成されません。オブジェクト自体はコピーされません。そのオブジェクトへの参照のみをコピーします。これは浅いコピーと呼ばれます

その後、元のオブジェクトを変更すると、コピーも変更されます。これは、オブジェクトがまだ1つしかないためです。ただし、その1つのオブジェクトへの参照(エイリアスまたはリンク)は2つあります。これらの参照の1つを使用してオブジェクトを変更しても、他の参照は同じオブジェクト、つまり変更したばかりのオブジェクトを指します。

// Declare a variable and assign it an object
const bookShelf = {
  read: 'Colour Of Magic',
  reading: 'Night Watch',
  toRead: 'Going Postal'
}

// Create a copy of the "bookShelf"
const newBookShelf = bookShelf

// Update the "bookShelf"
bookShelf.reading = 'Mort'
bookShelf.justFinished = 'Night Watch'

// Log the value of "bookShelf"
console.log(bookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

// Log the value of "newBookShelf"
// Since "newBookShelf" and "bookShelf"
// points to the same object
// the output will be the same
console.log(newBookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

プリミティブ値をコピーしようとすると、これは発生しません。プリミティブ値をコピーしようとしたときに元の値を変更しても、コピーは変更されません。理由:参照がありません。あなたは実際のコピーを作成していて、それらのコピーを直接操作しています。

// Declare a variable with some primitive value
let book = 'Guards! Guards! (Paperback)'

// Create a copy of the "book"
const bookToRead = book

// Update the value of "book"
book = 'Guards! Guards! (Kindle Edition)'

// Log the value of "book"
// This will log the updated value
console.log(book)
// Output:
// 'Guards! Guards! (Kindle Edition)'

// Log the value of "bookToRead"
// This will log the old value because the "bookToRead"
// is a real copy of "book"
console.log(bookToRead)
// Output:
// 'Guards! Guards! (Paperback)'

実際のコピーであるディープコピーの作成は、もう少し複雑です。効果の低い1つのオプションは、そのオブジェクトを最初から作成することです。もう1つのオプションは、Object.assign()を使用することです。もう1つは、JSON.parse()との組み合わせを使用することですJSON.stringify()

// Declare a variable and assign it an object
const bookShelf = {
  read: 'Colour Of Magic',
  reading: 'Night Watch',
  toRead: 'Going Postal'
}

// Create a copy of the "bookShelf"
const newBookShelf = Object.assign({}, bookShelf)

// Update the "bookShelf"
bookShelf.reading = 'Mort'
bookShelf.justFinished = 'Night Watch'

// Log the value of "bookShelf"
console.log(bookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Mort',
//   toRead: 'Going Postal',
//   justFinished: 'Night Watch'
// }

// Log the value of "newBookShelf"
// The output will be different this time
// because the "newBookShelf" points
// to a different object than the "bookShelf"
console.log(newBookShelf)
// Output:
// {
//   read: 'Colour Of Magic',
//   reading: 'Night Watch',
//   toRead: 'Going Postal'
// }

コールスタック

「コールスタック」と呼ばれるものについては、すでに聞いたことがあるでしょう。これは、このチュートリアルで前に説明したスタックと同じではありません。ご存知のように、スタックはJavaScriptがプリミティブ値が割り当てられた変数を格納するために使用する場所です。コールスタックは何か違うものです。

コールスタックは、JavaScriptが関数を追跡するために使用するメカニズムです。関数を呼び出すと、JavaScriptはその関数を呼び出しスタックに追加します。この関数が別の関数を呼び出す場合、JavaScriptはその関数を最初の関数の上にある呼び出しスタックにも追加します。

このプロセスは、前の関数によって呼び出される他の関数で繰り返されます。1つの関数が終了すると、JavaScriptはその関数を呼び出しスタックから削除します。2つの重要なことがあります。まず、スタック内のすべての新しい関数が呼び出しスタックの一番上に追加されます。

2つ目は、コールスタックが上から下に実行されることです。スタックに追加された最後の関数が最初に実行されます。スタックに追加された最初の関数は、最後に実行されます。これは、LIFOの原則(後入れ先出し)とも呼ばれます。これを1つの簡単な例のコードで説明しましょう。

function myFuncOne() {
  return 'This is the end.'
}

function myFuncTwo() {
  myFuncOne()

  return 'Knock knock.'
}

// Call stack is still empty here

myFuncTwo()

// Call stack:
// Step 1: myFuncTwo() is invoked
// Step 2: myFuncTwo() added to the call stack
// Step 3: myFuncTwo() calls myFuncOne()
// Step 4: myFuncOne() is added to the call stack
// Step 5: myFuncOne(), is executed
// Step 6: myFuncOne() removed from the stack
// Step 7: JavaScript goes back to myFuncTwo()
// Step 8: any code left inside myFuncTwo() after myFuncOne() call is executed
// Step 9: myFuncTwo() is removed from the stack
// Step 10: call stack is empty

結論:JavaScriptのメモリライフサイクル、ヒープ、スタック、およびコールスタック

メモリライフサイクル、ヒープ、スタック、およびコールスタックは、それほど頻繁に説明されていないトピックです。それらについてもっと学ぶために使用できる資料はあまりありません。このチュートリアルが、メモリライフサイクル、ヒープ、スタック、およびコールスタックとは何か、およびそれらがどのように機能するかを理解するのに役立つことを願っています。

この記事が気に入ったら、今後の投稿を見逃さないように購読してください。


リンク:  https://blog.alexdevero.com/memory-life-cycle-heap-stack-javascript/

#javascript