ホームページ > 記事 > ウェブフロントエンド > JS の 3 つの山の詳細な説明: スコープとクロージャ、プロトタイプとプロトタイプ チェーン、非同期とシングル スレッド
js はフロントエンドのバックボーンとして機能します。では、JavaScript の三大山とは何かご存知ですか?
スコープ
は現在のコードを参照します コンテキスト変数と関数の可視性とライフサイクルを制御します。最大の機能は変数を分離することで、異なるスコープにある同じ名前の変数が競合しないようにします。
スコープ チェーン
は、現在のスコープで値が見つからない場合、グローバル スコープに到達するまで上位スコープをクエリすることを意味します。このような検索プロセスはチェーンです。形成されたものをスコープチェーンと呼びます。 [推奨学習: JavaScript ビデオ チュートリアル ]
スコープは階層構造にスタックでき、子スコープは親スコープにアクセスできますが、その逆はできません。
スコープは 4 つのタイプに細分できます: グローバル スコープ
、モジュール スコープ
、関数スコープ
#、ブロックレベル スコープ
##グローバル スコープ: コードはプログラム内にあり、どこからでもアクセスできます。ウィンドウオブジェクトなど。ただし、グローバル変数はグローバル名前空間を汚染し、名前の競合を引き起こしやすくなります。
モジュール スコープ: 元のスクリプトは小さくて単純だったため、初期の js 構文にはモジュール定義がありませんでした。その後、スクリプトがますます複雑になるにつれて、モジュール型ソリューション (AMD、CommonJS、UMD、ES6 モジュールなど) が登場しました。通常、モジュールはファイルまたはスクリプトであり、このモジュールには独自の独立したスコープがあります。
関数スコープ: 名前が示すように、関数によって作成されるスコープ。クロージャはこのスコープ内で生成されますが、これについては後で別途紹介します。
ブロックレベルのスコープ: js 変数のプロモーションには変数カバレッジや変数汚染などの設計上の欠陥があるため、ES6 ではこれらの問題を解決するためにブロックレベルのスコープ キーワードが導入されています。典型的なケースは、let の for ループと var の for ループです。
// var demo for(var i=0; i<10; i++) { console.log(i); } console.log(i); // 10 // let demo for(let i=0; i<10; i++) { console.log(i); } console.log(i); //ReferenceError:i is not definedスコープを理解したら、それについて話しましょう
クロージャ:
関数 A には関数 B が含まれており、関数 B は関数 A の変数を使用し、次に関数 B Aクロージャまたはクロージャは、関数 A の内部変数を読み取ることができる関数です。
クロージャは、内部関数 によって外部関数の変数が解放されないことです。
クロージャの特徴:
クロージャの適用シナリオを以下にまとめます。
// demo1 输出 3 3 3 for(var i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } // demo2 输出 0 1 2 for(let i = 0; i < 3; i++) { setTimeout(function() { console.log(i); }, 1000); } // demo3 输出 0 1 2 for(let i = 0; i < 3; i++) { (function(i){ setTimeout(function() { console.log(i); }, 1000); })(i) }
/* 模拟私有方法 */ // 模拟对象的get与set方法 var Counter = (function() { var privateCounter = 0; function changeBy(val) { privateCounter += val; } return { increment: function() { changeBy(1); }, decrement: function() { changeBy(-1); }, value: function() { return privateCounter; } } })(); console.log(Counter.value()); /* logs 0 */ Counter.increment(); Counter.increment(); console.log(Counter.value()); /* logs 2 */ Counter.decrement(); console.log(Counter.value()); /* logs 1 */
/* setTimeout中使用 */ // setTimeout(fn, number): fn 是不能带参数的。使用闭包绑定一个上下文可以在闭包中获取这个上下文的数据。 function func(param){ return function(){ alert(param) }} const f1 = func(1);setTimeout(f1,1000);
/* 生产者/消费者模型 */ // 不使用闭包 // 生产者 function producer(){ const data = new(...) return data } // 消费者 function consumer(data){ // do consume... } const data = producer() // 使用闭包 function process(){ var data = new (...) return function consumer(){ // do consume data ... } } const processer = process() processer()
/* 实现继承 */ // 以下两种方式都可以实现继承,但是闭包方式每次构造器都会被调用且重新赋值一次所以,所以实现继承原型优于闭包 // 闭包 function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); this.getName = function() { return this.name; }; this.getMessage = function() { return this.message; }; } // 原型 function MyObject(name, message) { this.name = name.toString(); this.message = message.toString(); } MyObject.prototype.getName = function() { return this.name; }; MyObject.prototype.getMessage = function() { return this.message; };クロージャの概念は理解しているようですが、何かが足りないようですか?その意味はまだ終わっていません。私もクロージャで迷っていましたが、クロージャのライフサイクルを読んだ後、再び自分自身を発見しました。 学習したら、簡単なテストをしてみましょう
function test(a, b){ console.log(b); return { test: function(c) { return test(c,a); } } } var a = test(100);a.test(101);a.test(102); var b = test(200).test(201).test(202); var c = test(300).test(301);c.test(302); // undefined 100 100 // undefined 200 201 // undefined 300 301
prototype があり、各オブジェクトは内部のプロパティであるプロトタイプ(プロトタイプ)を初期化し、プロトタイプには共有プロパティやメソッドが格納されます。オブジェクトのプロパティにアクセスすると、JS エンジンはまず現在のオブジェクトにこのプロパティがあるかどうかを確認します。ない場合は、プロトタイプ オブジェクトにこのプロパティがあるかどうかを確認し、Object 組み込みオブジェクトが取得されるまで同様に確認します。このような検索プロセスは、プロトタイプ チェーン
の概念を形成しました。
instance.__proto__ === instance.constructor.prototype
Object.prototype.__proto__ === null
Object.prototype.constructor === Object
看起来是不是有点乱??别慌!!一张图帮你整理它们之间的关系
相同的配方再来一刀
const arr = [1, 2, 3]; arr.__proto__ === Array.prototype; // true arr.__proto__.__proto__ === Object.prototype; // true Array.__proto__ === Function.prototype; // true
JavaScript 是 单线程
语言,意味着只有单独的一个调用栈,同一时间只能处理一个任务或一段代码。队列、堆、栈、事件循环构成了 js 的并发模型,事件循环
是 JavaScript 的执行机制。
为什么js是一门单线程语言呢?最初设计JS是用来在浏览器验证表单以及操控DOM元素,为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程。
既然是单线程也就意味着不存在异步,只能自上而下执行,如果代码阻塞只能一直等下去,这样导致很差的用户体验,所以事件循环的出现让 js 拥有异步的能力。
更多编程相关知识,请访问:编程教学!!
以上がJS の 3 つの山の詳細な説明: スコープとクロージャ、プロトタイプとプロトタイプ チェーン、非同期とシングル スレッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。