JavaScript this 指向

201 阅读4分钟

总结

  • 函数通过this在运行时需要确定其运行环境
    • 当做值传递和返回
    • 当做对象和构造函数
  • 动态绑定、事件监听
    • this自然就指向了本节点对象
    • 动态绑定的事件本就是为节点对象的属性(事件名称前面加'on')重新赋值为一个匿名函数
    • 函数在执行时就是在节点对象的环境下
  • 构造函数
    • 指向该对象
    • 运行后会返回一个对象,该对象的 proto 指向 构造函数 的 prototype
  • 定时器
    • setInterval(obj.fun,1000); // this指向window对象
    • setInterval('obj.fun()',1000); // this指向obj对象
  • 箭头函数中的this
    • this固定指向当前定义时所在的对象

定义

1:this永远指向一个对象

2:this的指向完全取决于函数调用的位置(谁调用指向谁)

函数中的 this

  • 函数通过this在运行时需要确定其运行环境
    • 当做值传递和返回
    • 当做对象和构造函数

当做值传递和返回

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

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

B.f = A.f;
B.f()   // 姓名:李四
A.f()   // 姓名:张三

A.f属性被赋给B.f = 将A对象将匿名函数的地址赋值给B对象

image.png

当做对象和构造函数

function foo() {
    console.log(this.a);
}
var obj2 = {
    a: 2,
    fn: foo
};
var obj1 = {
    a: 1,
    o1: obj2
};
obj1.o1.fn(); // 2

obj1对象的o1属性值是obj2对象的地址,而obj2对象的fn属性的值是函数foo的地址;函数foo的调用环境是在obj2中的,因此this指向对象obj2。

面向对象

function Foo() {
    getName = function () {
        console.log(1);
    };
    return this;
}

Foo.getName = function () {
    console.log(2);
};

Foo.prototype.getName = function () {
    console.log(3);
};

var getName = function () {
    console.log(4);
};

function getName() {
    console.log(5);
}

Foo.getName();

getName();

Foo().getName();

getName();

new Foo.getName();

new Foo().getName();

new new Foo().getName();
// 变量提升:var-提前声明 function-提前声明+定义
// 加括号有参数,不加括号没有参数
// 不是私有变量找上级作用域
// new Foo() 创建实例要找原型 
// 2
// 4
// 1
// 1
// 2
// 3
// 3

image.png

事件绑定中的this

行内绑定

<input type="button" value="按钮" onclick="clickFun()">
<script>
    function clickFun(){
        this // 此函数的运行环境在全局window对象下,因此this指向window;
    }
</script>

<input type="button" value="按钮" onclick="this">
<!-- 运行环境在节点对象中,因此this指向本节点对象 -->
  • 当前运行环境下没有clickFun函数,浏览器就在整个环境中寻找一个叫clickFun的函数并执行这个函数,所以函数内部的this就指向了全局对象window

  • 如果不是一个函数调用,直接在当前节点对象环境下使用this,那么显然this就会指向当前节点对象

动态绑定、事件监听

<input type="button" value="按钮" id="btn">
<script>
    var btn = document.getElementById('btn');
    btn.onclick = function(){
        this ;  // this指向本节点对象
    }
</script>
  • 动态绑定的事件本就是为节点对象的属性(事件名称前面加'on')重新赋值为一个匿名函数,this自然就指向了本节点对象

  • 事件监听中this指向的原理与动态绑定基本一致

构造函数中的this

function Pro(){
    this.x = '1';
    this.y = function(){};
}
var p = new Pro();

image.png

  • 当 JS 引擎指向到第3步的时候,会强制的将this指向新创建出来的这个对象

window定时器中的this

var obj = {
    fun:function(){
        this ;
    }
}

setInterval(obj.fun,1000);      // this指向window对象
setInterval('obj.fun()',1000);  // this指向obj对象
  • setInterval() :window对象下内置的一个方法。第一个参数是一个函数,第二个参数则是执行前面函数或者代码的时间间隔

    • setInterval(obj.fun,1000) 将obj.fun的地址当做参数传递给了 setInterval 方法,1000毫秒后,函数的运行就已经是在window对象下了,其中的this则指向的全局window对象

    • setInterval('obj.fun()',1000) 中传入的一段可执行的 JS 代码;1000毫秒后当 JS 引擎来执行这段代码时,则是通过 obj 对象来找到 fun 函数并调用执行,那么函数的运行环境依然在对象 obj 内,所以函数内部的this也就指向了 obj 对象

  • 定时器是window的方法,所以会指向window

image.png

箭头函数中的this

  • 箭头函数内部并没有绑定this的机制,所以this固定指向当前定义时所在的对象

  • 上下文环境不做变化,this为全局对象,即this定义在顶层环境

  • 内部的this就是外层代码块的this

var isObject = {
        a: 'hhh',
        functions: () => {
            console.log("对象:",this);
        }
    }
isObject.functions();
//输出结果:对象:Window {postMessage: , blur: , focus: , close: , parent: Window, …}
  • 同样是对象方法,箭头函数里的this指向的是window对象
var isObject = {
        a: 'hhh',
        functions: () => {
            this.a = 0
            console.log("结果:",this.a);
        }
    }
isObject.functions();
//输出结果:结果:0
  • 在isObject对象functions方法内部定义了一个属性a,它属于this全局对象,所以输出结果为0。

  • this 不是只能指向window

function myFunction() {
     var innerfunction = () => {
        console.log('x:', this.x);
     }
     return innerfunction;
 }

var test = myFunction.call({x: 1});

test();
//输出结果:1
  • this此时指向myFunction里的对象{x:1}

  • 箭头函数本身并不能绑定this,所以它不能使用apply,call,bind方法来改变上下文环境

引用:

  1. 彻底搞懂JavaScript中的this指向问题 - 知乎 (zhihu.com)
  2. www.cnblogs.com/mogebw/p/12…