【this arguments 对象 apply() 方法 bind() 方法 call()】

this arguments 对象 apply() 方法 bind() 方法 call()

JavaScript 的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境。

this的指向

除去不常用的 with 和 eval 的情况,具体到实际应用中,this 的指向大致可以分为以下 4 种。

  • 作为对象的方法调用
  • 作为普通函数调用
  • 构造器调用
  • Function.prototype.call 或 Function.prototype.apply 调用

1.作为对象的方法调用

当函数作为对象的方法被调用时,this 指向该对象:

  var obj = {
    a: 1,
    getA: function(){
      alert ( this === obj ); // 输出:true
      alert ( this.a ); // 输出: 1
    }
  };
  obj.getA();

2.作为对象的方法调用

当函数不作为对象的属性被调用时,也就是我们常说的普通函数方式,此时的 this 总是指向全局对象。在浏览器的 JavaScript 里,这个全局对象是 window 对象。

  window.name = 'globalName';
  var getName = function(){
    return this.name;
  };
  console.log( getName() ); // 输出:globalName
  或者:
  window.name = 'globalName';
  var myObject = {
    name: 'sven',
    getName: function(){
      return this.name;
    }
  };
  var getName = myObject.getName;
  console.log( getName() ); // globalName

3.构造器调用

JavaScript 中没有类,但是可以从构造器中创建对象,同时也提供了 new 运算符,使得构造器看起来更像一个类。

除了宿主提供的一些内置函数,大部分 JavaScript 函数都可以当作构造器使用。构造器的外表跟普通函数一模一样,它们的区别在于被调用的方式。当用 new 运算符调用函数时,该函数总会返回一个对象,通常情况下,构造器里的 this 就指向返回的这个对象,见如下代码:

  var MyClass = function(){
    this.name = 'sven';
  };
  var obj = new MyClass();
  alert ( obj.name ); // 输出:sven

如果构造器显式地返回了一个 object 类型的对象,那么此次运算结果最终会返回这个对象,而不是我们之前期待的 this:

  var MyClass = function(){
    this.name = 'sven';
      return { // 显式地返回一个对象
      name: 'anne'
    }
  };
  var obj = new MyClass();
  alert ( obj.name ); // 输出:anne

如果构造器不显式地返回任何数据,或者是返回一个非对象类型的数据,就不会成上述结果:

  var MyClass = function(){
    this.name = 'sven'
    return 'anne'; // 返回 string 类型
  };
  var obj = new MyClass();
  alert ( obj.name ); // 输出:sven

丢失的this

  var obj = {
    myName: 'sven',
    getName: function(){
      return this.myName;
    }
  };
  console.log( obj.getName() ); // 输出:'sven'
  var getName2 = obj.getName;
  console.log( getName2() ); // 输出:undefined 

4. Function.prototype.call 或 Function.prototype.apply 调用

跟普通的函数调用相比,用 Function.prototype.call 或 Function.prototype.apply 可以动态地改变传入函数的 this:

  var obj1 = {
    name: 'sven',
    getName: function(){
      return this.name;
    }
  };
  var obj2 = {
    name: 'anne'
  };
  console.log( obj1.getName() ); // 输出: sven
  console.log( obj1.getName.call( obj2 ) ); // 输出:anne

当调用 obj.getName 时,getName 方法是作为 obj 对象的属性被调用的,此时的 this 指向 obj 对象,所以 obj.getName()输出’sven’

Arguments 对象

arguments 是一个对应于传递给函数的参数的类数组对象。

例如:

function func1(a, b, c) {
  console.log(arguments[0]);
  // Expected output: 1

  console.log(arguments[1]);
  // Expected output: 2

  console.log(arguments[2]);
  // Expected output: 3
}

func1(1, 2, 3);

arguments对象是所有(非箭头)函数中都可用的局部变量。你可以使用arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,第一个参数在索引 0 处。
例如,如果一个函数传递了三个参数,你可以以如下方式引用他们:

arguments[0];
arguments[1];
arguments[2];

call 和 apply

Function.prototype.call() Function 实例的 apply() 方法会以给定的 this 值和作为数组(或类数组对象提供的 arguments 调用该函数。
Function.prototype.apply() Function 实例的 call() 方法会以给定的 this 值和逐个提供的参数调用该函数。

call和apply的区别

作用一模一样,区别仅在于传入参数形式的不同。

apply 接受两个参数,第一个参数指定了函数体内 this 对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数:

  var func = function( a, b, c ){
    alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]
  };
  func.apply( null, [ 1, 2, 3 ] );

call 传入的参数数量不固定,跟 apply 相同的是,第一个参数也是代表函数体内的 this 指向,从第二个参数开始往后,每个参数被依次传入函数:

  var func = function( a, b, c ){
    alert ( [ a, b, c ] ); // 输出 [ 1, 2, 3 ]
  };
  func.call( null, 1, 2, 3 );

bind

Function.prototype.bind() Function 实例的 bind() 方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。

例如:

const module = {
  x: 42,
  getX: function () {
    return this.x;
  },
};

const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined

const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42

知识点引用于《JavaScript设计模式与开发实践》
Javascript | MDN

  • 37
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值