JS中的This

This的含义

首先,this在构造函数中可以表示实例对象。

function Person(name,gender){
      this.name = name;
      this.gender= gender;
}

而在其他地方,this则表示属性和方法当前所在的对象。this的值就是在点之前的这个对象,即调用该方法的对象。

不管在什么场合,This总是返回一个对象!

例子:方法中的this

let user = {
  name: "John",
  age: 30,

  sayHi() {
    // "this" 指的是“当前的对象”
    alert(this.name);
  }
};
user.sayHi(); // John

这里调用sayHi()的点之前的对象是user,因此this指向user。

结论:以“方法”的语法调用函数时:object.method(),调用过程中的 this 值是 object。

因为对象的属性可以赋值给另一个对象,所以this的指向也是可以改变的。

var A = {
  name: '张三',
  describe: function () {
    return '姓名:'+ this.name;
  }
};

var B = {
  name: '李四'
};

B.describe = A.describe;
B.describe() // "姓名:李四"

B.describe的属性是从A得到的。此时B.describe中this的指向就指向了自己。B也就变成了这样:

var B = {
  name: '李四'
  describe: function () {
    return '姓名:'+ this.name;
  }
};

上面的代码也可以这样写:

function f() {
  return '姓名:'+ this.name;
}

var A = {
  name: '张三',
  describe: f
};

var B = {
  name: '李四',
  describe: f
};

A.describe() // "姓名:张三"
B.describe() // "姓名:李四"
// f中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

后三种调用的运行环境都是全局环境,因此this指向了window
可以这样理解,JavaScript 引擎内部,obj和obj.foo储存在两个内存地址,称为地址一和地址二。obj.foo()这样调用时,是从地址一调用地址二,因此地址二的运行环境是地址一,this指向obj。但是,上面后三种情况,都是直接取出地址二进行调用,这样的话,运行环境就是全局环境,因此this指向全局环境。后三种情况等同于下面的代码。

// 情况一
(obj.foo = function () {
  console.log(this);
})()
// 等同于
(function () {
  console.log(this);
})()

// 情况二
(false || function () {
  console.log(this);
})()

// 情况三
(1, function () {
  console.log(this);
})()

如果this所在的方法不在对象的第一层,这时this只是指向当前一层的对象,而不会继承更上面的层。

var a = {
  p: 'Hello',
  b: {
    m: function() {
      console.log(this.p);
    }
  }
};

a.b.m() // undefined

因为a.b.m方法在a对象的第二层,这时方法中的this指向了a.b。所以它找不到a中的p属性。也就是说,上面的a.b.m() == (a.b).m()

使用this时的其它注意事项

  1. 避免多层this
    在函数中多层使用this会导致深层this指向不明。
var o = {
  f1: function () {
    console.log(this);
    var f2 = function () {
      console.log(this);
    }();
  }
}

o.f1()
// Object
// Window

上面的代码实际上可以视为这样

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

var o = {
  f1: function () {
    console.log(this);
    var f2 = temp();
  }
}

解决方法有二。一是用一个临时变量来记住this,二是使用箭头函数。

var o = {
  f1: function() {
    console.log(this);
    var that = this;
    var f2 = function() {
      console.log(that);
    }();
  }
}

o.f1()
// Object
// Object

箭头函数的this指向自己的上一层的this。下例中f2的this就指向了f1的this。

var o = {
  f1: function() {
    console.log(this);
    var f2 = ( () => console.log(this) )();
  }
}

o.f1()
// Object
// Object

顺便一提,如果使用了JS的严格模式。若函数内部的this指向了顶层对象,就会直接报错。

  1. 在处理数组时使用this。
    数组的mapforeach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。
var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    });
  }
}

o.f()
// undefined a1
// undefined a2

同样的,里面的this指向了window对象。
解决方法之一同上,用一个中间变量记住this。还有一个方法是把this作为foreach的第二个参数,固定它的运行环境。

var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach(function (item) {
      console.log(this.v + ' ' + item);
    }, this);
  }
}

//也可以用箭头函数改写:
var o = {
  v: 'hello',
  p: [ 'a1', 'a2' ],
  f: function f() {
    this.p.forEach((item) => {
      console.log(this.v + ' ' + item);
    });
  }
}


o.f()
// hello a1
// hello a2

3.不在回调函数里用this
回调函数中的this往往会改变指向,最好避免使用。

var o = new Object();
o.f = function () {
  console.log(this === o);
}
// jQuery 的写法
$('#button').on('click', o.f);

上面代码中,点击按钮以后,控制台会显示false。原因是此时this不再指向o对象,而是指向按钮的 DOM 对象,因为f方法是在按钮对象的环境中被调用的。这种细微的差别,很容易在编程中忽视,导致难以察觉的错误。

为了解决这个问题,可以采用一些方法对this进行绑定,也就是使得this固定指向某个对象,减少不确定性。`

原文地址:https://www.cnblogs.com/Nullc/p/12876422.html