搜尋
首頁web前端js教程JavaScript 變數、作用域及記憶體_javascript技巧

JS變數是鬆散型的(不強制類型)本質,決定了它只是在特定時間用於保存特定值的一個名字而已;
由於不存在定義某個變數必須要保存何種資料型別值的規則,變數的值及其資料型別可以在腳本的生命週期內改變;

一 變數及作用域
1.基本型別與引用型別

// JS變數包含兩種不同的資料型別的值:基本型別值與參考型別值;

// 1.基本型別值:保存在堆疊記憶體中的簡單資料段;即這種值完全保存在記憶體中的一個位置;
// 基本型別值包含:Undefined|Null|Boolean|Number|String;
// 這些型別在記憶體中佔有固定大小的空間;它們的值保存在堆疊空間,我們按值來存取;

// 2.引用型別值:保存在堆記憶體中的物件(可能由多個值構成),即變數中保存的其實只是一個指標,這個指標指向記憶體中的另一個位置,該位置保存物件;
// 引用型別的值的大小不固定,因此不能保存在棧內存,必須保存在堆內存中;但可以將引用類​​型的值的內存地址保存在棧內存中;
// 當查詢引用型別的變數時,先從堆疊記憶體讀取記憶體位址,然後透過位址找到堆疊記憶體中的值;=>按引用存取;

2.動態屬性

// 定义基本类型值和引用类型值的方式相似:创建一个变量并为该变量赋值;
// 但当这个值保存到变量中以后,对不同类型值可以执行的操作则不一样;
  var box = new Object();           // 创建引用类型;
  box.name = 'lee';              // 新增一个属性;
  console.log(box.name);           // =>lee;

  var box = 'lee';              // 创建基本类型
  box.age = 15;                // 给基本类型添加属性;
  console.log(box.age);            // =>undefined;

3.複製變數值

// 在变量复制方面,基本类型和引用类型也有所不同;
// 基本类型赋值的是值本身;
  var box = 'lee';              // 在栈内存中生成一个box'lee';
  var box2 = box;               // 在栈内存中再生成一个box2'lee';
  // box和box2完全独立;两个变量分别操作时互不影响;

// 引用类型赋值的是地址;
  var box = new Object();          // 创建一个引用类型;box在栈内存中;而Object在堆内存中;
  box.name = 'lee';             // 新增一个属性;
  var box2 = box;              // 把引用地址赋值给box2;box2在栈内存中;
  // box2=box,因为它们指向的是同一个对象;
  // 如果这个对象中的name属性被修改了,box.name和box2.name输出的值都会被修改掉;

4.傳遞參數

// JS中所有函数的参数都是按值传递的,即参数不会按引用传递;
  function box(num){             // 按值传递,传递的参数是基本类型;
    num +=10;               // 这里的num是局部变量,全局无效;
    return num;
  }
  var num = 50;
  var result = box(num);
  console.log(result);           // 60;
  console.log(num);             // 50;

  function box(num){
    return num;
  }
  console.log(num);             // num is not defined;

  function box(obj){
    obj.name = 'lee';
    var obj = new Object();       // 函数内部又创建了一个对象,它是局部变量;但在函数结束时被销毁了;
    obj.name = 'Mr';           // 并没有替换掉原来的obj;
  }
  var p = new Object();
  box(p);                 // 变量p被传递到box()函数中之后就被复制给了obj;在函数内部,obj和p访问的是同一个对象;
  console.log(p.name);           // =>lee;

  // JS函数的参数都将是局部变量;也就是说,没有按引用传递;

5.偵測類型

// 要检测一个变量的类型,通过typeof运算符类判断;
// 多用来检测基本类型;
  var box = 'lee';
  console.log(typeof box);          // =>string;

// 要检测变量是什么类型的对象,通过instanceof运算符来查看;
  var box = [1,2,3];
  console.log(box instanceof Array);     // =>true;
  var box2 = {};
  console.log(box2 instanceof Object);
  var box3 = /g/;
  console.lgo(box3 instanceof RegExp);
  var box4 = new String('lee');
  console.log(box4 instanceof String);   // =>true;是否是字符串对象;

  var box5 = 'string';
  console.log(box5 instanceof String);   // =>false;
  // 当使用instanceof检查基本类型的值时,它会返回false;

6.執行環境及作用域

// 执行环境:定义了变量或函数有权访问的其他数据,决定了它们各自的行为;
// 在Web浏览器中,全局执行环境=window对象;
// 因此所有的全局变量和函数都是作为window对象的属性和方法创建的;
  var box = 'blue';             // 声明一个全局变量;
  function setBox(){
    console.log(box);           // 全局变量可以在函数里访问;
  }  
  setBox();                 // 执行函数;
  // 全局的变量=window对象的属性;
  // 全局的函数=window对象的方法;

// PS:当执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁;
// 如果是在全局环境下,需要程序执行完毕,或者网页被关闭才会销毁;

// PS:每个执行环境都有一个与之关联的变量对象,就好比全局的window可以调用全局变量和全局方法一样;
// 局部的环境也有一个类似window的变量对象,环境中定义的所有变量和函数都保存在这个对象中;
// (我们无法访问这个变量对象,但解析器会处理数据时后台使用它);
  var box = 'blue';
  function setBox(){
    var box = 'red';           // 这里是局部变量,在当前函数体内的值是'red';出了函数体就不被认知;
    console.log(box);
  }  
  setBox();
  console.log(box);

// 通过传参可以替换函数体内的局部变量,但作用域仅限在函数体内这个局部环境;
  var box = 'blue';
  function setBox(box){           // 通过传参,将局部变量替换成了全局变量;
    alert(box);              // 此时box的值是外部调用时传入的参数;=>red;
  }
  setBox('red');
  alert(box);

// 如果函数体内还包含着函数,只有这个内函数才可以访问外一层的函数的变量;
// 内部环境可以通过作用域链访问所有的外部环境,但外部环境不能访问内部环境中的任何变量和函数;
  var box = 'blue';
  function setBox(){
    function setColor(){
      var b = 'orange';
      alert(box);
      alert(b);
    }
    setColor();              // setColor()的执行环境在setBox()内;
  }
  setBox();
  // PS:每个函数被调用时都会创建自己的执行环境;当执行到这个函数时,函数的环境就会被推到环境栈中去执行,而执行后又在环境栈中弹出(退出),把控制权交给上一级的执行环境;

  // PS:当代码在一个环境中执行时,就会形成一种叫做作用域链的东西;它的用途是保证对执行环境中有访问权限的变量和函数进行有序访问;作用域链的前端,就是执行环境的变量对象;

7.延長作用域鏈

// 有些语句可以在作用域链的前端临时增加一个变量对象,该变量对象会在代码执行后被移除;
// with语句和try-catch语句;这两个语句都会在作用域链的前端添加一个变量对象;
// with语句:会将指定的对象添加到作用域链中; 
// catch语句:会创建一个新的变量对象,其中包含的是被抛出的错误对象的声明;
  function buildUrl(){
    var qs = '?debug=true';
    with(location){            // with语句接收的是location对象,因此变量对象中就包含了location对象的所有属性和方法;
      var url = href+qs;        // 而这个变量对象被添加到了作用域链的前端;
    };
    return url;
  }

8.沒有區塊級作用域

// 块级作用域:表示诸如if语句等有花括号封闭的代码块,所以,支持条件判断来定义变量;
  if(true){                 // if语句代码块没有局部作用域;
    var box = 'lee';           // 变量声明会将变量添加到当前的执行环境(在这里是全局环境);
  }
  alert(box);

  for(var i=0; i<10; i++){         // 创建的变量i即使在for循环执行结束后,也依旧会存在与循环外部的执行环境中;
    var box = 'lee';
  }
  alert(i);
  alert(box);

  function box(num1,num2){
    var sum = num1+num2;         // 此时sum是局部变量;如果去掉var,sum就是全局变量了;
    return sum;
  }
  alert(box(10,10));
  alert(sum);                // sum is not defined;访问不到sum;
  // PS:不建议不使用var就初始化变量,因为这种方法会导致各种意外发生;

// 一般确定变量都是通过搜索来确定该标识符实际代表什么;搜索方式:向上逐级查询;
  var box = 'blue';
  function getBox(){
    return box;              // 此时box是全局变量;如果是var box='red',那就变成局部变量了;
  }
  alert(getBox());              
  // 调用getBox()时会引用变量box;
  // 首先,搜索getBox()的变量对象,查找名为box的标识符;
  // 然后,搜索继续下一个变量对象(全局环境的变量对象),找到了box标识符;
// PS:变量查询中,访问局部变量要比全局变量更快,因为不需要向上搜索作用域链;

二 記憶體問題

// JS具有自动垃圾收集机制,执行环境会负责管理代码执行过程中使用的内存;它会自行管理内存分配及无用内存的回收;

// JS最常用的垃圾收集方式就是标记清除;垃圾收集器会在运行的时候给存储在内存中的变量加上标记;
// 然后,它会去掉环境中正在使用的变量的标记,而没有被去掉标记的变量将被视为准备删除的变量;
// 最后,垃圾收集器完成内存清理工作,销毁那些标记的值并回收他们所占用的内存空间;

// 垃圾收集器是周期性运行的,这样会导致整个程序的性能问题;
// 比如IE7以前的版本,他的垃圾收集器是根据内存分配量运行的,比如256个变量就开始运行垃圾收集器,这样就不得不频繁地运行,从而降低了性能;

// 一般来说,确保占用最少的内存可以让页面获得更好的性能;
// 最佳方案:一旦数据不再使用,将其值设置为null来释放引用,这个做法叫做解除引用;
  var o = {
    name:'lee';
  };
  o = null;               // 解除对象引用,等待垃圾收集器回收;

三 小結

1.變數
// JS變數可以保存兩種類型的值:基本型別值和參考型別值;它們具有以下特點:
// 1.基本型別值在記憶體中佔據固定大小的空間,因此被保存在堆疊記憶體中;
// 2.從一個變數複製基本型別的值給另一個變數會建立這個值的一個副本;
// 3.引用型別的值是物件,保存在堆疊記憶體;
// 4.包含引用型別值的變數實際上包含的並不是物件本身,而是一個指向該物件的指標;
// 5.從一個變數複製引用型別的值給另一個變數的其實是指標,因此兩個變數最後都指向用一個物件;
// 6.決定一個值是哪一種基本型別可以使用typeof運算子;而決定一個值是哪一種參考型別可以使用instanceof操作符;

2.作用域
// 所有變數都存在於一個執行環境(作用域)中,這個執行環境決定了變數的生命週期,以及哪一部分程式碼可以存取其中的變數;
// 1.執行環境有全域執行環境與函數執行環境之分;
// 2.每次進入一個新執行環境,都會建立一個用於搜尋變數和函數的作用域鏈;
// 3.函數的局部環境不僅有權利存取函數作用域中的變量,而且有權存取其父環境,甚至全域環境;
// 4.變數的執行環境有助於確定應該適當釋放記憶體;

3.內存
// JS自動垃圾收集機制
// 1.離開作用域的值將自動標記為可以回收,因此將在垃圾收集期間被刪除;
// 2.為了確保有效地回收記憶體,應該及時解除不再使用的全域物件/全域物件屬性以及循環引用變數的參考;

陳述
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

了解JavaScript引擎:實施詳細信息了解JavaScript引擎:實施詳細信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python vs. JavaScript:學習曲線和易用性Python vs. JavaScript:學習曲線和易用性Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

Python vs. JavaScript:社區,圖書館和資源Python vs. JavaScript:社區,圖書館和資源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社區、庫和資源方面的對比各有優劣。 1)Python社區友好,適合初學者,但前端開發資源不如JavaScript豐富。 2)Python在數據科學和機器學習庫方面強大,JavaScript則在前端開發庫和框架上更勝一籌。 3)兩者的學習資源都豐富,但Python適合從官方文檔開始,JavaScript則以MDNWebDocs為佳。選擇應基於項目需求和個人興趣。

從C/C到JavaScript:所有工作方式從C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

JavaScript引擎:比較實施JavaScript引擎:比較實施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

超越瀏覽器:現實世界中的JavaScript超越瀏覽器:現實世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在現實世界中的應用包括服務器端編程、移動應用開發和物聯網控制:1.通過Node.js實現服務器端編程,適用於高並發請求處理。 2.通過ReactNative進行移動應用開發,支持跨平台部署。 3.通過Johnny-Five庫用於物聯網設備控制,適用於硬件交互。

使用Next.js(後端集成)構建多租戶SaaS應用程序使用Next.js(後端集成)構建多租戶SaaS應用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技術工具構建了功能性的多租戶SaaS應用程序(一個Edtech應用程序),您可以做同樣的事情。 首先,什麼是多租戶SaaS應用程序? 多租戶SaaS應用程序可讓您從唱歌中為多個客戶提供服務

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.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

VSCode Windows 64位元 下載

VSCode Windows 64位元 下載

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

MantisBT

MantisBT

Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強大的PHP整合開發環境

Dreamweaver Mac版

Dreamweaver Mac版

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。