Java教程

JavaScript中this指向问题

本文主要是介绍JavaScript中this指向问题,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

1. 全局下的 this
在全局环境下,this 指向全局对象。

全局对象和宿主环境相关,在浏览器下,全局对象就是 window 对象,在 node.js 中,全局对象是 global 对象。
开启严格模式后, this 指向 window 的函数不再指向 window,而是变成了 undefined。

2. 函数中的 this
函数在不同情况下,其 this 的指向也不同。

2.1 对象下的方法
方法也是一个函数,如果通过对象调用一个函数,函数的 this 就会指向这个对象。

say函数作为对象下的方法,在被调用后,其 this 指向的是他所在的对象,在这里就是 person 对象。

2.2 原型链上方法的 this
原型链上的方法,this 指向的也是调用该方法的对象。

Object.create 做就就是将参数作为原型,创建一个对象。

所以 object 的第一原型就是 proto 对象。

number1 和 number2 都是 object 变量的属性,但却可以被 sum 方法中的 this 访问到,所以在原型链的方法中,this 指向的就是调用该方法的对象。

2.3 getter / setter 下的 this
getter 和 setter 下的 this 也会指向调用该 getter 和 setter 的对象。

getter 和 setter 本质上也可以理解成两个函数,作为对象下的函数,在调用的时候 this 也会指向该对象。

2.4 作为 DOM 节点的事件处理器
作为 DOM 节点的事件处理器的时,函数的 this 会指向这个 DOM 对象。

<div>
  <button>点击我</button>
</div>

<script>
  document.querySelector('button').addEventListener('click', function() {
    this.innerHTML = '被点击了!';
  });
</script>

2.5 作为一个内联的事件处理器
内联的事件处理器,其 this 指向的是 DOM 节点自身。

<div>
  <button onclick="console.log(this); console.log(this === document.querySelector('button'))">点击我</button>
</div>

2.6 其他大部分情况下
排开上述的几个情况,剩下的函数大部分情况下在调用时,this 指向的是全局对象,在浏览器中就是 window 对象。

function fn() {
  console.log(this);

  console.log(this === window);
}

fn();

这样调用函数,其 this 指向的就是 window 对象了。

有的时候可能会搞混以下情况:

var object = {
  username: '咸鱼',
  fn: function() {
    console.log(this.username);

    function thisTest() {
      console.log(this.username);

      console.log(this === window);
    }

    thisTest();
  },
};

object.fn();

这里 thisTest 方法输出的 username 就会是个 undefined,因为他的 this 指向的是 window,因为他不属于 object 对象的一个方法,所以 this 就指向了 window。在回调函数中经常会碰到这个问题:

var info = {
  account: '123',
  password: '456',
  login: function(cb) {
    setTimeout(function() {
      cb({
        account: this.account,
        password: this.password,
      });
    }, 1000);
  }
};

info.login(function(info) {
  console.log(info);
});

这里回调函数获取的账号和密码是 undefined,原因就是 this 的指向问题。

通常会使用保留上层 this 的方式解决这个问题。

var info = {
  account: '123',
  password: '456',
  login: function(cb) {
    var _this = this;

    setTimeout(function() {
      cb({
        account: _this.account,
        password: _this.password,
      });
    }, 1000);
  }
};

info.login(function(info) {
  console.log(info);
});

这样就能解决这个问题。

另外一个情况也很容易混淆 this :

var object = {
  user: 'no.1',
  say: function() {
    console.log(this.user);
  },
};

var say = object.say;

object.say(); // 输出:"no.1"
say(); // 输出:undefined

这是因为把 object 下的 say 方法单独赋值给 say 变量的时候,其就作为了 window 下的一个方法,所以他的 this 指向的是 window。

在严格模式中,这种情况下的 this 会变成 undefined。

2.7 构造函数
在 JavaScript 构造函数也被成为 对象构造器,用于产生对象。

构造函数的声明和普通函数几乎没有区别:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

var point = new Point(1, 2);

console.log(point.x); // 输出:1
console.log(point.y); // 输出:2

构造函数使用 new 关键字来构造对象。所以当一个函数被使用 new 关键字调用时,这个函数就会作为一个构造函数。

3. 修改this

3.1 call 方法和 apply 方法
函数具有 call 方法和 apply 方法,这两个方法可以在调用函数的时候指定函数的 this。

var object = {
  user: 'no.1',
};

function say() {
  console.log(this.user);
}

say(); // 输出:undefined
say.call(object); // 输出:"no.1"
say.apply(object); // 输出:"no.1"

通过 call 和 apply 方法将 say 函数执行时候的 this 设置为 object 对象。

call 方法从第二个参数开始,表示是要传递给当前函数的参数。

var object = {
  user: 'no.1',
};

function fn(arg1, arg2, arg3) {
  console.log(
    this,
    arg1,
    arg2,
    arg3,
  );
}

fn.call(object, 1, 2, 3);

apply 的第二个参数是个数组,数组里面的项会按数组的顺序作为参数传递给函数。

var object = {
  user: 'no.1',
};

function fn() {
  console.log(
    this,
    arguments,
  );
}

fn.apply(object, [1, 2, 3]);

通过 arguments 关键字就可以看到当前函数的参数,通常在需要修改 this ,又不确定参数的情况下,会使用 apply 来修改 this。

3.2 bind

bind 方法用于给一个函数永久绑定一个指定的 this,bind 不会修改原函数,会返回一个新的函数。

var obj1 = { value: '今天打砖' };
var obj2 = { value: '明天打转' };

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

var bindFn1 = fn.bind(obj1)
var bindFn2 = bindFn1.bind(obj2);

bindFn1();
bindFn2();

可以看到 bindFn1 被绑定了 obj1 作为 this,之后不论怎么操作,他的 this 都会是 obj1。

这篇关于JavaScript中this指向问题的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!