溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

JavaScript中的對象有哪些

發(fā)布時間:2021-11-20 13:57:20 來源:億速云 閱讀:120 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要講解了“JavaScript中的對象有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“JavaScript中的對象有哪些”吧!

An object

ECMAScript, 是一門高級抽象面向?qū)ο蟮恼Z言,用以處理Objects. 當(dāng)然,也有原生類型,但是必要時,也需要轉(zhuǎn)換成object.

Object是一個屬性的集合,并且都擁有一個單獨(dú)的原型對象[prototype object]. 這個原型對象[prototype object]可以是一個object或者null值。

讓我們舉一個Object的例子。首先我們要清楚,一個Object的prototype是一個內(nèi)部的[[prototype]]屬性的引用。不過一般來說,我們會使用____ 下劃線來代替雙括號,例如__prototype__

看這段代碼

var foo = {
  x: 10,
  y: 20};

如上結(jié)構(gòu)有兩個顯式的屬性[explicit own properties]和一個自帶隱式的 __proto__ 屬性[implicit
__proto__ property],也就是foo的prototype.

這個property有什么用處呢?我們來看一個原型鏈[prototype chain]的例子。

A prototype chain

Prototype對象也是對象類型的,也會有自己的prototypes。如果這個prototype仍然存在一個非空的prototype,那么這樣一直搜尋下去,就形成了一個原型鏈[prototype chain]。

原型鏈?zhǔn)怯梢幌盗杏脕砝^承和共享屬性的對象組成有限的對象鏈。

考慮這樣的一個情況。

有兩個對象,只有一小部分的方法或者屬性不同,其余的都是一樣的。很明顯,在一個好的設(shè)計(jì)模式中,我們會需要重用那部分相同的,而不是在每個對象中重復(fù)定義那些相同的方法或者屬性。在基于類[class-based]的系統(tǒng)中,這些重用部分被稱為類的繼承
– 相同的部分放入class A,然后class B和class C從A繼承,并且擁有各自的獨(dú)特的東西。

ECMAScript沒有類的概念。但是,重用[reuse]這個理念沒什么不同(某些方面,甚至比class-更加靈活),可以由prototype chain原型鏈來實(shí)現(xiàn)。這種繼承被稱為delegation
based inheritance-基于繼承的委托,或者更通俗一些,叫做原型繼承。

上述的Classes A,B,C,在ECMAScript中可以創(chuàng)建三個對象:a,b,c. 由a來負(fù)責(zé)b和c相同的部分,而b和c則負(fù)責(zé)各自不同的獨(dú)特的東西。

var a = {  x: 10,  calculate: function (z) {return this.x + this.y + z
  }
};var b = {  y: 20,  __proto__: a};var c = {  y: 30,  __proto__: a};// call the inherited methodb.calculate(30); // 60c.calculate(40); // 80

這樣看上去是不是很簡單啦。b和c可以使用a中定義的calculate方法,這就是有原型鏈來[prototype chain]實(shí)現(xiàn)的。

我們來看一下原理:如果在對象b中找不到calculate方法(也就是對象b中沒有這個calculate屬性), 那么就會沿著原型鏈開始找。如果這個calculate方法在b的prototype中沒有找到,那么就會沿著原型鏈找到a的prototype,一直遍歷完整個原型鏈。記住,一旦找到,就返回第一個找到的屬性或者方法。因此,第一個找到的屬性成為繼承屬性。如果遍歷完整個原型鏈,仍然沒有找到,那么就會返回undefined.

注意一點(diǎn),this這個值在一個繼承機(jī)制中,仍然是指向它原本屬于的對象,而不是從原型鏈上找到它時,它所屬于的對象。例如,以上的例子,this.y是從b和c中獲取的,而不是a。當(dāng)然,你也發(fā)現(xiàn)了this.x是從a取的,因?yàn)槭峭ㄟ^原型鏈機(jī)制找到的。

如果一個對象的prototype沒有顯示的聲明過或者說定義過,那么__prototype__的默認(rèn)值就是object.prototype, 而object.prototype也會有一個__prototype__, 這個就是原型鏈的終點(diǎn)了,被設(shè)置為null.

下面的圖示就是表示了上述a,b,c的關(guān)系

我們再考慮一種情況。有時候,我們需要對象使用相同的或者相似的結(jié)構(gòu)(例如相同的屬性集),但是不同的值。在這種情況下,我們可以考慮使用構(gòu)造函數(shù)[constructor function],是一種特定結(jié)構(gòu)構(gòu)造的對象。

Constructor

除了可以構(gòu)造特定對象,構(gòu)造函數(shù)[constructor]還有一個有用的功能 – 為一個新建對象創(chuàng)建一個原型對象。這個原型對象放置在構(gòu)造函數(shù)的原型[ConstrutorFunction.prototype]中。

我們用構(gòu)造函數(shù)重寫一下上述的例子。

// a constructor functionfunction Foo(y) {  // which may create objects
  // by specified pattern: they have after
  // creation own "y" property
  this.y = y;
}// also "Foo.prototype" stores reference// to the prototype of newly created objects,// so we may use it to define shared/inherited// properties or methods, so the same as in// previous example we have:// inherited property "x"Foo.prototype.x = 10;// and inherited method "calculate"Foo.prototype.calculate = function (z) {  return this.x + this.y + z;
};// now create our "b" and "c"// objects using "pattern" Foovar b = new Foo(20);var c = new Foo(30);// call the inherited methodb.calculate(30); // 60c.calculate(40); // 80// let's show that we reference// properties we expectconsole.log(  b.__proto__ === Foo.prototype, // true
  c.__proto__ === Foo.prototype, // true

  // also "Foo.prototype" automatically creates
  // a special property "constructor", which is a
  // reference to the constructor function itself;
  // instances "b" and "c" may found it via
  // delegation and use to check their constructor

  b.constructor === Foo, // true
  c.constructor === Foo, // true
  Foo.prototype.constructor === Foo // true

  b.calculate === b.__proto__.calculate, // true
  b.__proto__.calculate === Foo.prototype.calculate // true);

上述的代碼是如下的關(guān)系

上述的圖示可以看出來,每一個object都有一個prototype. 構(gòu)造函數(shù)Foo也擁有自己的__proto__, 也就是Function.prototype, 而Function.prototype的__proto__指向了Object.prototype. 因此,F(xiàn)oo.prototype只是一個顯式的屬性,也就是b和c的__proto__屬性。

針對這個內(nèi)容更完整和詳細(xì)的可以在第七章ES3系列中找到。有兩個部分: Chapter 7.1. OOP. The general theory(各種OOP的原理和它們與ECMAScript的對比),還有Chapter
7.2. OOP. ECMAScript implementation(闡述如何將OOP的概念引入到ECMAScript中)

現(xiàn)在,我們已經(jīng)了解了基本的object原理,那么我們接下去來看看ECMAScript里面的程序執(zhí)行環(huán)境[runtime program execution]. 這就是通常稱為的“執(zhí)行上下文堆?!盵execution
context stack]。每一個元素都可以抽象的理解為object。你也許發(fā)現(xiàn)了,沒錯,在ECMAScript中,幾乎處處都能看到object的身影。

Execution context stack

在ECMASscript中的代碼有三種類型:global, function和eval。

每一種代碼的執(zhí)行都需要依賴自身的上下文。當(dāng)然global的上下文可能涵蓋了很多的function和eval的實(shí)例。函數(shù)的每一次調(diào)用,都會進(jìn)入函數(shù)執(zhí)行中的上下文,并且來計(jì)算函數(shù)中變量等的值。eval函數(shù)的每一次執(zhí)行,也會進(jìn)入eval執(zhí)行中的上下文,判斷應(yīng)該從何處獲取變量的值。

注意,一個function可能產(chǎn)生無限的上下文環(huán)境,因?yàn)橐粋€函數(shù)的調(diào)用(甚至遞歸)都產(chǎn)生了一個新的上下文環(huán)境。

function foo(bar) {}// call the same function,// generate three different// contexts in each call, with// different context state (e.g. value// of the "bar" argument)foo(10);foo(20);foo(30);

一個執(zhí)行上下文可以激活另一個上下文,就好比一個函數(shù)調(diào)用了另一個函數(shù)(或者全局的上下文調(diào)用了一個全局函數(shù)),然后一層一層調(diào)用下去。邏輯上來說,這種實(shí)現(xiàn)方式是棧,我們可以稱之為上下文堆棧。

例如A上下文激活了B的上下文,那么A稱為caller,B稱為callee. 一個callee同時也可能是另一個callee的caller。(例如一個全局上下文中的function又一次調(diào)用了它的內(nèi)部函數(shù)。)

當(dāng)一個caller激活了一個callee,那么這個caller就會暫停它自身的執(zhí)行,然后將控制權(quán)交給這個callee. 于是這個callee被放入堆棧,稱為進(jìn)行中的上下文[running/active
execution context]. 當(dāng)這個callee的上下文結(jié)束之后,會把控制權(quán)再次交給它的caller,然后caller會在剛才暫停的地方繼續(xù)執(zhí)行。在這個caller結(jié)束之后,會繼續(xù)觸發(fā)其他的上下文。一個callee可以用return或者例外退出(exit with an exception)結(jié)束它自身的上下文.

所有的ECMAScript的程序執(zhí)行都可以看做是一個執(zhí)行上下文堆棧[execution context (EC) stack]。堆棧的頂部就是處于激活狀態(tài)的上下文。

當(dāng)一段程序開始時,會先進(jìn)入全局執(zhí)行上下文環(huán)境[global execution context], 這個也是堆棧中最底部的元素。此全局程序會開始初始化,初始化生成必要的對象[objects]和函數(shù)[functions].
在此全局上下文執(zhí)行的過程中,它可能會激活一些方法(當(dāng)然是已經(jīng)初始化過的),然后進(jìn)入他們的上下文環(huán)境,然后將新的元素加入堆棧。在這些初始化都結(jié)束之后,這個系統(tǒng)會等待一些事件(例如用戶的鼠標(biāo)點(diǎn)擊等),會觸發(fā)一些方法,然后進(jìn)入一個新的上下文環(huán)境。

在這個圖示中,一些方法的上下文稱為EC1,全局的上下文稱為 Global EC,我們看一下堆棧形式,演示了從全局上下文進(jìn)入和推出EC1的過程。

這就是ECMAScript的執(zhí)行系統(tǒng)如何管理代碼執(zhí)行的。

關(guān)于上下文環(huán)境的更多內(nèi)容,可以在 Chapter 1. Execution context中找到。

就像我們剛剛講過的,堆棧中每一個執(zhí)行的上下文可以看做一個對象[object]。接街區(qū),我們將看看它的結(jié)構(gòu)和執(zhí)行它的代碼時狀態(tài)類型(或者說屬性)。

Execution context

一個執(zhí)行的上下文可以抽象的理解為object。每一個執(zhí)行的上下文都有一系列的屬性(我們稱為上下文狀態(tài)),他們用來追蹤關(guān)聯(lián)代碼的執(zhí)行進(jìn)度。這個圖示就是一個context的結(jié)構(gòu)

當(dāng)然除了這三個必要的屬性,一個上下文環(huán)境也會根據(jù)情況依賴其他的屬性(狀態(tài))。

讓我們仔細(xì)來看看這三個屬性

Variable object

一個VO[variable object]是關(guān)聯(lián)上下文執(zhí)行環(huán)境的一系列數(shù)據(jù)。它是與上下文關(guān)系密切的一個特殊對象,存儲了在上下文中定義的變量和函數(shù)聲明。

注意:函數(shù)表達(dá)式[function expression](而不是函數(shù)聲明[function
declarations])是不包含在VO[variable object]里面的。

Variable Object是一個抽象的概念,某個方面來講,它表示使用不同的object.以下簡稱VO. 例如,在global上下文中,variable object也是全局對象[global object]。(這就是我們可以通過全局對象的屬性來指向全局變量)。

讓我們看看下面例子中的全局執(zhí)行上下文情況。

var foo = 10;function bar() {} // function declaration, FD(function baz() {}); // function expression, FEconsole.log(
  this.foo == foo, // true
  window.bar == bar // true);console.log(baz); // ReferenceError, "baz" is not defined

如下圖所示

可以看到,函數(shù)baz是一個函數(shù)表達(dá)式,所以它不在VO里面,所以會有一個ReferenceError的提示,因?yàn)榇藭r是在全局環(huán)境下讀取,也就是在函數(shù)表達(dá)式外部讀取的。

注意,和其他的語言不同(例如c/c++),在ECMAScript中,只有函數(shù)functions會新建一個新的作用域。在一個函數(shù)中定義的變量和內(nèi)部函數(shù)在外部是無法獲取的,同時也不會影響全局的變量。

使用eval的話,我們通常會進(jìn)入一個新的eval上下文環(huán)境。Eval會使用global VO,也可以使用caller的VO。

那么函數(shù)和它們的VO的情況呢,在一個函數(shù)的上下文中,一個VO代表了激活變量[activation object],以下簡稱AO.

Activation object

當(dāng)一個函數(shù)被調(diào)用激活之后,這個稱為AO(activation object)的特殊對象就被新建了.它涵蓋了普通的參數(shù)和一個特殊的arguments對象(這是一個參數(shù)的映射表,并且有索引屬性)。我們也可以認(rèn)為:AO實(shí)際上就是函數(shù)上下文的VO.

例如,函數(shù)的VO實(shí)際上就是簡單的VO,但是除了這些變量和函數(shù)定義,還有參數(shù)和arguments對象,這些就成為AO.

考慮下面的情況

function foo(x, y) {  var z = 30;  function bar() {} // FD
  (function baz() {}); // FE}foo(10, 20);

那么AO的圖示如下所示:

同樣道理,function expression不在AO的行列。

對于這個AO的詳細(xì)內(nèi)容可以通過Chapter 2. Variable object找到

我們接下去將第三個主要的對象。眾所周知,在ECMAScript中,我們會用到內(nèi)部函數(shù)[inner functions],在這些內(nèi)部函數(shù)中,我們可能會引用它的父函數(shù)變量,或者全局的變量。我們把這些變量對象成為上下文作用域?qū)ο骩scope
object of the context]. 類似于上面討論的原型鏈[prototype chain],我們在這里稱為作用域鏈[scope
chain]。

Scope chain

作用域鏈就是在代碼上下文中,搜索標(biāo)識符的過程中遇到的一系列對象

這個原理和原型鏈很類似,如果這個變量在自己的作用域中沒有,那么它會尋找父級的,直到最頂層。

標(biāo)示符[Identifiers]可以理解為變量名稱、函數(shù)聲明和普通參數(shù)。例如,當(dāng)一個函數(shù)在自身函數(shù)體內(nèi)需要引用一個變量,但是這個變量并沒有在函數(shù)內(nèi)部聲明(或者也不是某個參數(shù)名),那么這個變量就可以稱為自由變量[free
variable].那么我們搜尋這些自由變量就需要用到作用域鏈。

在一般情況下,一個作用域鏈包括父級變量VO、函數(shù)自身的VO和AO。不過,有些情況下也會包含其它的對象,例如在執(zhí)行期間,動態(tài)加入作用域鏈中的—例如with或者catch語句。

當(dāng)處理一個變量,作用域鏈?zhǔn)菚腁O開始搜索,然后一直搜索到頂端。和原型鏈非常類似。

var x = 10;

(function foo() {  var y = 20;
  (function bar() {var z = 30;// "x" and "y" are "free variables"// and are found in the next (after// bar's activation object) object// of the bar's scope chainconsole.log(x + y + z);
  })();
})();

我們假設(shè)作用域鏈的對象聯(lián)動是通過一個叫做__parent__的屬性,它是指向作用域鏈的下一個對象。這可以在Rhino Code中測試一下這種流程,這種技術(shù)也確實(shí)在ES5環(huán)境中實(shí)現(xiàn)了(有一個稱為outer鏈接).當(dāng)然也可以用一個簡單的數(shù)據(jù)來模擬這個模型。使用__parent__的概念,我們可以把上面的代碼演示成如下的情況。(因此,父級變量是被存在函數(shù)的[[Scope]]屬性中的)

在代碼執(zhí)行過程中,如果使用with或者catch語句就會改變作用域鏈。而這些對象都是一些簡單對象,他們也會有原型鏈。這樣的話,作用域鏈會從兩個維度來搜尋。

  1. 首先在原本的作用域鏈

  2. 每一個鏈接點(diǎn)的作用域的鏈(如果這個鏈接點(diǎn)是有prototype的話)

我們再看下面這個例子

Object.prototype.x = 10;var w = 20;var y = 30;// in SpiderMonkey global object// i.e. variable object of the global// context inherits from "Object.prototype",// so we may refer "not defined global// variable x", which is found in// the prototype chainconsole.log(x); // 10(function foo() {  // "foo" local variables
  var w = 40;  var x = 100;  // "x" is found in the
  // "Object.prototype", because
  // {z: 50} inherits from it

  with ({z: 50}) {console.log(w, x, y , z); // 40, 10, 30, 50
  }  // after "with" object is removed
  // from the scope chain, "x" is
  // again found in the AO of "foo" context;
  // variable "w" is also local
  console.log(x, w); // 100, 40

  // and that's how we may refer
  // shadowed global "w" variable in
  // the browser host environment
  console.log(window.w); // 20})();

我們就會有如下結(jié)構(gòu)圖示。注意,在我們?nèi)ニ褜_parent__之前,首先會去__proto__的鏈接中。

注意,不是所有的全局對象都是由Object.prototype繼承而來的。上述圖示的情況可以在SpiderMonkey中測試。

我們會搜尋作用域鏈來尋找需要的變量。剛才也有提過,在一個上下文結(jié)束之后,它的狀態(tài)和自身會銷毀掉。同時,這個內(nèi)部函數(shù)會返回到父級函數(shù)中。也許,這個返回函數(shù)稍后會再激活另一個上下文。如何保持一個自由變量仍然處于被激活中呢?理論上來說,有一個概念可以解決這個問題,稱為閉包[Closure].它也是和作用域鏈有直接關(guān)系的。

Closure

在ECMAScript中,function[函數(shù)]是基本等級[first-class]的對象。這就意味著,函數(shù)可以作為另一個函數(shù)的參數(shù)(在這種情況下,稱之為”funargs”, 也就是”functional
arguments”的縮寫).接收funargs的函數(shù)稱為高級函數(shù)[higher-order function], 或者類似于數(shù)學(xué)中的運(yùn)算符[operator].
同樣,函數(shù)也可以作為另一個函數(shù)的返回。把函數(shù)作為返回值的函數(shù)稱為以函數(shù)為值的函數(shù)[function valued functions](或者functions with functional
value)

關(guān)于上述的funargs和functional value,會引發(fā)一個叫做”Funarg problem”(或者”A problem of a functional argument)”。為了解決這個問題,我們引入了“閉包”。我們下面來詳細(xì)討論這兩個問題(在ECMAScript中的要解決這兩個問題,需要用到函數(shù)的一個[[Scope]]的屬性)。

首先”funarg problem”的一個類型就是自下而上[”upward funarg problem”]. 當(dāng)一個函數(shù)作為另一個函數(shù)的返回值時,并且使用了自由變量[free
variable]的時候會發(fā)生。即便它的父級上下文環(huán)境已經(jīng)結(jié)束了,它可以引用父級的變量,。這個內(nèi)部函數(shù)在創(chuàng)建時就會將父級的作用域鏈保存在自己的作用域[[Scope]]中。當(dāng)函數(shù)運(yùn)行時,上下文環(huán)境的作用域量是由活躍變量[activation
object]和它[[Scope]]屬性組合而成。

Scope chain = Activation object + [[Scope]]

請?jiān)俅巫⒁膺@個很重要的點(diǎn) – 在函數(shù)創(chuàng)建期間[creation moment],函數(shù)會將父級的作用域鏈保存起來,因?yàn)殡S后調(diào)用這個函數(shù)的時候使用的已經(jīng)保存的作用域鏈來搜尋變量。

請看下面的函數(shù)

function foo() {  var x = 10;  return function bar() {console.log(x);
  };
}// "foo" returns also a function// and this returned function uses// free variable "x"var returnedFunction = foo();// global variable "x"var x = 20;// execution of the returned functionreturnedFunction(); // 10, but not 20

這種形式的作用域稱為靜態(tài)作用域[static/lexical scope]。上面的x變量就是在函數(shù)bar的[[Scope]]中搜尋到的。理論上來說,也會有動態(tài)作用域[dynamic
scope], 也就是上述的x被解釋為20,而不是10. 但是EMCAScript不使用動態(tài)作用域。

“funarg problem”的另一個類型就是自上而下[”downward funarg problem”].在這種情況下,父級的上下會存在,但是在判斷一個變量值的時候會有多義性。也就是,這個變量究竟應(yīng)該使用哪個作用域。是在函數(shù)創(chuàng)建時的作用域呢,還是在執(zhí)行時的作用域呢?為了避免這種多義性,可以采用閉包,也就是使用靜態(tài)作用域。

請看下面的例子

// global "x"var x = 10;// global functionfunction foo() {  console.log(x);
}

(function (funArg) {  // local "x"
  var x = 20;  // there is no ambiguity,
  // because we use global "x",
  // which was statically saved in
  // [[Scope]] of the "foo" function,
  // but not the "x" of the caller's scope,
  // which activates the "funArg"

  funArg(); // 10, but not 20})(foo); // pass "down" foo as a "funarg"

從上述的情況,我們似乎可以斷定,在語言中,使用靜態(tài)作用域是閉包的一個強(qiáng)制性要求。不過,在某些語言中,會提供動態(tài)和靜態(tài)作用域的結(jié)合,可以允許開發(fā)員選擇哪一種作用域。但是在ECMAScript中,只采用了靜態(tài)作用域。所以ECMAScript完全支持使用[[Scope]]的屬性。我們可以給閉包得出如下定義

閉包是一系列代碼塊(在ECMAScript中是函數(shù)),并且靜態(tài)保存所有父級的作用域。通過這些保存的作用域來搜尋到函數(shù)中的自由變量。

注意,其實(shí)每一個函數(shù)都在創(chuàng)建期間保存[[Scope]],所以理論上來說,在ECMAScript中所有的函數(shù)都是閉包。

還有一個很重要的點(diǎn),幾個函數(shù)可能含有相同的父級作用域(這是一個很普遍的情況,例如有好幾個內(nèi)部或者全局的函數(shù))。在這種情況下,在[[Scope]]中存在的變量是會共享的。一個閉包中變量的變化,也會影響另一個閉包的。

function baz() {  var x = 1;  return {foo: function foo() { return ++x; },bar: function bar() { return --x; }
  };
}var closures = baz();console.log(  closures.foo(), // 2
  closures.bar()  // 1);

上述代碼可以用這張圖來表示

如果有這個特性的話,在一個循環(huán)中創(chuàng)建多個函數(shù)就會有關(guān)聯(lián)了。在循環(huán)中創(chuàng)建函數(shù),我們可能會遇到意想不到的情況,因?yàn)樗械暮瘮?shù)都會共享同一個變量了。所有的函數(shù)都有同一個[[Scope]], 并且都指向了最后一次賦值的count。

var data = [];for (var k = 0; k < 3; k++) {  data[k] = function () {alert(k);
  };
}data[0](); // 3, but not 0data[1](); // 3, but not 1data[2](); // 3, but not 2

有幾種方法可以解決種鴿問題。一種就是在作用域鏈中提供一個新增的對象,例如增加一個函數(shù)。

var data = [];for (var k = 0; k < 3; k++) {  data[k] = (function (x) {return function () {      alert(x);
    };
  })(k); // pass "k" value}// now it is correctdata[0](); // 0data[1](); // 1data[2](); // 2

如果對閉包和它的應(yīng)用有興趣的,可以去看看 Chapter 6. Closures.
如果對作用域鏈想要有更深入鏈接的,可以去看看 Chapter 4. Scope chain。

接下去我們討論下一個章節(jié),也就是上下文環(huán)境的最后一個屬性– this.

This value

任何對象在上下文環(huán)境中都可以使用this。我需要澄清一個誤區(qū),在一些描述中總是認(rèn)為this是一個變量對象的屬性。請記住

this是執(zhí)行上下文環(huán)境的一個屬性,而不是某個變量對象的屬性

這個特點(diǎn)很重要,因?yàn)楹妥兞坎煌?,this是沒有一個類似搜尋變量的過程。當(dāng)你在代碼中使用了this,這個 this的值就直接從執(zhí)行的上下文中獲取了,而不會從作用域鏈中搜尋。this的值只取決中進(jìn)入上下文時的情況。

順便說一句,和ECMAScript不同,Python有一個self的參數(shù),和this的情況差不多,但是可以在執(zhí)行過程中被改變。在ECMAScript中,是不可以給this賦值的,因?yàn)?,還是那句話,this不是變量。

在global context(全局上下文)中,this的值就是指全局這個對象,這就意味著,this值就是這個變量本身。

var x = 10;console.log(  x, // 10
  this.x, // 10
  window.x // 10);

在函數(shù)上下文[function context]中,this會可能會根據(jù)每次的函數(shù)調(diào)用而成為不同的值.this會由每一次caller提供,caller是通過調(diào)用表達(dá)式[call
expression]產(chǎn)生的(也就是這個函數(shù)如何被激活調(diào)用的)。例如,下面的例子中foo就是一個callee,在全局上下文中被激活。下面的例子就表明了不同的caller引起this的不同。

// the code of the "foo" function// never changes, but the "this" value// differs in every activationfunction foo() {  alert(this);
}// caller activates "foo" (callee) and// provides "this" for the calleefoo(); // global objectfoo.prototype.constructor(); // foo.prototypevar bar = {  baz: foo};bar.baz(); // bar(bar.baz)(); // also bar(bar.baz = bar.baz)(); // but here is global object(bar.baz, bar.baz)(); // also global object(false || bar.baz)(); // also global objectvar otherFoo = bar.baz;otherFoo(); // again global object

要更深入的了解問什么每次函數(shù)調(diào)用的時候,this都會改變,請看Chapter 3. This。

感謝各位的閱讀,以上就是“JavaScript中的對象有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對JavaScript中的對象有哪些這一問題有了更深刻的體會,具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI