JavaScript —— this指向问题

20180812 修改一
20180816 修改二
转载:https://zhuanlan.zhihu.com/p/42145138?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io

综:

普通函数:

  • this总是代表它的直接调用者(js的this是执行上下文),例如 obj.func ,那么func中的this就是obj;
  • 在默认情况(非严格模式下,未使用 ‘use strict’),没找到直接调用者,则this指的是 window;
  • 在严格模式下,没有直接调用者的函数中的this是undefined;
  • 使用call,apply,bind(ES5新增)绑定的,this指的是绑定的对象;

箭头函数:

  • 箭头函数没有自己的this,它的this是继承而来;
  • 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象。 定义它的时候,可能环境是window;
  • 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this;

    this要点

    1. this永远指向一个对象
    2. this指向取决于函数调用的位置

    注:
    JS中,一切皆对象,运行环境也是对象,函数都是在某个对象下运行,而this就是函数运行时所在的对象(环境)
    但JS支持运行环境动态切换 => this指向也是动态的,很难事先确定到底指向哪个对象。

基本原理

function fun(){
    console.log(this.s);
}

var obj = {
    s:'1',
    f:fun
}

var s = '2';
obj.f();  //1
fun();  //2

obj.f()的调用中,因为运行环境在obj对象内,因此函数中的this指向对象obj;而在全局作用域下调用 fun() ,函数中的 this 就会指向全局作用域对象window。

JS中,数组、函数、对象都是引用类型,在参数传递时引用传递
obj对象两个属性,属性值类型不同,内存中表现形式也不同:属性 f 存储 fun 所在内存地址。
函数调用时

因为函数在js中既可以当做值传递和返回,也可以当做对象和构造函数,所有函数在运行时需确定其当前的运行环境,this从而诞生。=> this会根据运行环境的改变而改变,函数中的this也只能在运行时才能最终确定运行环境

运行环境动态切换规则理解

var A = {
    name: '张三',
    f: function () {
        console.log('姓名:' + this.name);
    }
};
​
var B = {
    name: '李四'
};
​
B.f = A.f;  //A对象将匿名函数的地址赋值给B对象
B.f()   // 姓名:李四
A.f()   // 姓名:张三

匿名函数

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。

——————————————————————-

事件绑定

行内绑定

  • 在html节点内,以节点属性的方式绑定,属性名(onclick)是事件名称前面加’on’,属性的值则是一段可执行的 JS 代码段;
  • 事件触发时,属性值作为JS代码被执行,当前运行环境下没有clickFun函数,因此浏览器就需要跳出当前运行环境,在整个环境中寻找并执行这个函数,所以函数内部的this就指向了全局对象window
<input type="button" value="按钮" onclick="clickFun()">
<script>
    function clickFun(){
        this // 此函数的运行环境在全局window对象下,因此this指向window;
    }
</script>
  • 如果不是一个函数调用,直接在当前节点对象环境下使用this,那么显然this就会指向当前节点对象
<input type="button" value="按钮" onclick="this">
<!-- 运行环境在节点对象中,因此this指向本节点对象 -->

动态绑定与事件监听

<input type="button" value="按钮" id="btn">
<script>
    var btn = document.getElementById('btn');
    btn.onclick = function(){
        this ;  // this指向本节点对象
    }
</script>
  • 动态绑定是为节点对象的属性(事件名称前面加’on’)重新赋值为一个匿名函数,因此函数在执行时就是在节点对象的环境下,this自然就指向了本节点对象;
  • 事件监听中this指向的原理与动态绑定基本一致,所以不再阐述;

——————————————————————-

构造函数

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

构造函数执行
new 一个构造函数并执行函数内部代码的过程是这个五个步骤。当 JS 引擎指向到第3步的时候,会强制将this指向新创建出来的这个对象

——————————————————————-

定时器setInterval

  • setInterval() 是window对象下内置方法,接受两个参数,第一个参数允许是一个函数或者是一段可执行的 JS 代码,第二个参数则是执行前面函数或者代码的时间间隔
var obj = {
    fun:function(){
        this ;
    }
}
​
setInterval(obj.fun,1000);      // this指向window对象
setInterval('obj.fun()',1000);  // this指向obj对象
  • setInterval(obj.fun,1000) 的第一个参数是obj对象的fun,因为 JS 中函数可以被当做值来做引用传递,实际就是将这个函数的地址当做参数传递给了 setInterval方法。换句话说, setInterval 的第一参数接受了一个函数,那么此时1000毫秒后,函数的运行就已经是在window对象下了,也就是函数的调用者已经变成了window对象,所以this指向全局window对象
  • setInterval(‘obj.fun()’,1000) 中的第一个参数,实际则是传入的一段可执行的 JS 代码;1000毫秒后当 JS 引擎来执行这段代码时,则是通过 obj 对象来找到 fun 函数并调用执行,那么函数的运行环境依然在 对象 obj 内,所以函数内部的this指向 obj 对象。

——————————————————————-

函数对象的call()、apply()方法

  • 函数作为对象提供了call(),apply() 方法,他们也可用来调用函数,接受一个对象作为参数,用来强制指定本次调用时函数中this的指向
call(obj,arg1,arg2…argN);
参数说明:
obj:函数内this要指向的对象
arg1,arg2…argN :参数列表,参数与参数之间使用一个逗号隔开
var lisi = {names:'lisi'};
var zs = {names:'zhangsan'};
function f(age){
    console.log(this.names);
    console.log(age);

}
f(23);//undefined//将f函数中的this指向固定到对象zs上;
f.call(zs,32);//zhangsan
apply(obj,[arg1,arg2…,argN]);
参数说明:
obj:函数内this要指向的对象
arg1,arg2…argN :参数列表,要求格式为数组
var lisi = {name:'lisi'}; 
var zs = {name:'zhangsan'}; 
function f(age,sex){
    console.log(this.name+age+sex); 
}
//将f函数中的this指向固定到对象zs上;
f.apply(zs,[23,'nan']);

猜你喜欢

转载自blog.csdn.net/qq_21980099/article/details/81611650
今日推荐