js bind 传参、_浅析JS中this

前言

在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象

ES2015 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)

为什么要学习this?如果你学过面向对象编程,那你肯定知道干什么用的,毕竟这是js中必须要掌握的东西。

■ this

例子1:

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this); //Window
}
a();

8f774b47d99354bce669890b4ded6c75.png

按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明。

function a(){
    var user = "追梦子";
    console.log(this.user); //undefined
    console.log(this);  //Window
}
window.a();

c4e58a0f2441c13861efe8ee4c290fc2.png

和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的。

例子2:

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user); //this指向o
    }
}
o.fn();//this指向o
//追梦子

0a05918907d59edc5cae40648bfed5ea.png

这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。

其实例子1和例子2说的并不够准确,下面这个例子就可以推翻上面的理论。

如果要彻底的搞懂this必须看接下来的几个例子

例子3:

var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user); //this指向?
    }
}
window.o.fn();//this指向?
//追梦子

这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象。

这里先不解释为什么上面的那段代码this为什么没有指向window,我们再来看一段代码。

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();

这里同样也是对象o点出来的,但是同样this并没有执行它,那你肯定会说我一开始说的那些不就都是错误的吗?其实也不是,只是一开始说的不准确,接下来我将补充一句话,我相信你就可以彻底的理解this的指向的问题。

  • 情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window
function a(){
    var user = "追梦子";
    console.log(this); //Window
}
a();
  • 情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。
var o = {
    user:"追梦子",
    fn:function(){
        console.log(this.user); //this指向o
    }
}
o.fn();//this指向o
//追梦子
  • 情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();

例子3可以证明,如果不相信,那么接下来我们继续看几个例子

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a); //undefined
        }
    }
}
o.b.fn();

尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。

还有一种比较特殊的情况,例子4:

var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //undefined
            console.log(this); //window
        }
    }
}
var j = o.b.fn;
j();

这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。

this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn。

this讲来讲去其实就是那么一回事,只不过在不同的情况下指向的会有些不同,上面的总结每个地方都有些小错误,也不能说是错误,而是在不同环境下情况就会有不同,所以我也没有办法一次解释清楚,只能你慢慢地的去体会。

构造函数版this:

function Fn(){
    this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子

这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。

function Fn(){
    this.user = "追梦子";
}
var a = new Fn();

/*相当于复制了一份Fn到对象a里面
a{
  Fn{
    this.user = "追梦子";
  }
}
*/

console.log(a.user); //追梦子

除了上面的这些以外,我们还可以自行改变this的指向,关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章,详细的说明了我们如何手动更改this的指向。

更新一个小问题当this碰到return时

function fn()  
{  
    this.user = '追梦子';  
    return {};  
}
var a = new fn();  
console.log(a.user); //undefined

再看一个

function fn()  
{  
    this.user = '追梦子';  
    return function(){};
}
var a = new fn();  
console.log(a.user); //undefined

再来

function fn()  
{  
    this.user = '追梦子';  
    return 1;
}
var a = new fn;  
console.log(a.user); //追梦子

_____

function fn()  
{  
    this.user = '追梦子';  
    return undefined;
}
var a = new fn;  
console.log(a.user); //追梦子

这是什么意思呢?

如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象或者不写则那么this还是指向函数的实例。

return {}; return function(){};返回的是一个对象,this就指向这个对象,但是这个对象里并没有user属性,所以只能打印出undefined

return 1; return undefined;返回的是不是一个对象,this还是指向函数的实例,又因为实例时完全复制的原型fn,里面存有user属性,所以可以打印出user的值

function fn()  
{  
    this.user = '追梦子';  
    return undefined;
}
var a = new fn;  
console.log(a); //fn {user: "追梦子"}

还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。

function fn()  
{  
    this.user = '追梦子';  
    return null;
}
var a = new fn;  
console.log(a.user); //追梦子

知识点补充:

  1. 在严格版中的默认的this不再是window,而是undefined。
  2. new操作符会改变函数this的指向问题,虽然我们上面讲解过了,但是并没有深入的讨论这个问题,网上也很少说,所以在这里有必要说一下。
function fn(){
    this.num = 1;
}
var a = new fn();
console.log(a.num); //1

为什么this会指向a?

  1. 首先new关键字会创建一个空的对象
  2. 然后会自动调用一个函数apply方法
  3. 将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代

注意: 当你new一个空对象的时候,js内部的实现并不一定是用的apply方法来改变this指向的,这里我只是打个比方而已.

if (this === 动态的可改变的) return true;

常用

代码案例:

const test = {
  prop: 42,
  func: function() {
    return this.prop;   //这里的this就是test
  },
};

console.log(test.func());//这里的this就是test
// expected output: 42

d8f007e341cd2144bb7f2d74622568c3.png

全局上下文

无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true

a = 37;
console.log(window.a); // 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"

函数上下文

在函数内部,this的值取决于函数被调用的方式

因为下面的代码不在严格模式下,且 this 的值不是由该调用设置的,所以 this 的值默认指向全局对象,浏览器中就是 window

function f1(){
  return this;
}
//在浏览器中:
f1() === window;   //在浏览器中,全局对象是window

//在Node中:
f1() === globalThis; 

然而,在严格模式下,如果进入执行环境时没有设置 this 的值,this会保持为 undefined,如下:

function f2(){
  "use strict"; // 这里是严格模式
  return this;
}

f2() === undefined; // true

函数上下文中的 this

var obj = {a: 'Custom'};
var a = 'Global';

function whatsThis() {
  return this.a; 
}

whatsThis();          // 'Global' 
whatsThis.call(obj);  // 'Custom' 
whatsThis.apply(obj); // 'Custom' 

this 和对象转换

function add(c, d) {
  return this.a + this.b + c + d;
}

var o = {a: 1, b: 3};

// 第一个参数是用作“this”的对象
// 其余参数用作函数的参数
add.call(o, 5, 7); // 16

// 第一个参数是用作“this”的对象
// 第二个参数是一个数组,数组中的两个成员用作函数参数
add.apply(o, [10, 20]); // 34

在非严格模式下使用 callapply 时,如果用作 this 的值不是对象,则会被尝试转换为对象。nullundefined 被转换为全局对象。原始值如 7'foo' 会使用相应构造函数转换为对象。因此 7 会被转换为 new Number(7) 生成的对象,字符串 'foo' 会转换为 new String('foo') 生成的对象。

function bar() {
  console.log(Object.prototype.toString.call(this));
}

bar.call(7);     // [object Number]
bar.call('foo'); // [object String]
bar.call(undefined); // [object global]

作为对象的方法

当函数作为对象里的方法被调用时,this 被设置为调用该函数的对象。

下面的例子中,当 o.f() 被调用时,函数内的 this 将绑定到 o 对象。

var o = {
  prop: 37,
  f: function() {
    return this.prop;
  }
};

console.log(o.f()); // 37

请注意,这样的行为完全不会受函数定义方式或位置的影响。在前面的例子中,我们在定义对象o的同时,将其中的函数定义为成员 f 。但是,我们也可以先定义函数,然后再将其附属到o.f。这样做的结果是一样的:

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // 37

这表明函数是从 of 成员调用的才是重点。

同样,this 的绑定只受最接近的成员引用的影响。在下面的这个例子中,我们把一个方法g当作对象o.b的函数调用。在这次执行期间,函数中的this将指向o.b。事实证明,这与他是对象 o 的成员没有多大关系,最近的引用才是最重要的。

o.b = {g: independent, prop: 42};
console.log(o.b.g()); // 42

原型链中的 this

对于在对象原型链上某处定义的方法,同样的概念也适用。如果该方法存在于一个对象的原型链上,那么 this 指向的是调用这个方法的对象,就像该方法就在这个对象上一样。

var o = {
  f: function() { 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

在这个例子中,对象 p 没有属于它自己的 f 属性,它的 f 属性继承自它的原型。虽然最终是在 o 中找到 f 属性的,这并没有关系;查找过程首先从 p.f 的引用开始,所以函数中的 this 指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p。这是 JavaScript 的原型继承中的一个有趣的特性。

作为构造函数

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

虽然构造函数返回的默认值是 this 所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回 this 对象)。

/*
 * 构造函数这样工作:
 *
 * function MyConstructor(){
 *   // 函数实体写在这里
 *   // 根据需要在this上创建属性,然后赋值给它们,比如:
 *   this.fum = "nom";
 *   // 等等...
 *
 *   // 如果函数具有返回对象的return语句,
 *   // 则该对象将是 new 表达式的结果。 
 *   // 否则,表达式的结果是当前绑定到 this 的对象。
 *   //(即通常看到的常见情况)。
 * }
 */

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37


function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // logs 38

在刚刚的例子中(C2),因为在调用构造函数的过程中,手动的设置了返回对象,与this绑定的默认对象被丢弃了。(这基本上使得语句 “this.a = 37;”成了“僵尸”代码,实际上并不是真正的“僵尸”,这条语句执行了,但是对于外部没有任何影响,因此完全可以忽略它)。

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>

<p>因为 person 对象“拥有” fullName 方法。</p>

<p id="demo"></p>

<script>
// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  id     : 678,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 代表 person 对象。

因为 person 对象“拥有” fullName 方法。

Bill Gates

this 是什么?

JavaScript this 关键词指的是它所属的对象。

它拥有不同的值,具体取决于它的使用位置:

  • 在方法中,this 指的是所有者对象。
  • 单独的情况下,this 指的是全局对象。
  • 在函数中,this 指的是全局对象。
  • 在函数中,严格模式下,this 是 undefined。
  • 在事件中,this 指的是接收事件的元素。

像 call() 和 apply() 这样的方法可以将 this 引用到任何对象。

方法中的 this

在对象方法中,this 指的是此方法的“拥有者”。

在本页最上面的例子中,this 指的是 person 对象。

person 对象是 fullName 方法的拥有者。

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>

<p>因为 person 对象“拥有” fullName 方法。</p>

<p id="demo"></p>

<script>
// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  id     : 678,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 代表 person 对象。

因为 person 对象“拥有” fullName 方法。

Bill Gates

单独的 this

在单独使用时,拥有者是全局对象,因此 this 指的是全局对象。

在浏览器窗口中,全局对象是 [object Window]:

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 引用 window 对象:</p>

<p id="demo"></p>

<script>
var x = this;
document.getElementById("demo").innerHTML = x;
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 引用 window 对象:

[object Window]

在严格模式中,如果单独使用,那么this指的是全局对象[object Window]:

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 引用 window 对象:</p>

<p id="demo"></p>

<script>
"use strict";
var x = this;
document.getElementById("demo").innerHTML = x;
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 引用 window 对象:

[object Window]

函数中的 this(默认)

在 JavaScript 函数中,函数的拥有者默认绑定 this。

因此,在函数中,this 指的是全局对象 [object Window]。

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 代表“拥有” myFunction 的对象:</p>

<p id="demo"></p>

<script>
document.getElementById("demo").innerHTML = myFunction();
function myFunction() {
  return this;
}
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 代表“拥有” myFunction 的对象:

[object Window]

函数中的 this(严格模式)

JavaScript 严格模式不允许默认绑定。

因此,在函数中使用时,在严格模式下,this 是未定义的(undefined)。

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在函数中,默认地,<b>this</b> 引用全局对象。</p>

<p>在严格模式中,<b>this</b> 是 <b>undefined</b>,因为严格模式不允许默认绑定:</p>

<p id="demo"></p>

<script>
"use strict";
document.getElementById("demo").innerHTML = myFunction();
function myFunction() {
  return this;
}
</script>

</body>
</html>

//
Javascript this 关键词
在函数中,默认地,this 引用全局对象。

在严格模式中,this 是 undefined,因为严格模式不允许默认绑定:

undefined

事件处理程序中的 this

在 HTML 事件处理程序中,this 指的是接收此事件的 HTML 元素:

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<button onclick="this.style.display='none'">单击来删除我!</button>

</body>
</html>

//
Javascript this 关键词
单击来删除我!

对象方法绑定

在此例中,this 是 person 对象(person 对象是该函数的“拥有者”):

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 代表“拥有” fullName 方法的 person 对象。</p>

<p id="demo"></p>

<script>
// 创建对象:
var person = {
  firstName  : "Bill",
  lastName   : "Gates",
  id     : 678,
  myFunction : function() {
    return this;
  }
};

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.myFunction();
</script>

</body>
</html>
//
Javascript this 关键词
在本例中,this 代表“拥有” fullName 方法的 person 对象。

[object Object]

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<b>this</b> 代表 <b>person</b> 对象。</p>

<p>因为 person 对象“拥有” fullName 方法。</p>

<p id="demo"></p>

<script>
// 创建对象:
var person = {
  firstName: "Bill",
  lastName : "Gates",
  id     : 678,
  fullName : function() {
    return this.firstName + " " + this.lastName;
  }
};

// 显示来自对象的数据:
document.getElementById("demo").innerHTML = person.fullName();
</script>

</body>
</html>

//
Javascript this 关键词
在本例中,this 代表 person 对象。

因为 person 对象“拥有” fullName 方法。

Bill Gates

换句话说,this.firstName意味着this(person)对象的firstName属性。

显式函数绑定

call() 和 apply() 方法是预定义的 JavaScript 方法。

它们都可以用于将另一个对象作为参数调用对象方法。

您可以在本教程后面阅读有关 call() 和 apply() 的更多内容。

在下面的例子中,当使用 person2 作为参数调用 person1.fullName 时,this 将引用 person2,即使它是 person1 的方法:

实例

<!DOCTYPE html>
<html>
<body>

<h1>JavaScript <b>this</b> 关键词</h1>

<p>在本例中,<strong>this</strong> 引用 person2,即使它是 person1 的方法:</p>

<p id="demo"></p>

<script>
var person1 = {
  fullName: function() {
    return this.firstName + " " + this.lastName;
  }
}
var person2 = {
  firstName:"Bill",
  lastName: "Gates",
}
var x = person1.fullName.call(person2); 
document.getElementById("demo").innerHTML = x; 
</script>

</body>
</html>
//
Javascript this 关键词
在本例中,this 引用 person2,即使它是 person1 的方法:

Bill Gates

学懂 JavaScript 语言,一个标志就是理解下面两种写法,可能有不一样的结果。

var obj = {
  foo: function () {}
};

var foo = obj.foo;

// 写法一
obj.foo()

// 写法二
foo()

上面代码中,虽然obj.foofoo指向同一个函数,但是执行结果可能不一样。请看下面的例子。

var obj = {
  foo: function () { console.log(this.bar) },
  bar: 1
};

var foo = obj.foo;
var bar = 2;

obj.foo() // 1
foo() // 2

这种差异的原因,就在于函数体内部使用了this关键字。很多教科书会告诉你,this指的是函数运行时所在的环境。对于obj.foo()来说,foo运行在obj环境,所以this指向obj;对于foo()来说,foo运行在全局环境,所以this指向全局环境。所以,两者的运行结果不一样。

这种解释没错,但是教科书往往不告诉你,为什么会这样?也就是说,函数的运行环境到底是怎么决定的?举例来说,为什么obj.foo()就是在obj环境执行,而一旦var foo = obj.foofoo()就变成在全局环境执行?

本文就来解释 JavaScript 这样处理的原理。理解了这一点,你就会彻底理解this的作用。

二、内存的数据结构

JavaScript 语言之所以有this的设计,跟内存里面的数据结构有关系。

var obj = { foo:  5 };

上面的代码将一个对象赋值给变量obj。JavaScript 引擎会先在内存里面,生成一个对象{ foo: 5 },然后把这个对象的内存地址赋值给变量obj

ec9c42a57b406f833c4e3bcc1026680b.png

也就是说,变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

原始的对象以字典结构保存,每一个属性名都对应一个属性描述对象。举例来说,上面例子的foo属性,实际上是以下面的形式保存的。

3e477b915b0bb5877f6d5f5c20fe8796.png
{
  foo: {
    [[value]]: 5
    [[writable]]: true
    [[enumerable]]: true
    [[configurable]]: true
  }
}

注意,foo属性的值保存在属性描述对象的value属性里面。

三、函数

这样的结构是很清晰的,问题在于属性的值可能是一个函数。

var obj = { foo: function () {} };

这时,引擎会将函数单独保存在内存中,然后再将函数的地址赋值给foo属性的value属性。

ee9c250f5a54ab2aa1d11642ce6500d0.png
{
  foo: {
    [[value]]: 函数的地址
    ...
  }
}

由于函数是一个单独的值,所以它可以在不同的环境(上下文)执行。

var f = function () {};
var obj = { f: f };

// 单独执行
f()

// obj 环境执行
obj.f()

四、环境变量

JavaScript 允许在函数体内部,引用当前环境的其他变量。

var f = function () {
  console.log(x);
};

上面代码中,函数体里面使用了变量x。该变量由运行环境提供。

现在问题就来了,由于函数可以在不同的运行环境执行,所以需要有一种机制,能够在函数体内部获得当前的运行环境(context)。所以,this就出现了,它的设计目的就是在函数体内部,指代函数当前的运行环境。

var f = function () {
  console.log(this.x);
}

上面代码中,函数体里面的this.x就是指当前运行环境的x

var f = function () {
  console.log(this.x);
}

var x = 1;
var obj = {
  f: f,
  x: 2,
};

// 单独执行
f() // 1

// obj 环境执行
obj.f() // 2

上面代码中,函数f在全局环境执行,this.x指向全局环境的x

bb782216ad65836e3c55b53e7485ce50.png

obj环境执行,this.x指向obj.x

995147490afe5c35c3d378bdf712dc59.png

回到本文开头提出的问题,obj.foo()是通过obj找到foo,所以就是在obj环境执行。一旦var foo = obj.foo,变量foo就直接指向函数本身,所以foo()就变成在全局环境执行。

https://www.google.com/search?q=fn.call()%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BC%A0%E5%85%A5this&oq=fn.call()%E4%B8%BA%E4%BB%80%E4%B9%88%E8%A6%81%E4%BC%A0%E5%85%A5this&aqs=chrome..69i57.15959j0j8&sourceid=chrome&ie=UTF-8​www.google.com JavaScript函数的隐式参数: arguments 和 this​juejin.im

核心原始

首先,让我们看一下核心函数调用原语,即Function的call方法[1]。调用方法相对简单。

  1. argList从参数1到结尾创建参数列表()
  2. 第一个参数是 thisValue
  3. 调用thisset为thisValueargList作为其参数列表的函数

例如:

function hello(thing) {
  console.log(this + " says hello " + thing);
}

hello.call("Yehuda", "world") //=> Yehuda says hello world

正如你所看到的,我们调用hello与方法this设置为"Yehuda"和一个参数"world"。这是JavaScript函数调用的核心原语。您可以将所有其他函数调用视为对该原语的替代。(“ desugar”是采用一种方便的语法,并以更基本的核心原语进行描述)。

[1]在ES5规范中,该call方法是根据另一个更底层的原语进行描述的,但是它是该原语之上非常薄的包装,因此在此我进行了一些简化。有关更多信息,请参见本文结尾。

简单函数调用

显然,一直调用函数call会很烦人。JavaScript允许我们使用parens语法(hello("world")。直接调用函数。

function hello(thing) {
  console.log("Hello " + thing);
}

// this:
hello("world")

// desugars to:
hello.call(window, "world");

仅当使用严格模式 [2] 时,此行为在ECMAScript 5中已更改:

// this:
hello("world")

// desugars to:
hello.call(undefined, "world");

简短的版本是:的函数调用fn(...args)与相同fn.call(window [ES5-strict: undefined], ...args)

请注意,对于内联声明的函数也是如此:(function() {})()与相同(function() {}).call(window [ES5-strict: undefined)

[2]实际上,我撒了点谎。ECMAScript 5规范说undefined(几乎)总是通过,但是thisValue在非严格模式下,被调用的函数应将其更改为全局对象。这允许严格模式调用者避免破坏现有的非严格模式库。

会员职能

调用方法的下一个非常常见的方法是作为对象(person.hello())的成员。在这种情况下,调用将终止:

var person = {
  name: "Brendan Eich",
  hello: function(thing) {
    console.log(this + " says hello " + thing);
  }
}

// this:
person.hello("world")

// desugars to this:
person.hello.call(person, "world");

请注意,该hello方法如何以这种形式附加到对象并不重要。请记住,我们之前将其定义hello为独立函数。让我们看看如果我们动态地将对象附加到对象上会发生什么:

function hello(thing) {
  console.log(this + " says hello " + thing);
}

person = { name: "Brendan Eich" }
person.hello = hello;

person.hello("world") // still desugars to person.hello.call(person, "world")

hello("world") // "[object DOMWindow]world"

注意,该函数没有其“ this”的持久概念。它总是在调用时根据其调用方调用的方式进行设置。

https://www.google.com/search?q=this+%E6%8C%87%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BD%9C%E7%94%A8&oq=this+%E6%8C%87%E4%B8%8A%E4%B8%8B%E6%96%87%E4%BD%9C%E7%94%A8&aqs=chrome..69i57.20087j0j8&sourceid=chrome&ie=UTF-8​www.google.com https://blog.fundebug.com/2019/08/15/what-is-javascript-this/​blog.fundebug.com 4、对作用于上下文和this的理解_郭小刀-CSDN博客​blog.csdn.net
1bf5e3dfe359cc2c6348a147a9fc3a72.png
理解 this 的指向​set.sh
817985eeadd6b15a3c14891e0b4881f4.png
JS基础篇之作用域、执行上下文、this、闭包​juejin.im
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值