js中this的指向问题

this指向性问题在开发过程中,可以说是时时刻刻都在,自己也知道一些this指向的区别,但是并没有细致的研究过,今天看到https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this里面的解释很详细,摘录一些留着自己以后复习复习。

函数的 this 关键字在 JavaScript 中的表现略有不同,此外,在严格模式和非严格模式之间也会有一些差别。

一、在全局环境中

在全局执行环境中(在任何函数体外部),this都是指向全局对象。在浏览器中,window对象即是全局对象:

console.log(this); //Window
var a = 1;
console.log(window.a);  //1
this.b = 3;
console.log(b); // 3
console.log(window.b) //3

二、在函数环境中

  在函数内容,this指向取决于函数调用的方式:

function f(){
"use strict"; //使用严格模式
console.log(this); } f(); // window ;使用严格模式时,输出undefined
这里我理解为实际调用函数的是浏览器的window.f();实际并非如果,在严格模式下,返回值:false,因为f是被直接调用的,而不是作为对象的属性或方法调用的(如 window.f())。浏览器可能在支持严格模式时没有正确实现这个功能,于是它们错误地返回了window对象。
this指向如何发生改变?
1、一般想到的是call和apply方法:将一个对象作为call或者apply的第一个参数,this将会被绑定到这个参数对象上
var obj = {parent:'男'};
var parent = '28';
function child(obj){
    console.log(this.parent);
}
child(); // 28  
child.call(obj); //
child.apply(obj); //

2、bind方法,调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,不管函数是怎样调用的。

function f(){
  return this.a;
}
var g = f.bind({a:"js"});
console.log(g()); // js

var h = g.bind({a:'html'}); // this已经被绑定bind的第一个参数,不会重复绑定,输出的值还是js
console.log(h()); // js

var o = {a:css, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // css, js, js

3、箭头函数

官方有解释,箭头函数引入的其中一个原因,就是其不绑定this;在箭头函数中,箭头函数的this被设置为封闭的词法环境的,换句话说,箭头函数中的this取决于该函数被创建时的环境。

var objProject = this;
var foo = (() => this);
console.log(foo());  // window
console.log(objProject);  // window
console.log(foo() === objProject ); // true
// 作为对象的一个方法调用
var obj = {foo: foo};
console.log(obj.foo() === objProject ); // true
// 尝试使用call来设定this
console.log(foo.call(obj) === objProject ); // true
// 尝试使用bind来设定this
foo = foo.bind(obj);
console.log(foo() === objProject ); // true

4、作为对象的方法调用时

当函数作为对象的方法被调用时,this指向调用的该函数的对象:

var obj = {
  a: 37,
  fn: function() {
    return this.a;
  }
};
console.log(obj.fn());  // 37

请注意,这样的行为,根本不受函数定义方式或位置的影响。在前面的例子中,我们在定义对象obj的同时,将函数内联定义为成员 fn。但是,我们也可以先定义函数,然后再将其附属到obj.fn。这样做会导致相同的行为:

var obj = {a: 47};
function independent() {
  return this.a;
}
obj.fn = independent;
console.log(obj);  //{a:47,fn:f}
console.log(obj.fn()); //  47

对于在对象原型链上某处定义的方法,this指向的是调用这个方法的对象,就像该方法在对象上一样

var o = {
  f: function() { 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5

在这个例子中,对象p没有属于它自己的f属性,它的f属性继承自它的原型。虽然在对 f 的查找过程中,最终是在 o 中找到 f 属性的,这并没有关系;查找过程首先从 p.f 的引用开始,所以函数中的 this 指向p。也就是说,因为f是作为p的方法调用的,所以它的this指向了p

5、作为构造函数

当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。

虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象(如果返回值不是一个对象,则返回this对象)。

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); //  37
function C2(){
  this.a = 37;
  return {a:38};
}
o = new C2();
console.log(o.a); //  38,手动设置了返回对象

6、作为DOM事件处理函数

当函数被用作事件处理函数时,它的this指向触发事件的元素(一些浏览器在使用非addEventListener的函数动态添加监听函数时不遵守这个约定)。

// 被调用时,将关联的元素变成蓝色
function bluify(e){
  console.log(this === e.currentTarget); // 总是 true
  // 当 currentTarget 和 target 是同一个对象时为 true
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}
// 获取文档中的所有元素的列表
var elements = document.getElementsByTagName('*');
// 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}

关于this问题的一道面试题:

var baz = 0;
let foo = {
    bar:function() {
        console.log(this,this.baz); 
        return this.baz;
    },
    baz:1
};
let foo2 = {
    baz:2
};

let a = foo.bar();  //作为对象的方法调用,this指向调用函数的对象,即foo
let b = foo.bar.call(foo2); //使用call方法将this绑定到第一个参数对象向,此时,this指向foo2
let fn = foo.bar;
console.log(fn);
let c = fn(); //let fn创建的对象,此时,fn = function(){...},此时函数执行时,默认指向全局window对象
let d;
(function test(){
  d = arguments[0]()
})(foo.bar);   // arguments.callee包括了一个函数的引用去创建一个arguments对象,它能让一个匿名函数很方便的指向本身,即此时this指向arguments类数组对象
console.log(a,b,c,d);

结果如下:

原文地址:https://www.cnblogs.com/layaling/p/10650366.html