搜尋
首頁web前端js教程javascript中的作用域和上下文使用簡要概述_基礎知識

javascript中的作用域(scope)和上下文(context)是這門語言的獨特之處,這部分歸功於他們帶來的靈活性。每個函數有不同的變數上下文和作用域。這些概念是javascript中一些強大的設計模式的後盾。然而這也給開發人員帶來很大困惑。以下全面揭示了javascript中的上下文和作用域的不同,以及各種設計模式如何使用他們。

上下文 vs 作用域

首先需要澄清的問題是上下文和作用域是不同的概念。多年來我注意到許多開發者經常將這兩個術語混淆,錯誤的將一個描述為另一個。平心而論,這些術語變得非常混亂不堪。

每個函數呼叫都有與之相關的作用域和上下文。從根本上說,範圍是基於函數(function-based)而上下文是基於物件(object-based)。換句話說,作用域是和每次函數呼叫時變數的存取有關,並且每次呼叫都是獨立的。上下文總是關鍵字 this 的值,是呼叫目前可執行程式碼的物件的參考。

變數作用域

變數能夠被定義在局部或全域作用域,這導致運行時變數的存取來自不同的作用域。全域變數需被宣告在函數體外,在整個運行過程中都存在,能在任何作用域中存取和修改。局部變數僅在函數體內定義,且每次函數呼叫都有不同的作用域。這個主題是僅在呼叫中的賦值,求值和對值的操作,不能存取作用域以外的值。

目前javascript不支援區塊級作用域,區塊級作用域指在if語句,switch語句,循環語句等語句區塊中定義變數,這表示變數不能在語句區塊之外被存取。當前任何在語句塊中定義的變數都能在語句塊之外存取。然而,這種情況很快就會改變,let 關鍵字已經正式加入ES6規格。用它來取代var關鍵字可以將局部變數聲明為區塊級作用域。

"this" 上下文

上下文通常取決於一個函數如何被呼叫。當函數作為物件的方法被呼叫時,this 被設定為呼叫方法的物件:

複製程式碼 程式碼如下:

var object = {
foo: function(){
alert(this === object);
}
};

object.foo(); // true

同樣的原理適用於當呼叫函數時透過new的操作符建立一個物件的實例。以這種方式呼叫時,this 的值將被設定為新建立的實例:
複製程式碼 程式碼如下:

function foo(){
alert(this);
}

foo() // window
new foo() // foo

當呼叫一個未綁定函數,this 將被預設為全域上下文(global context) 或window物件(如果在瀏覽器中)。然而如果函數在嚴格模式下被執行("use strict"),this的值將被預設為undefined。
執行上下文和作用域鏈

javascript是一個單線程語言,這意味著在瀏覽器中同時只能做一件事情。當javascript解釋器初始執行程式碼,它首先預設竟如全域上下文。每次呼叫一個函數將會建立一個新的執行上下文。

這裡常發生混淆,這術語」執行上下文(execution context)「這裡的所要表達的意思是作用域,不是前面討論的上下文。這是槽糕的命名,然而這術語ECMAScript規範所定義的,無奈的遵守吧。

每次新建立一個執行上下文,會被加到作用域鏈的頂部,又是也成為執行或呼叫堆疊。瀏覽器總是運行在位於作用域鏈頂部目前執行上下文。一旦完成,它(當前執行上下文)將從棧頂被移除並且將控制權歸還給先前的執行上下文。例如:
複製程式碼 程式碼如下:

function first(){
second( );
function second(){
third();
function third(){
fourth();
function fourth(){
// do something
}
}
}
}
first();

運行前面的程式碼將會導致巢狀的函數被從上倒下執行直到 fourth 函數,此時作用域鏈從上到下為: fourth, third, second, first, global。 fourth 函數能夠存取全域變數和任何在first,second和third函數中定義的變量,就如同存取自己的變數一樣。一旦fourth函數執行完成,fourth暈高興上下文將被從作用域鏈頂端移除並且執行將返回到thrid函數。這一過程持續進行直到所有程式碼已完成執行。

不同執行情境之間的變數命名衝突透過攀爬作用域鏈解決,從局部直到全域。這意味著具有相同名稱的局部變數在作用域鏈中有更高的優先權。

簡單的說,每次你試圖存取函數執行上下文中的變數時,尋找進程總是從自己的變數物件開始。如果在自己的變數物件中沒發現要找的變量,繼續搜尋作用域鏈。它將攀爬作用域鏈檢查每一個執行上下文的變數物件去尋找和變數名稱匹配的值。

閉包

當一個嵌套的函數在定義(作用域)的外面被訪問,以至它可以在外部函數返回後被執行,此時一個閉包形成。它(閉包)維護(在內部函數中)對外部函數中局部變量,arguments和函數聲明的存取。封裝允許我們從外部作用域中隱藏和保護執行上下文,而暴露公共接口,透過接口進一步操作。一個簡單的例子看起來如下:
複製程式碼 程式碼如下:

function foo() {
var local = 'private variable';
return function bar(){
return local;
}
}

var getLocalVariable = foo() var getLocalVariable = foo >getLocalVariable() // private variable

其中最受歡迎的閉包類型是廣為人知的模組模式。它允許你模擬公共的,私有的和特權成員:
複製代碼 代碼如下:

var Module = (function(){
var privateProperty = 'foo';

function privateMethod(args){
//do something
}

return {

publicProperty: "",

publicMethod: function(args){
//do something
},

privilegedMethod: function(args){ privateMethod(args);
}
}
})();

模組其實有些類似於單例,在末尾加上一對括號,當解釋器解釋完後立即執行(立即執行函數)。閉包執行上下位的外部唯一可用的成員是傳回物件中公用的方法和屬性(例如Module.publicMethod)。然而,所有的私有屬性和方法在整個程式的生命週期中都將存在,由於(閉包)使執行上下文收到保護,和變數的互動要透過公用的方法。

另一種類型的閉包叫做立即呼叫函數表達式(immediately-invoked function expression IIFE),無非是一個在window上下文中的自調用匿名函數(self-invoked anonymous function)。

複製程式碼 程式碼如下:
function(window){


function(window){
> a = 'foo', b = 'bar';

function private(){
// do something
}

window.Module = {


window.Module = {

public: function(){
// do something
}
};

})(this);
對保護全域命名空間,這種表達式非常有用,所有在函數體內聲明的變數都是局部變量,並透過閉包在整個運行環境保持存在。這種封裝原始碼的方式對程式和框架都是非常流行的,通常暴露單一全域介面與外界互動。


Call 和 Apply複製代碼


代碼如下:


function user(first, last, age){
// do something
} user.call(window, 'John', 'Doe', 30); user.apply (window, ['John', 'Doe', 30]);
実行結果は同じです。ユーザー関数はウィンドウ コンテキストで呼び出され、同じ 3 つのパラメーターが提供されます。

ECMAScript 5 (ES5) では、コンテキストを制御する Function.prototype.bind メソッドが導入され、この関数 (コンテキスト) は、バインド メソッドの最初のパラメーターに永続的にバインドされます。関数の呼び出し方法。クロージャを通じて関数のコンテキストを修正します。サポートされていないブラウザの場合の解決策は次のとおりです。
コードをコピーします。 コードは次のとおりです。

if(!('bind' in Function.prototype)){
Function.prototype.bind = function(){
var fn = this, context = argument[ 0] 、args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args);
}


これは、オブジェクト指向やイベント処理などのコンテキスト損失でよく使用されます。これが必要なのは、ノードの addEventListener メソッドがイベント ハンドラーがバインドされているノードとして関数実行のコンテキストを常に維持するためであり、これが重要です。ただし、高度なオブジェクト指向技術を使用し、コールバック関数のコンテキストをメソッドのインスタンスとして維持する必要がある場合は、コンテキストを手動で調整する必要があります。これはバインドによってもたらされる利便性です:


関数MyClass() {
this.element = document.createElement('div');
this.element.addEventListener('click', this.onClick.bind(this), false);
🎜>
MyClass.prototype.onClick = function(e){
// do something
};


バインド関数のソース コードを振り返ると、次の行は、配列のメソッドを呼び出す比較的単純なコードであることに気づくかもしれません:


コードをコピー コードは次のとおりです: Array.prototype.slice.call(arguments, 1);

興味深いことに、ここで、引数オブジェクトは実際には配列ではないことに注意してください。多くの場合、配列のような ) オブジェクトとして説明されます。これは、nodelist (document.getElementsByTagName() メソッド) によって返される結果です。これらには長さ属性が含まれており、値にインデックスを付けることができますが、スライスやプッシュなどのネイティブの配列メソッドをサポートしていないため、配列ではありません。ただし、配列と同様に動作するため、配列メソッドを呼び出してハイジャックすることができます。配列のようなコンテキストで配列メソッドを実行する場合は、上記の例に従ってください。
他のオブジェクト メソッドを呼び出すこの手法は、JavaScript で古典的な継承 (クラス継承) をエミュレートするときにオブジェクト指向にも適用されます:



コードをコピー コードは次のとおりです。 MyClass.prototype.init = function(){
// 「MyClass」のコンテキストでスーパークラスの init メソッドを呼び出します。 " インスタンス
MySuperClass.prototype.init.apply(this, argument);
}


サブクラス (MyClass) のインスタンスでスーパークラス (MySuperClass) のメソッドを呼び出すことによって、この強力なデザインパターンを再現できます。

結論

最新の JavaScript ロールではスコープとコンテキストが重要かつ基本的な役割を果たすため、高度なデザイン パターンを学習し始める前にこれらの概念を理解することが非常に重要です。クロージャ、オブジェクト指向、継承、またはさまざまなネイティブ実装について話す場合でも、コンテキストとスコープが重要な役割を果たします。 JavaScript 言語をマスターし、そのコンポーネントを深く理解することが目標の場合、スコープとコンテキストを出発点にする必要があります。

翻訳者の補足

作者が実装したバインド関数は、bind によって返される関数を呼び出すときにパラメータを渡すことができません。次のコードはこの問題を修正します。 🎜>



コードをコピーします
コードは次のとおりです: if(!('bind' Function.prototype)){ Function.prototype.bind = function(){
var fn = this, context = argument[0], args = Array.prototype.slice.call(arguments, 1);
return function(){
return fn.apply(context, args.concat(arguments));//修正
}
}
}

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
switch case 内变量的范围switch case 内变量的范围Feb 09, 2024 am 09:00 AM

packagemainimport"fmt"funcmain(){x:=10switchx{case0:y:='a'fmt.Printf("%c\n",y)case1://y='b'//thiscan'tcompile,y:='b'fmt.Printf("%c\n",y)default:y:=

Linux多线程编程锁详解:如何避免竞争和死锁Linux多线程编程锁详解:如何避免竞争和死锁Feb 11, 2024 pm 04:30 PM

在Linux多线程编程中,锁是一种非常重要的机制,可以避免线程间的竞争和死锁。然而,如果不正确使用锁,可能会导致性能下降和不稳定的行为。本文将介绍Linux中的常见锁类型,如何正确使用它们,以及如何避免竞争和死锁等问题。在编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性。每个对象都对应于一个可称为”互斥锁”的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。Linux实现的互斥锁机制包括POSIX互斥锁和内核互斥锁,本文主要讲POSIX互斥锁,即线程间互斥锁。信号量用在多线程

详解Golang函数中的变量作用域详解Golang函数中的变量作用域Jan 18, 2024 am 08:51 AM

Golang函数中的变量作用域详解在Golang中,变量的作用域指的是变量的可访问范围。了解变量的作用域对于代码的可读性和维护性非常重要。在本文中,我们将深入探讨Golang函数中的变量作用域,并提供具体的代码示例。在Golang中,变量的作用域可以分为全局作用域和局部作用域。全局作用域指的是在所有函数外部声明的变量,即在函数之外定义的变量。这些变量可以在整

Python Lambda表达式:让编程变得更轻松Python Lambda表达式:让编程变得更轻松Feb 19, 2024 pm 09:54 PM

pythonLambda表达式是一个小的匿名函数,它可以将一个表达式存储在变量中并返回它的值。Lambda表达式通常用于执行简单的任务,这些任务可以通过编写一个单独的函数来完成,但Lambda表达式可以使代码更简洁和易读。Lambda表达式的语法如下:lambdaarguments:expressionarguments是Lambda表达式接收的参数列表,expression是Lambda表达式的体,它包含需要执行的代码。例如,以下Lambda表达式将两个数字相加并返回它们的和:lambdax,

掌握JavaScript函数的嵌套和作用域掌握JavaScript函数的嵌套和作用域Nov 03, 2023 pm 07:55 PM

掌握JavaScript函数的嵌套和作用域,需要具体代码示例在JavaScript编程中,函数是非常重要的概念。函数的嵌套和作用域能够极大地提高代码的可读性和灵活性。本文将介绍如何正确地使用嵌套函数和作用域,并提供具体的代码示例。函数的嵌套可以理解为在一个函数中定义了另一个函数。这种嵌套的方式能够将代码分成多个小块,使得程序的逻辑更加清晰。同时,嵌套函数还可

JavaScript const关键字的用法及作用JavaScript const关键字的用法及作用Feb 19, 2024 pm 06:30 PM

JavaScript中const的作用和用法JavaScript是一种广泛应用于网页开发的编程语言,其具有灵活性和动态性是其特点之一。在JavaScript中,我们可以使用const关键字来声明一个常量。本文将介绍const关键字的作用和用法,并提供一些具体的代码示例来帮助读者更好地理解。const的作用const(常量)是一种用于声明不可更改的变量的关键字

c语言static的作用和用法是什么c语言static的作用和用法是什么Jan 31, 2024 pm 01:59 PM

c语言static的作用和用法:1、变量作用域;2、生命周期;3、函数内部;4、修饰全局变量;5、修饰函数;6、其他用途;详细介绍:1、变量作用域,当一个变量前有static关键字,那么这个变量的作用域被限制在声明它的文件内,也就是说,这个变量是“文件级作用域”,这对于防止变量的“重复定义”问题很有用;2、生命周期,静态变量在程序开始执行时初始化一次,并在程序结束时销毁等等。

如何解决Python的变量未定义错误?如何解决Python的变量未定义错误?Jun 24, 2023 pm 10:12 PM

Python是一种高级编程语言,它的易用性和流行程度使得它成为了众多程序员的首选语言。与其他语言一样,Python也存在一些常见的错误类型,例如变量未定义错误。当我们在Python中使用一个未定义的变量时,程序就会抛出一个名为“NameError”的异常。这种错误通常出现在以下几种情况下:拼写错误:可能是因为变量名拼写错误导致了变量未定义错误,我们需要仔细检

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解鎖Myrise中的所有內容
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

WebStorm Mac版

WebStorm Mac版

好用的JavaScript開發工具

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

Safe Exam Browser

Safe Exam Browser

Safe Exam Browser是一個安全的瀏覽器環境,安全地進行線上考試。該軟體將任何電腦變成一個安全的工作站。它控制對任何實用工具的訪問,並防止學生使用未經授權的資源。

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

微軟推出的免費、功能強大的一款IDE編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器