作用域,上下文,闭包
作用域
作用域決定了你的代碼里的變量和其他資源在各個區域中的可見性,為代碼提供了一個安全層級,用戶只能訪問他們當前需要的東西。
在 JavaScript 中有兩種作用域:
全局作用域:定義在函數之外的變量會被保存在全局作用域中,在代碼的任何地方都是可訪問的。
局部作用域(函數作用域):在函數內定義的變量(局部變量)或者函數的參數,只在當前函數體內以及這個函數體嵌套的任意函數體可訪問,函數外部不能訪問。
?
訪問當前作用域的變量速度比訪問其他作用域的快,因為會順著作用域鏈查找,直到找到你要的或者沒有結果。
?
在一個函數中,如果局部變量和全局變量同名,局部變量會覆蓋全局變量。在函數體內訪問這個變量,是局部變量的值。所以,在不同的作用域,可以命名相同的變量而不導致沖突,解決了不同范圍的同名變量命名問題
var num = 1; //聲明一個全局變量function func() {var num = 2; //聲明一個局部變量return num;}console.log(func()); //輸出:2局部變量在函數開始執行時創建,函數執行完后局部變量會自動銷毀。(當通過閉包在函數外面引用了局部變量,當函數執行完,局部變量不會被銷毀)
一個應用中全局作用域的生存周期與該應用相同。局部作用域只在該函數調用執行期間存在。?
?
變量聲明提前
變量在整個函數體內都是有定義的,所以在賦值前是能訪問的,即變量聲明提升到當前函數體頂部(要是當前函數嵌套了其他函數,其他函數中聲明的變量,由于作用域鏈的關系,其他函數體的變量,在當前函數體內是不可訪問的,不存在聲明提升到當前函數體的說法)
function func() {console.log(num); //輸出:undefined,而非報錯,因為變量num在整個函數體內都是有定義的var num = 1; //聲明num 在整個函數體func內都有定義console.log(num);?//輸出:1?}func();
?
作用域鏈
從當前作用域出發,決定了哪些數據能被訪問,不講大道理,直接畫圖吧。
比如下圖:想在函數3里訪問變量a,過程是:先在函數3里找,沒有就在函數2里找,再沒有就在函數1里找,直到找到全局作用域,看是否有這么個變量a,是不是像順著一根鏈子找呢,這個就是作用域鏈。(上一層的作用域也叫做父級作用域)
?
ECMAScript 6 引入了let和const關鍵字。這些關鍵字可以代替var。
let likes = 'Coding'; const skills = 'Javascript and PHP';?
和var關鍵字不同,let和const關鍵字支持在塊級聲明中創建使用局部作用域。
if (true) { var name = 'Hammad'; let likes = 'Coding';、 const skills = 'JavaScript and PHP'; } console.log(name); // logs 'Hammad' console.log(likes); // Uncaught ReferenceError: likes is not defined console.log(skills); // Uncaught ReferenceError: skills is not defined?
上下文
上下文指的是在相同的作用域中的this的值??梢允褂煤瘮捣椒ǜ淖兩舷挛?#xff0c;上下文是執行的時候確定的。
在全局作用域中,上下文總是 Window 對象。
作為一個對象的方法,上下文就是這個方法所在的那個對象。
使用new關鍵字調用函數時上下文,上下文會設置為被調用的函數的實例
當在嚴格模式(strict mode)中調用函數時,上下文默認是 undefined。
?
使用 .call(), .apply() 和 .bind() 改變上下文
Call 和 Apply 函數來改變函數調用時的上下文。context={a:1,y:2};
function hello(a,b) {
alert(this.a);
alert(a);
alert(b);
}
hello();
hello.call(context,"cc","dd"); //1,cc,dd
hello.apply(context,["cc","dd"]); //
?
Bind 并不是自己調用函數,它只是在函數調用之前綁定上下文和其他參數。
(function introduce(name, interest) { console.log('Hi! I'm '+ name +' and I like '+ interest +'.'); console.log('The value of this is '+ this +'.') }).bind(window, 'Hammad', 'Cosmology')();?
函數的運行過程
第一階段是創建階段,是函數剛被調用但代碼并未執行的時候。創建階段主要發生了 3 件事。
創建變量對象
創建作用域鏈
設置上下文(this)的值
第二個階段就是代碼執行階段,進行其他賦值操作并且代碼最終被執行。
?
詞法作用域
詞法作用域(靜態作用域)的意思是在函數嵌套中,內層函數可以訪問父級作用域的變量等資源,在定義時就確定。
?
閉包
當內部函數試著訪問外部函數的作用域鏈(詞法作用域之外的變量)時產生閉包。閉包包括它們自己的作用域鏈、父級作用域鏈和全局作用域。
閉包不僅能訪問外部函數的變量,也能訪問外部函數的參數。
即使函數已經return,閉包仍然能訪問外部函數的變量。這意味著return的函數允許持續訪問外部函數的所有資源。
當你的外部函數return一個內部函數,調用外部函數時return的函數并不會被調用。你必須先用一個單獨的變量保存外部函數的調用,然后將這個變量當做函數來調用。
用閉包實現共有作用域和私有作用域:
(function () { // private scope })();?
函數結尾的括號告訴解析器立即執行此函數。我們可以在其中加入變量和函數,外部無法訪問。但如果我們想在外部訪問它們,也就是說我們希望它們一部分是公開的,一部分是私有的。我們可以使用閉包的一種形式,稱為模塊模式(Module Pattern),它允許我們用一個對象中的公有作用域和私有作用域來劃分函數。
模塊模式
var Module = (function() { function privateMethod() { // do something } return { publicMethod: function() { // can call privateMethod(); } }; })(); Module.publicMethod(); // works Module.privateMethod(); // Uncaught ReferenceError: privateMethod is not defined?
Module 的return語句包含了我們的公共函數。私有函數并沒有被return。函數沒有被return確保了它們在 Module 命名空間無法訪問。但我們的共有函數可以訪問我們的私有函數,方便它們使用有用的函數、AJAX 調用或其他東西。
一種習慣是以下劃線作為開始命名私有函數,并返回包含共有函數的匿名對象。這使它們在很長的對象中很容易被管理。向下面這樣:
var Module = (function () { function _privateMethod() { // do something } function publicMethod() { // do something } return { publicMethod: publicMethod, } })();?
立即執行函數表達式(IIFE)
另一種形式的閉包是立即執行函數表達式(Immediately-Invoked Function Expression,IIFE)。這是一種在 window 上下文中自調用的匿名函數,也就是說this的值是window。它暴露了一個單一全局接口用來交互。如下所示:
(function(window) { // do anything })(this);?
?兩段好玩的閉包代碼
1、返回一個函數
function createComparisonFunction(propertyName) { return function(object1, object2){var value1 = object1[propertyName];
var value2 = object2[propertyName];
if (value1 < value2){
return -1;
} else if (value1 > value2){
return 1;
} else {
return 0;
}
}; } var compare = createComparisonFunction("name");
//createComparisonFunction函數返回后,閉包的作用域鏈開始初始化,包含了Comparison作用鏈上的對象;Comparison返回后作用域鏈被銷毀,但是上面的活動對象內存得不到釋放,直到匿名函數被銷毀 var result = compare({ name: "Nicholas" }, { name: "Greg" }); compare=' ';//解除對匿名函數的引用,釋放內存。此時result已經達到目的指向了需要引用的函數
2,循環引用造成的內存泄漏
?
轉載于:https://www.cnblogs.com/yaoyao-sun/p/10365422.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的作用域,上下文,闭包的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [BZOJ 2555] SubStrin
- 下一篇: udp/tcp流程