成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

前端筆記(一) 變量,執(zhí)行環(huán)境與作用域,this

elva / 3229人閱讀

摘要:瀏覽器總是運(yùn)行位于作用域鏈頂部的當(dāng)前執(zhí)行上下文。作用域的前端永遠(yuǎn)是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對(duì)象而全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)對(duì)象。調(diào)用棧為了達(dá)到當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。

ECMAScript中的變量值類(lèi)型

基本類(lèi)型 : Number, String, Boolean, Undefined, Null

引用類(lèi)型 : Object, Array, Function, Date, RegExp

在將一個(gè)值賦給變量時(shí)解析器必須確定這個(gè)值是基本類(lèi)型值還是引用類(lèi)型值。

基本數(shù)據(jù)類(lèi)型是按值訪(fǎng)問(wèn)的, 因?yàn)榭梢圆僮鞅4嬖谧兞恐械膶?shí)際的值。

引用類(lèi)型則不同, 它的值是保存在堆內(nèi)存中的對(duì)象, 而JavaScript不允許直接訪(fǎng)問(wèn)內(nèi)存中的位置。

所以在操作對(duì)象時(shí)實(shí)際上是在操作對(duì)象的引用, 即引用類(lèi)型的值是按引用訪(fǎng)問(wèn)的。

基本類(lèi)型的特點(diǎn) :

1.值不會(huì)改變 2. 不可以添加屬性和方法

var name = "BarryAllen";

name.substring(5); //"Allen"
console.log(name) //BarryAllen  

name.identity = "Flash";
console.log(name.identity) //undefined 

name.skill = function() {
    console.log("Running very fast.")
}
name.skill(); //name.skill is not a function


引用類(lèi)型的特點(diǎn) :

1.值可以被修改 2. 可以添加屬性和方法

var obj = {};
obj.name = "BarryAllen";

var change = obj;
change.name = "OliverQueen";
console.log(obj.name); //OliverQueen

obj.identity = "Flash";
console.log(obj.identity) //Flash

obj.skill = function() {
    console.log("Running very fast.")
}
obj.skill(); //Running very fast.

從上面的代碼不難看出在進(jìn)行復(fù)制變量的時(shí)候基本類(lèi)型進(jìn)行的是類(lèi)似創(chuàng)建副本的操作, 而引用類(lèi)型則是對(duì)指向?qū)ο蟮闹羔樀膹?fù)制所以在復(fù)制操作結(jié)束后兩個(gè)變量將引用同一個(gè)對(duì)象。因此改變其中一個(gè)變量就會(huì)影響到另一個(gè)變量。

參數(shù)的傳遞

ECMAScript中規(guī)定所有函數(shù)的參數(shù)都是按值傳遞的。

function setAge(obj) {
    obj.age = 18;
    obj = {};
    obj.age = 25;
}
var person = {}
setAge(person);
console.log(person.age) //18

在函數(shù)內(nèi)部重新聲明了對(duì)象并修改了obj.age 的值, 若參數(shù)傳遞是按引用傳遞的那么person.age 應(yīng)該輸出25, 但事實(shí)卻不是這樣。由于此時(shí)對(duì)象是按值傳遞, 故原始的引用仍然未變。事實(shí)上在函數(shù)被執(zhí)行完畢后這個(gè)新創(chuàng)建的局部對(duì)象就會(huì)被立即銷(xiāo)毀。

檢測(cè)類(lèi)型

typeof 用于檢測(cè)基本類(lèi)型

instanceof 在檢測(cè)引用類(lèi)型時(shí), 用于判斷它是什么類(lèi)型的對(duì)象( 因?yàn)樗幸妙?lèi)型的值都是Object的實(shí)例 )。

var num = 786;
var bol = true;
var name = "Violet";
console.log(typeof num +"~"+ typeof bol +"~"+ typeof name); //number~boolean~string

var arr = [];
var func = new Function();
console.log(arr instanceof Array) //true
console.log(func instanceof Function) //true
執(zhí)行環(huán)境(Execution Context)與作用域

執(zhí)行環(huán)境也被稱(chēng)為執(zhí)行上下文, 每一個(gè)執(zhí)行環(huán)境中都有一個(gè)關(guān)聯(lián)的變量對(duì)象, 環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。

在Javascript中有三種代碼的執(zhí)行環(huán)境 :

全局執(zhí)行環(huán)境 --- 默認(rèn)的最外圍的執(zhí)行環(huán)境, 在瀏覽器中其關(guān)聯(lián)的變量對(duì)象被認(rèn)為是window對(duì)象

函數(shù)執(zhí)行環(huán)境 --- 每當(dāng)調(diào)用一個(gè)函數(shù)時(shí), 一個(gè)新的執(zhí)行上下文就會(huì)被創(chuàng)建出來(lái)

Eval --- 接受字符串作為參數(shù), 并將其作為javascript代碼去運(yùn)行, eval函數(shù)并不會(huì)創(chuàng)建新的作用域

每次新創(chuàng)建的一個(gè)執(zhí)行上下文會(huì)被添加到作用域鏈的頂部,有時(shí)也稱(chēng)為執(zhí)行或調(diào)用棧。瀏覽器總是運(yùn)行位于作用域鏈頂部的當(dāng)前執(zhí)行上下文。一旦完成,當(dāng)前執(zhí)行上下文將從棧頂被移除并且將控制權(quán)歸還給之前的執(zhí)行上下文。

下面來(lái)詳細(xì)講解一下函數(shù)執(zhí)行環(huán)境的建立過(guò)程:

建立階段

建立arguments對(duì)象, 參數(shù), 函數(shù), 變量 ( 注意創(chuàng)建的順序 !)

建立作用域鏈

確定this的值

代碼執(zhí)行階段

變量賦值

函數(shù)引用

執(zhí)行其他代碼

(function (obj) {
  console.log(typeof obj); //number
  console.log(typeof foo); //function
  console.log(typeof boxer); //undefined
  var foo = "Mashics";
   function foo() {
      document.write("This is a function.");
   }
  var boxer = function() {
      document.write("I am a boxer.");
   }
})(666);

這段代碼充分說(shuō)明了函數(shù)執(zhí)行環(huán)境建立再到執(zhí)行的過(guò)程, 即首先是參數(shù)的創(chuàng)建, 然后再是在函數(shù)體內(nèi)去尋找函數(shù)的聲明, 最后是變量聲明。值得注意的是當(dāng)javascript引擎在尋找函數(shù)聲明時(shí)首先找到了foo 這個(gè)函數(shù), 因而之后定義的變量則不會(huì)重新覆蓋其屬性, 引擎接下來(lái)就開(kāi)始查找具體代碼段里面的變量聲明并添加到關(guān)聯(lián)變量對(duì)象的屬性中,并將其賦值為undefined , 因而像變量提升這種經(jīng)典的問(wèn)題又可以從執(zhí)行環(huán)境創(chuàng)建過(guò)程的角度來(lái)回答并解決了。

作用域鏈與閉包

當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí), 會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈, 其用途就是保證對(duì)執(zhí)行環(huán)境有權(quán)訪(fǎng)問(wèn)的所有變量和函數(shù)的有序訪(fǎng)問(wèn)。作用域的前端永遠(yuǎn)是當(dāng)前執(zhí)行代碼所在環(huán)境的變量對(duì)象, 而全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)對(duì)象。在進(jìn)行變量查找的時(shí)候就是通過(guò)作用域鏈一級(jí)一級(jí)的向上查找。而閉包中的一部分特性則是由作用域鏈這個(gè)重要特性決定的。

var outer = "Margin";
function foo() {
  var mider = "Padding";
    function baz() {
       var inner = "Content";
       console.log( "Gotcha! " + outer + " and " + mider + " . " );
    }
  return baz;
}
var fn = foo();
fn(); //Gotcha! Margin and Padding . 
console.log(inner); //inner is not defined.

這段代碼是一個(gè)簡(jiǎn)單的閉包, 但它卻說(shuō)明了作用域鏈中最重要的特性:

??!即內(nèi)部環(huán)境可以通過(guò)作用域鏈訪(fǎng)問(wèn)所有外部環(huán)境, 但外部環(huán)境不能訪(fǎng)問(wèn)內(nèi)部環(huán)境中的任何變量和函數(shù) ?。?/p>

PS : 另外再解釋一下幾個(gè)容易令人混淆或者說(shuō)是難懂的概念。

變量對(duì)象與活動(dòng)對(duì)象

變量對(duì)象在執(zhí)行環(huán)境的建立階段被創(chuàng)建, 在未進(jìn)入執(zhí)行階段之前其中的屬性不能被訪(fǎng)問(wèn), 而當(dāng)其進(jìn)入執(zhí)行階段后變量對(duì)象變?yōu)榛顒?dòng)對(duì)象, 接下來(lái)就可以進(jìn)行執(zhí)行階段中的步驟了。

作用域與作用域鏈

作用域與執(zhí)行環(huán)境是兩個(gè)完全不同的概念, javascript代碼執(zhí)行的過(guò)程其實(shí)有兩個(gè)階段即代碼編譯階段和代碼執(zhí)行階段, 作用域是在編譯階段創(chuàng)建的一套規(guī)則, 用來(lái)管理引擎如何在當(dāng)前作用域以及嵌套的子作用域中根據(jù)標(biāo)識(shí)符名稱(chēng)進(jìn)行變量查找, 而執(zhí)行上下文的創(chuàng)建則是在代碼執(zhí)行階段進(jìn)行的。作用域鏈?zhǔn)怯梢幌盗凶兞繉?duì)象組成, 我們可以在這個(gè)單向通道中, 查詢(xún)變量對(duì)象中的標(biāo)識(shí)符, 這樣就可以訪(fǎng)問(wèn)到上一層作用域中的變量了。

this詳解

在理解this的綁定過(guò)程之前, 必須要理解調(diào)用棧和調(diào)用位置這兩個(gè)概念, 因?yàn)閠his的綁定完全取決于從調(diào)用棧中分析出的調(diào)用位置。而調(diào)用位置就在當(dāng)前正在執(zhí)行的函數(shù)的前一個(gè)調(diào)用中。

調(diào)用棧:為了達(dá)到當(dāng)前執(zhí)行位置所調(diào)用的所有函數(shù)。

調(diào)用位置:函數(shù)在代碼中被調(diào)用的位置( 而不是聲明的位置 )。

function head() {
   //當(dāng)前調(diào)用棧為head
   console.log("first");
   body(); //body的調(diào)用位置 --> head
}
function body() {
   //當(dāng)前調(diào)用棧為head -> body
   console.log("second");
   footer(); //footer的調(diào)用位置 --> body
}
function footer() {
  //當(dāng)前的調(diào)用棧為head -> body -> footer
   console.log("third");
}
head();  //head的調(diào)用位置 --> 全局作用域
this綁定規(guī)則:

默認(rèn)綁定

隱式綁定

顯示綁定

new綁定

默認(rèn)綁定

當(dāng)函數(shù)獨(dú)立調(diào)用, 即直接使用不帶任何修飾的函數(shù)引用進(jìn)行調(diào)用時(shí)this使用默認(rèn)綁定, 此時(shí)this指向全局對(duì)象。

var a = 2;
function foo() {
   console.log( this.a );
}
foo(); // 2

隱式綁定

當(dāng)函數(shù)引用有上下文對(duì)象時(shí), 隱式綁定規(guī)則會(huì)把函數(shù)調(diào)用中的this綁定到這個(gè)上下文對(duì)象。

var obj = {
   a : 2,
   foo : foo
}
function foo() {
   console.log( this.a );
}
obj.foo(); //2

因?yàn)檎{(diào)用foo()時(shí)this被綁定到obj, 因此這里的this 相當(dāng)于obj 。

隱式丟失

當(dāng)隱式綁定的函數(shù)被顯式或者隱式賦值時(shí)會(huì)丟失綁定對(duì)象, 從而把this綁定到全局對(duì)象上或者undefined上。而在回調(diào)函數(shù)中的this綁定會(huì)丟失也正是因?yàn)閰?shù)傳遞其實(shí)就是一種隱式賦值。

var a = "Global";
var obj = {
   a : 2,
   foo : foo
}
function foo() {
   console.log( this.a );
}
var bar = obj.foo;
bar(); //Global ->顯示賦值

function doFoo(fn) {
   fn();
}
doFoo( obj.foo ); //Global ->隱式賦值

setTimeout(obj.foo, 1000); //Global ->內(nèi)置函數(shù)中的隱式賦值,類(lèi)似于下面這段代碼

function setTimeout(fn, delay) {
  //等待delay毫秒
  fn();
}

顯式綁定

通過(guò)Function.prototype 中的call , apply , bind 來(lái)直接指定this的綁定對(duì)象。

call和apply都是立即執(zhí)行的函數(shù), 并且接受參數(shù)的形式不同。

bind則是創(chuàng)建一個(gè)新的包裝函數(shù)并且返回, 而不是執(zhí)行。

var obj = {
   a : 2
}
function foo() {
   console.log( this.a );
}
var bar = function() {
   foo.call(obj);
}
bar(); //2  -->硬綁定

function calculate(b, c) {
   console.log(this.a, b, c);
   return (this.a * b) + c;
}
var excute = function() {
   return calculate.apply(obj, arguments); //apply方法可接受參數(shù)并將變量傳遞到下層函數(shù)
}
excute(5,10); //2 5 10 20

var baz = calculate.bind(obj); //bind方法將this綁定到obj對(duì)象上
baz(8,5); //2 8 5 21

new綁定

在JavaScript中構(gòu)造函數(shù)只是一些使用new操作符時(shí)被調(diào)用的普通函數(shù), 即發(fā)生構(gòu)造函數(shù)調(diào)用時(shí)會(huì)執(zhí)行以下操作:

創(chuàng)建一個(gè)全新的對(duì)象

新對(duì)象被執(zhí)行[[Prototype]]連接

新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this

若函數(shù)沒(méi)有返回對(duì)象, new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象

function Foo(a) {
    this.a = a;
}
var bar = new Foo(6);
console.log( bar.a ); //6

優(yōu)先級(jí)

new綁定 > 顯式綁定 > 隱式綁定 > 默認(rèn)綁定

this與箭頭函數(shù)

ES6中的箭頭函數(shù)并不使用this的四種標(biāo)準(zhǔn)原則,它是根據(jù)外層( 函數(shù)或者全局 )作用域來(lái)決定this。

先來(lái)看下一種常見(jiàn)的this綁定丟失情景:

function foo() {
   setTimeout(function() {
     console.log( this.a );
   },1000);
}
var obj = {
   a : 2
}
foo.call(obj); //undefined 

這里由于setTimeout中發(fā)生的隱式丟失因而this應(yīng)用了默認(rèn)規(guī)則, 因而輸出undefined 。那么如何將this綁定到我們想要的obj對(duì)象上呢?

var obj = {
   a : 2
}
function foo() {
   setTimeout( () => {
      console.log( this.a );
   },1000);
}
foo.call(obj) //2

顯然箭頭函數(shù)中的this 在詞法上繼承了foo , 因而它會(huì)捕獲調(diào)用時(shí)foo的this, 即this被綁定到obj對(duì)象上。

參考書(shū)籍:
《JavaScript高級(jí)程序設(shè)計(jì)》
《你不知道的JavaScript》(上)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92824.html

相關(guān)文章

  • 重學(xué)前端學(xué)習(xí)筆記(十八)--JavaScript的閉包和執(zhí)行上下文

    摘要:申明與賦值立即執(zhí)行的函數(shù)表達(dá)式,通過(guò)創(chuàng)建一個(gè)函數(shù),并且立即執(zhí)行,來(lái)構(gòu)造一個(gè)新的域,從而控制的范圍。函數(shù)接受一個(gè)的形參,該參數(shù)是一個(gè)對(duì)象引用,并執(zhí)行了。在最新的標(biāo)準(zhǔn)中,引入了一個(gè)新概念。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的專(zhuān)欄...

    silencezwm 評(píng)論0 收藏0
  • 重學(xué)前端學(xué)習(xí)筆記(十八)--JavaScript的閉包和執(zhí)行上下文

    摘要:申明與賦值立即執(zhí)行的函數(shù)表達(dá)式,通過(guò)創(chuàng)建一個(gè)函數(shù),并且立即執(zhí)行,來(lái)構(gòu)造一個(gè)新的域,從而控制的范圍。函數(shù)接受一個(gè)的形參,該參數(shù)是一個(gè)對(duì)象引用,并執(zhí)行了。在最新的標(biāo)準(zhǔn)中,引入了一個(gè)新概念。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的專(zhuān)欄...

    liaorio 評(píng)論0 收藏0
  • 重學(xué)前端學(xué)習(xí)筆記(十八)--JavaScript的閉包和執(zhí)行上下文

    摘要:申明與賦值立即執(zhí)行的函數(shù)表達(dá)式,通過(guò)創(chuàng)建一個(gè)函數(shù),并且立即執(zhí)行,來(lái)構(gòu)造一個(gè)新的域,從而控制的范圍。函數(shù)接受一個(gè)的形參,該參數(shù)是一個(gè)對(duì)象引用,并執(zhí)行了。在最新的標(biāo)準(zhǔn)中,引入了一個(gè)新概念。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開(kāi)的一個(gè)專(zhuān)欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過(guò)程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的專(zhuān)欄...

    caikeal 評(píng)論0 收藏0
  • [學(xué)習(xí)筆記] JavaScript 作用

    摘要:全局執(zhí)行環(huán)境的變量對(duì)象始終是作用域鏈中的最后一個(gè)變量對(duì)象。綜上,每個(gè)函數(shù)對(duì)應(yīng)一個(gè)執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境對(duì)應(yīng)一個(gè)變量對(duì)象,而多個(gè)變量對(duì)象構(gòu)成了作用域鏈,如果當(dāng)前執(zhí)行環(huán)境是函數(shù),那么其活動(dòng)對(duì)象在作用域鏈的前端。 1.幾個(gè)概念 先說(shuō)幾個(gè)概念:函數(shù)、執(zhí)行環(huán)境、變量對(duì)象、作用域鏈、活動(dòng)對(duì)象。這幾個(gè)東東之間有什么關(guān)系呢,往下看~ 函數(shù) 函數(shù)大家都知道,我想說(shuō)的是,js中,在函數(shù)內(nèi)部有兩個(gè)特殊...

    ?xiaoxiao, 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<