您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

JavaScript this

当前执行的环境对象,在非严格模式下,总是指向对象,在严格模式下可以是任意值。(MDN)

this 指向的是当前的上下文环境,所以不同情况下的 this 指向也不同。

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

全局对象和宿主环境相关,在浏览器下,全局对象就是 window 对象,在 node.js 中,全局对象是 global 对象。

window === this; // :true

新的标准提供了 globalThis 关键字来全局对象,这样就能抹平宿主的差异来操作处理全局对象了。

在不同情况下,其 this 的指向也不同。

也是,如果通过对象,的 this 就会指向这个对象。

var person = {
  age: ,
  name: '鸽子王',
  skill: '放鸽子',
  say: function() {
    console.log('来一段自我介绍:');
    console.log('我是' + this.name);
    console.log('我今年' + this.age + '岁');
    console.log('我最擅长' + this.skill);
  },
};

person.say();

say作为对象下的,在被后,其 this 指向的是他所在的对象,就是 person 对象。

原型链上的,this 指向的也是该的对象。

var __proto__ = {
  sum: function() {
    return this.number1 + this.number2;
  },
};

var object = Object.create(__proto__);

object.number1 = ;
object.number2 = ;

console.log(
  object.sum(),
); // :3

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

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

number1number2 都是 object 变量的,但却可以被 sum 中的 this 访问到,所以在原型链的中,this 指向的就是该的对象。

gettersetter 下的 this 也会指向该 gettersetter 的对象。

var object = {
  _name: '鸽子王',

  get name() {
    return this._name;
  },

  set name(val) {
    console.log(val);
    this._name = val;
  }
};

console.log(object.name); // :鸽子王

object.name = '鸽子天王'; // :鸽子天王

console.log(object.name); // :鸽子天王

gettersetter 本质上也可以理解成两个,作为对象下的,在的时候 this 也会指向该对象。

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

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

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

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

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

这个规则有局限性,只有最外层的 this 符合这个规则。

<div>
  <button onclick="function  { console.log(this) }; ;">点击我</button>
</div>

test 的 this 指向的是全局对象 window

排开上述的几个情况,剩下的大部分情况下在时,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();

这里 thisTestusername 就会是个 undefined,因为他的 this 指向的是 window,因为他不属于 object 对象的,所以 this 就指向了 window。

在回调中经常会碰到这个问题:

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

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,
      });
    }, );
  }
};

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

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

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

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

var point = new Point(, );

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

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

在构造被后,其内部的 this 会指向对象,具体的可以参考 构造 章节。

具有 callapply ,这两个可以在的时候指定的 this。

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

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

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

通过 callapply 将 say 执行时候的 this 设置为 object 对象。

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

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

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

fn.call(object, , , );

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

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

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

fn.apply(object, [, , ]);

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

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

bind 还有更多灵活的,参数也可以绑定,有关 bind、call、apply 这三个的更详细的信息可以查阅对应的文档。

理解好 this 的处理机制可以设计出更加完善的 JavaScript 应用程序。

this 在 ES6 的箭头中的表现也有所不同,可以查阅 ES6 中有关箭头的。


联系我
置顶