JavaScript中的this關鍵字

JavaScript函數中的關鍵字this並不指其本身(Itself),舉例說明:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(num)</span> {</span>
    console.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"foo: "</span> + num );

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// keep track of how many times `foo` is called</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.count++;
}

foo.count = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> i;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i<<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>; i++) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) {
        foo( i );
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 6</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 7</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 8</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 9</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// how many times was `foo` called?</span>
console.log( foo.count ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 0 </span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

上例中儘管foo()執行了4次,但是foo.count依然爲0,說明this指代的並不是foo函數自身。那麼我們執行的count++到底是給什麼值在增加呢?實際上我們創建了一個全局變量count,即window下的一個變量,其初始值爲NaN,即使其被增加了4次,其值依然爲NaN。

若上述示例改爲下面就很容易理解:

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">function foo(num) {
    console<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">log</span>( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"foo: "</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">+</span> num );

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// keep track of how many times `foo` is called</span>
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">data</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>count<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">++</span>;
}

<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">data</span> <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span> {
    count: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>
};

<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> i;

for (i<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;"><</span><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>; i<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">++</span>) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i <span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">></span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) {
        foo( i );
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 6</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 7</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 8</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 9</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// how many times was `foo` called?</span>
console<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">log</span>( <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">data</span><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>count ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li></ul>

但是這裏,我們並沒有用到this關鍵字,我們只是選擇性地迴避了this,採用了另一種方式-Lexical scope來完成的。

如果我們要在函數內部引用其自身時,我們只能採用lexical identifier (variable)來指向其自身,如下:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    foo.count = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// `foo` refers to itself</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

此種方式對於有函數名的函數有效,但是對於匿名函數就無能爲力了,比如下面:

<code class="hljs lua has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">setTimeout( <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span></span>{
    // anonymous <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(no name)</span></span>, cannot
    // refer to itself
}, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span> );</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

對此我們無能爲力,不過有一個並不建議使用(目前已廢棄的方式)的方式來引用函數自身:arguments.callee,實際上我們最好的方式就是在需要引用函數自身時不要使用匿名函數,這樣就避免了上述問題的出現。

所以我們最開始時如果我們要引用自身函數時,採用其自身的函數名(identifier )即可:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(num)</span> {</span>
    console.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"foo: "</span> + num );

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// keep track of how many times `foo` is called</span>
    foo.count++;
}

foo.count = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> i;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i<<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>; i++) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) {
        foo( i );
    }
}
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 6</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 7</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 8</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// foo: 9</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// how many times was `foo` called?</span>
console.log( foo.count ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 4</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

上例中我們似乎還是迴避了this關鍵字,只不過上例中我們要引用函數自身,不能使用this關鍵字。

如果我們一定要使用this關鍵字來指代函數自身時,我們可以這樣做:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-reserved" style="box-sizing: border-box;">function</span> foo(num) {
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"foo: "</span> + num );

    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> keep track <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">of</span> how many times `<span class="javascript" style="box-sizing: border-box;">foo</span>` <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> called
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">Note</span>: `<span class="javascript" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span></span>` IS actually `<span class="javascript" style="box-sizing: border-box;">foo</span>` now, based <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">on</span>
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> how `<span class="javascript" style="box-sizing: border-box;">foo</span>` <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> called (see below)
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.count++;
}

foo.count = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>;

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> i;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (i=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i<<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>; i++) {
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i > <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>) {
        <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> using `<span class="javascript" style="box-sizing: border-box;">call(..)</span>`, we ensure the `<span class="javascript" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span></span>`
        <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> points at the <span class="hljs-reserved" style="box-sizing: border-box;">function</span> object (`<span class="javascript" style="box-sizing: border-box;">foo</span>`) itself
        foo.call( foo, i );
    }
}
<span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">6</span>
// <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7</span>
// <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">8</span>
// <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">9</span>

// how many times was `<span class="javascript" style="box-sizing: border-box;">foo</span>` called?
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( foo.count ); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>

另一個對於this的誤解是指:this指的是函數的lexical scope,You Dont Know JS 中關於this有這樣的一段話:

To be clear, this does not, in any way, refer to a function’s lexical scope. It is true that internally, scope is kind of like an object with properties for each of the available identifiers. But the scope “object” is not accessible to JavaScript code. It’s an inner part of the Engine’s implementation.

請看下例:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.bar();
}

<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">bar</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//undefined</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

上述代碼試圖通過this在foo()和bar()的lexical scopes中建立橋樑,所以通過bar()來獲取foo()的inner scope的變量a,這樣的橋樑實際上並不存在。

那麼this機制到底是怎樣的呢?其實,this是在運行時綁定的(runtime binding),而不是創建時綁定(author-time binding),即函數在調用時是基於其上下文來綁定的。

You Dont Know JS 中關於this機制有這樣的一段話:

‘This’ is not an author-time binding but a runtime binding. It is contextual based on the conditions of the function’s invocation. this binding has nothing to do with where a function is declared, but has instead everything to do with the manner in which the function is called.

When a function is invoked, an activation record, otherwise known as an execution context, is created. This record contains information about where the function was called from (the call-stack), how the function was invoked, what parameters were passed, etc. One of the properties of this record is the this reference which will be used for the duration of that function’s execution.

上述提到,this是在函數調用時基於其Call-site來綁定的,那麼什麼是Call-site呢

call-site: the location in code where a function is called (not where it’s declared).

那麼如何確定函數的call-site呢,

go locate where a function is called from

但是,確定函數的call-site並不容易,因此我們換一種思路,來尋找函數的call-stack:

the stack of functions that have been called to get us to the current moment in execution

下面我們來通過例子來說明call-site和call-stack的關係:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-reserved" style="box-sizing: border-box;">function</span> baz() {
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> call-stack <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">is</span>: `<span class="javascript" style="box-sizing: border-box;">baz</span>`
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> so, our call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> the <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">global</span> scope

    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"baz"</span> );
    bar(); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <-- call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> `<span class="javascript" style="box-sizing: border-box;">bar</span>`
}

<span class="hljs-reserved" style="box-sizing: border-box;">function</span> bar() {
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> call-stack <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">is</span>: `<span class="javascript" style="box-sizing: border-box;">baz</span>`<span class="hljs-function" style="box-sizing: border-box;"> -></span> `<span class="javascript" style="box-sizing: border-box;">bar</span>`
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> so, our call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> `<span class="javascript" style="box-sizing: border-box;">baz</span>`

    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"bar"</span> );
    foo(); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <-- call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> `<span class="javascript" style="box-sizing: border-box;">foo</span>`
}

<span class="hljs-reserved" style="box-sizing: border-box;">function</span> foo() {
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> call-stack <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">is</span>: `<span class="javascript" style="box-sizing: border-box;">baz</span>`<span class="hljs-function" style="box-sizing: border-box;"> -></span> `<span class="javascript" style="box-sizing: border-box;">bar</span>`<span class="hljs-function" style="box-sizing: border-box;"> -></span> `<span class="javascript" style="box-sizing: border-box;">foo</span>`
    <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> so, our call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> `<span class="javascript" style="box-sizing: border-box;">bar</span>`

    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"foo"</span> );
}

baz(); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <-- call-site <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> `<span class="javascript" style="box-sizing: border-box;">baz</span>`</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li></ul>

我們可以通過瀏覽器的dev Tool的debugger來調試查看函數的call-stack。

在我們清楚 call-site之後,我們來看this綁定的四條準則:

1. Default Binding

這條是最常見的綁定規則,也就是說this指向global object,請看例子:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;

foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

如果在strict mode下,this指向undefined:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
<span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;">    "use strict"</span>;

    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;

foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// TypeError: `this` is `undefined`</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

其中,一個細節要注意,如果foo()不是在strict mode下,其this仍指向global object:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;

(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>{</span>
<span class="hljs-pi" style="color: rgb(0, 102, 102); box-sizing: border-box;">    "use strict"</span>;

    foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>
})();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

2. Implicit Binding

does the call-site have a context object, also referred to as an owning or containing object

如果call-site有上下文對象,或者說其有包含它的容器對象,那麼此時Implicit Binding起作用了,看下例:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    foo: foo
};

obj.foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

上例中foo先被申明,然後被obj引用,實際上,即使在obj中申明函數,結果也一樣:

<code class="hljs http has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">

<span class="javascript" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    foo: <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
           console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
          }
};

obj.foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

call-site uses the obj context to reference the function, so you could say that the obj object “owns” or “contains” the function reference at the time the function is called.

obj在foo()函數被調用之前持有foo函數的引用,即obj是foo的上下文對象,此時Implicit Binding生效,this也就指向了該上下文對象。注意下面的一種情況:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj2 = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">42</span>,
    foo: foo
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj1 = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    obj2: obj2
};

obj1.obj2.foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 42</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

思考下面的示例:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-reserved" style="box-sizing: border-box;">function</span> foo() {
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> obj = {
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">a</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: foo
};

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> bar = obj.foo; <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-reserved" style="box-sizing: border-box;">function</span> reference/alias!

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> a = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"oops, global"</span>; <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> `<span class="javascript" style="box-sizing: border-box;">a</span>` also property <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">on</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">global</span> object

bar(); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"oops, global"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

表面上看,bar是通過obj的foo屬性來指向foo函數的,實際上,bar是直接指向foo的引用的,因爲obj中的foo也是指向foo引用的。此時,因爲this就失去綁定,default binding生效。

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">doFoo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(fn)</span> {</span>
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// `fn` is just another reference to `foo`</span>

    fn(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// <-- call-site!</span>
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    foo: foo
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"oops, global"</span>; <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// `a` also property on global object</span>

doFoo( obj.foo ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// "oops, global"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

這裏,我們通過參數傳遞將foo函數引用賦值給fn,此時就與obj無關了,是fn指向foo函數引用了,this失去隱式綁定,default binding生效,即使你傳入回調函數(即這裏的fn)的函數不是自己寫的也沒有關係:

<code class="hljs coffeescript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-reserved" style="box-sizing: border-box;">function</span> foo() {
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">console</span>.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> obj = {
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">a</span>: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    <span class="hljs-attribute" style="box-sizing: border-box; color: rgb(0, 136, 0);">foo</span>: foo
};

<span class="hljs-reserved" style="box-sizing: border-box;">var</span> a = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"oops, global"</span>; <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> `<span class="javascript" style="box-sizing: border-box;">a</span>` also property <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">on</span> <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">global</span> object

setTimeout( obj.foo, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span> ); <span class="hljs-regexp" style="color: rgb(0, 136, 0); box-sizing: border-box;">//</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"oops, global"</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

這裏的setTimeout我們可以這樣理解:

<code class="hljs rust has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">function setTimeout(<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">fn</span>,<span class="hljs-title" style="box-sizing: border-box;">delay</span>) {
    // <span class="hljs-title" style="box-sizing: border-box;">wait</span> (</span>somehow) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> `delay` milliseconds
    <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">fn</span>(</span>); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// <-- call-site!</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

這樣與上文就一致了。

3. Explicit Binding

我們可以通過call(..)和apply(..)來顯式綁定this:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>
};

foo.call( obj ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

倘若我們將原始類型的變量作爲this顯示綁定時,其原始類型會被自動包裝成對應的對象類型(object-form),Explicit Binding綁定就是Hard Binding。

Hard Binding

explicit binding也不能解決上文中的this失去綁定後this的重新綁定,但是我們可以通過下面的小trick來解決this的重新綁定問題:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> bar = <span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    foo.call( obj );
};

bar(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>
setTimeout( bar, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span> ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>

<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// `bar` hard binds `foo`'s `this` to `obj`</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// so that it cannot be overriden</span>
bar.call( window ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

上文中我們創建函數bar(),在函數內部調用foo.call(obj),將obj 
綁定到this上,我們稱這種爲Hard Binding。

4. new Binding

In JS, constructors are just functions that happen to be called with the new operator in front of them. They are not attached to classes, nor are they instantiating a class. They are not even special types of functions. They’re just regular functions that are, in essence, hijacked by the use of new in their invocation.

js並不像一般的面嚮對象語言,具有constructor functions,當我們使用new時,調用函數,我們稱該動作爲constructor call,使用new時發生了以下幾件事:

  1. a brand new object is created (aka, constructed) out of thin air
  2. the newly constructed object is [[Prototype]]-linked
  3. the newly constructed object is set as the this binding for that function call
  4. unless the function returns its own alternate object, the new-invoked function call will automatically return the newly constructed object.

舉例說明:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(a)</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a = a;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> bar = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> foo( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> );
console.log( bar.a ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

首先,創建一個對象,其與var a={}創建的對象沒有任何區別,然後將該對象與foo建立聯繫,將this與該對象綁定,返回該對象。

this綁定優先級

介紹完上述的幾種this綁定,首先,efault binding優先級最低,我們放在一邊。

implicit binding 和explicit binding那個優先級高呢?看示例:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj1 = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>,
    foo: foo
};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj2 = {
    a: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>,
    foo: foo
};

obj1.foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>
obj2.foo(); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3</span>

obj1.foo.call( obj2 ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3</span>
obj2.foo.call( obj1 ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>

說明explicit binding優先級高於implicit binding,那麼implicit binding 和new binding呢?

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;">function foo(something) {
    this<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.a</span> = something<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
}

var obj1 = {
    foo: foo
}<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>

var obj2 = {}<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>

obj1<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.foo</span>( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>( obj1<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.a</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">; // 2</span>

obj1<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.foo</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.call</span>( obj2, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>( obj2<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.a</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">; // 3</span>

var bar = new obj1<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.foo</span>( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">;</span>
console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>( obj1<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.a</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">; // 2</span>
console<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.log</span>( bar<span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.a</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">; // 4</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>

說明new binding優先級高於implicit binding,那麼new binding和explicit binding呢?

是不是可以這樣測試呢:

<code class="hljs vbnet has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> foo.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">call</span>(obj1)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

注意,這樣是不可以的。

Before we explore that in a code listing, think back to how hard binding physically works, which is that Function.prototype.bind(..) creates a new wrapper function that is hard-coded to ignore its own this binding (whatever it may be), and use a manual one we provide.

因此,很顯然hard binding(也就是explicit binding),看示例:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(something)</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a = something;
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> obj1 = {};

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> bar = foo.bind( obj1 );
bar( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span> );
console.log( obj1.a ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> baz = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> bar( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> );
console.log( obj1.a ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span>
console.log( baz.a ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 3</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

由於new bar(3)並沒有改變obj1.a的值,可見,explicit binding優先級最高。

總結

現在我們總結this的用法:

  1. 函數是否使用new關鍵字調用,如果有,那麼this指向該新創建的對象。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> bar = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> foo()</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
  1. 調用函數是否使用了call 和apply,如果有,那麼this指向該我們綁定的對象上。
<code class="hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">var bar </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> foo.call( obj2 )</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
  1. 函數調用時是否有上下文對象(context ),如果有,那麼this指向該上下文對象。
<code class="hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">var bar </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> obj1.foo()</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
  1. 除上述以外情況,如果是strict mode下,那麼this指向undefined,否則指向global object。
<code class="hljs fix has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-attribute" style="box-sizing: border-box;">var bar </span>=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;"> foo()</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

Binding Exceptions

當我們使用call, apply, 或 bind時傳遞給this對象的值爲null 或undefined,這些值會被忽略, default binding生效。

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">function</span> <span class="hljs-title" style="box-sizing: border-box;">foo</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span> {</span>
    console.log( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.a );
}

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>;

foo.call( <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">null</span> ); <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// 2</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

最後,強調一點,關於Object.create、Object.create()和Object.create(null)之類的區別:

<code class="hljs javascript has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> a=<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>.create;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">var</span> b=<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">Object</span>.create(<span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">null</span>);
console.log(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> a);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//function</span>
console.log(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">typeof</span> b);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//object</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

Object.create只是對Object中create函數的一個引用,Object.create(null)是創建一個不繼承任何原型對象的對象,試比較var a=Object.create(null)和var b={}的區別:

<code class="hljs lasso has-numbering" style="display: block; padding: 0px; background-color: transparent; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-top-left-radius: 0px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-bottom-left-radius: 0px; word-wrap: normal; background-position: initial initial; background-repeat: initial initial;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> a<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span>Object<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>create(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">null</span>);
<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">var</span> b<span class="hljs-subst" style="color: rgb(0, 0, 0); box-sizing: border-box;">=</span>{};
console<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">log</span>(a<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>__proto__);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//undefined</span>
console<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">log</span>(b<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">.</span>__proto__);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//Object {}</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章