JavaScript中的this关键字

来源:互联网 发布:淘宝店铺详情页设计 编辑:程序博客网 时间:2024/05/16 10:41

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> objectbar(); <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> objectsetTimeout( 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>


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 碎纸机过热件亮了卡住纸了怎么办 汽车买贵了2万多怎么办 宝宝眼皮被蚊子咬肿了怎么办 一岁宝宝撞头咬到舌头有伤口怎么办 二胎快生了老大特别粘人怎么办 生二胎不舍得大宝跟奶奶睡怎么办 怀二胎婆婆不帮忙带孩子怎么办 注册过的高铁用户名忘了怎么办 硕士延期毕业找好的工作怎么办 竞彩足球绑定信用卡提不了现怎么办 qq启动出现问题请卸载重装怎么办 u盘有文件打开后却是空的怎么办 王者荣耀不记得所在的区服怎么办 交易猫出售游戏账号是微信号怎么办 网银密码输错3次怎么办 无线网卡信号很好就是没网速怎么办 红米2a忘了登陆账号怎么办 qq封了密保手机没用了怎么办 乐视手机重置账号密码忘了怎么办 此版本的ios不支持银联怎么办 单反m档拍出来照片是黑色怎么办 从兴趣部落老发骚扰信息怎么办 在厂里辞一个月厂长不批怎么办 在厂里做管理被员工恐吓怎么办 在葡京娱乐输了很多钱怎么办 从珠海入镜澳门北京往返签注怎么办 艾艾灸灸了一身小子子怎么办? 微信视频已过期或已清理怎么办 视频已过期或已被清理怎么办 小孩作业不会老婆天天吵骂打怎么办 苹果手机在太阳下屏幕变暗怎么办 斗鱼的鱼丸竞猜主播结算了怎么办 附近有个小姐姐想加她好友怎么办 孩子出现听别人说话语速很快怎么办 苹果手机上的邮件删了怎么办 手机qq邮箱独立密码忘记了怎么办 哺乳期吃了人参回奶了怎么办? 扣扣邮箱里的邮件过期了怎么办 一体机的管理员账号被删除了怎么办 手机里的邮箱重要吗删除了怎么办 华为荣耀10账号邮箱忘记了怎么办