日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

作用域,上下文,闭包

發布時間:2025/4/16 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 作用域,上下文,闭包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作用域

作用域決定了你的代碼里的變量和其他資源在各個區域中的可見性,為代碼提供了一個安全層級,用戶只能訪問他們當前需要的東西。

在 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的值。可以使用函數方法改變上下文,上下文是執行的時候確定的

在全局作用域中,上下文總是 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,循環引用造成的內存泄漏

var el = document.getElementById('MyElement');var func = function () {// }el.func = func;func.element = el;//通常循環引用發生在為dom元素添加閉包作為expendo的時候。 function init() {var el = document.getElementById('MyElement');el.onclick = function () {//…… }}init();解除引用:function init() {var el = document.getElementById('MyElement');el.onclick = function () {//…… }el = null; }init();

?

轉載于:https://www.cnblogs.com/yaoyao-sun/p/10365422.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的作用域,上下文,闭包的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。