JavaScript this

JavaScript this

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

 

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

 

1. 全局下的 this

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

 

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

 

window === this; // 输出:true

代码块

预览

复制

图片描述

 

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

 

2. 函数中的 this

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

 

2.1 对象下的方法

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

 

var person = {

  age: 14,

  name: '鸽子王',

  skill: '放鸽子',

  say: function() {

    console.log('来一段自我介绍:');

    console.log('我是' + this.name);

    console.log('我今年' + this.age + '岁');

    console.log('我最擅长' + this.skill);

  },

};

 

person.say();

代码块

预览

复制

图片描述

 

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

 

2.2 原型链上方法的 this

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

 

var __proto__ = {

  sum: function() {

    return this.number1 + this.number2;

  },

};

 

var object = Object.create(__proto__);

 

object.number1 = 1;

object.number2 = 2;

 

console.log(

  object.sum(),

); // 输出:3

代码块

预览

复制

图片描述

 

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

 

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

 

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

 

2.3 getter / setter 下的 this

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

 

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); // 输出:鸽子天王

代码块

预览

复制

图片描述

 

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 οnclick="console.log(this); console.log(this === document.querySelector('button'))">点击我</button>

</div>

代码块

预览

复制

图片描述

 

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

 

<div>

  <button οnclick="function test() { console.log(this) }; test();">点击我</button>

</div>

代码块

预览

复制

test 函数的 this 指向的是全局对象 window。

 

图片描述

 

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 关键字调用时,这个函数就会作为一个构造函数。

 

在一个构造函数被调用后,其内部的 this 会指向一个对象,具体的内容可以参考 构造函数 章节。

 

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。

 

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

 

4. 小结

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

 

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

 

JavaScript this

52/80

目录

书签

收藏

A

大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值