JS笔记《this》

105 阅读4分钟

概述

  • this就是函数运行时所在的对象(环境),它总是返回一个对象。换种说法,this就是属性或方法当前所在的对象。
var person = {
  name: '张三',
  say: function(){
   return '姓名.' + this.name;
  }
}

person.say()  // '姓名.张三'
// this.name 表示 name 属性所在的那个对象,
// 由于 this.name 是在 say 方法中调用,而 say 方法所在的当前对象是 person,
// 因此 this 指向 person, this.name 就是 person.name
  • 由于对象的属性可以赋值给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。
//...引用上述 person对象
var person2 = {
  name: '李四'
}
person2.say = person.say;
person2.say();  // '姓名.李四'
// person 对象的 say 方法被赋给了 person2,
// 于是 person2.say 就表示 say 方法所在的对象是 person2,
// 所以 this.name 就指向 person2.name
  • 只要函数被赋给另一个变量,this的指向就会变。
var A = {
  name: '张三',
  say: function(){
      return '姓名.' + this.name;
  }
}
var name = '李四';
var fn = A.say;
fn(); // '姓名.李四'
// A.say 方法被赋给了变量 fn,
// fn 当前所在的对象是顶层对象(window)
// 所以 this 指向 window,就指向了 window.name

使用场合

全局环境

  • 全局环境使用this,它指的就是顶层对象window
function f() {
  console.log(this === window);
}
f() // true

构造函数

  • 构造函数中的this指的就是实例对象。
function Car(name){
  console.log(this);  // Car {}
  this.name = name;
}
new Car('Audi')

对象的方法

  • this的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变this指向。
var obj ={
  foo: function () {
    console.log(this);
  }
};

obj.foo() // obj

// 情况一
(obj.foo = obj.foo)() // window
// 情况二
(false || obj.foo)() // window
// 情况三
(1, obj.foo)() // window
// 以上三种情况obj.foo就是一个值,这个值真正调用
// 的时候运行环境已经是 window了,所以this不再指向obj

解释:objobj.foo存储在两个地址,称为地址一地址二obj.foo()这样调用时,是从地址一调用地址二,因此地址二的运行环境是地址一,所以this指向obj。但是上面三种情况都是直取出地址二进行调用,这样的话运行环境就是全局环境,因此this指向全局。

  • 如果this所在的方法不在对象的第一层,这时this只是指向当前一层的对象,而不会继承更上层。
var a = {
  b:{
    c: function(){
      console.log('p:' + this.p);
    }
  },
  p: 'hello p!'
}
a.b.c();   // p:undefined
// 由于 this 只是指向当前一层的对象,所以 this 指向b,b 对象里没有 p 属性,所以 undefined
// 改成如下方式可以正常访问:
var a = {
  b: {
    c: function () {
      console.log('p:' + this.p);
    },
    p: 'hello p!'
  },

}
a.b.c(); // p:hello p!
// this 指向 b,b 对象里存在 p属性,所以可以正常调用

var f = a.b.c;
f();   // p:undefined
// f 的运行是在window对象中,this指向 window,所以 undefined

var f1 = a.b;
f1.c(); // p:hello p!
// 将 c()所在的对象赋值给 f1,f1就等同于a.b,f1.c() 相当于 a.b.c(),this 依然指向 a.b,所以正常调用

call()

  • 指定函数内部this的指向:

    • 第一个参数应该是一个对象,如果参数为空、null、undefined,则默认传入全局对象。
    • 第二个开始的参数是函数调用时所需的参数,可以是多个。
var obj = {}

function f(){
  console.log(this);
}

f()                // window
f.call(obj)        // obj{}  this 指向修改为 obj 对象,相当于 obj.xxx
f.call()           // window 参数为空,指向window
f.call(null)       // window 参数为null,指向window
f.call(undefined)  // window 参数为undefined,指向window
f.call(5)   // Number {5}  原始值参数会自动转为对应的包装对象(Number(5)),f 内部的 this 指向包装对象

function add(a, b) {
  return a + b;
}
add.call(this, 1, 2) // 3  add 中的 this 指定为当前环境(window), 1和2为执行 add 函数的参数

apply()

  • call方法一样,唯一区别是接收一个数组作为函数执行时的参数。
function f(x, y, z){
  return x + y + z;
}
f.apply(this, [1,2,3])  //  6   123对应xyz

bind()

  • 将函数体内的this绑定到某个对象,返回一个新的函数。第一个参数是所要绑定this的对象。
var counter = {
  count: 0,
  inc: function(){
    this.count++;
  }
}

var obj = {
  count: 100
}

var func = counter.inc.bind(obj); // 将 counter.inc 中的 this 指向 obj 并返回一个函数
func();   // 执行这个函数,this 就指向 obj
obj.count // 101
  • 第二个开始的参数是函数调用时所需的参数,可以是多个。
function f(x, y, z){
  return x + y + z;
}

var newF = f.bind(this, 1, 2);  // 1、2对应参数x、y
newF(3)  // 3  3对应参数z