• JS中的this


    最近在学习JavaScript面向对象,其中有个难点就是关于this的问题。

    关于this,我们要知道的两个问题,一个是this指向什么?另一个是this可以写在哪?

    关于this的指向

    总的来说,this指向对象,具体要分情况来说。

    两个原则:

    1、this的指向是运行时决定的;

    2、在运行时,函数是谁调用的,this就指向谁。比如说:

    在直接调用时,this指向window对象

    func();//此时的this指向window对象

    函数运行时被谁调用,this就指向谁

    obj1.func(this);//此时的this指向obj1
    
    obj2.func(this);//此时的this指向obj2

    关于this可以写在哪里

    this可以写在全局中或是函数中,下面来看这两种情况:

    一、全局中

    在全局中的this就指向window对象,例如:

    var name = "foodoir";
    this.name === window.name;//true

    在全局中我们很容易将this的值和作用域弄混,其实this的值只与调用时函数所处的执行环境(execution context)相关,与函数作用域没有一点关系。

    二、函数中

    this在函数中的使用又可以分为几种情况

    情况一:简单的函数

    function f(){
    var name = 'foodoir';
    console.log(this.name);
    }
    f();//abc

    情况二:在DOM事件中,事件监听中,this指向该元素本身

    var element = document.getElementById('id');
        element.onclick = function(){
            console.log(this);    //输出相应的元素自身 如input元素[object HTMLInputElement],指向DOM的元素
        }

     情况三:函数作为对象方法,当函数作为对象的方法时,this所指的即为包含该方法的那个对象。

    复制代码
    var o = {
      name:'foodoir',
      say:function(){
      console.log('hello ' + this.name);
      }
    }
    
    o.say();//hello foodoir
    复制代码

    情况四:构造函数情况,当this出现在构造函数中,this的值即为刚new好的那个对象。

    复制代码
    function Person(name,age){
    this.name = name;
    this.age=age;
    }
    var p1 = new Person('foodoir',21);
    var p2 = new Person('jack',33);
    
    p1.name;//foodoir
    
    p2.age;//33
    复制代码

    情况五:函数仅作为函数调用
      在函数只是作为函数调用时,this值为全局变量window。下面这个例子定义了一个全局变量和全局函数,当函数直接调用时,this所指就是window对象;当函数作为对象的方法调用时,this指向o对象。此外,它也很好的解释了this的值只与执行上下文相关,而与函数本身或者说作用域是没有关系的。

    复制代码
        //函数当做函数调用时,this指向全局变量window
        var global = '我是全局变量';
        function f(global){
            alert(this.global);
        }
        f('test');  //输出'我是全局变量'
        var o = {
            f : f,
            global : '对象中的变量'
        }
        o.f('test');  //输出'对象中的变量'
    复制代码

    call和apply

    可以使用call()和apply()方法改变函数的执行环境为指定对象的环境,则this所指的就是那个指定的对象。

    call方法:
    语法:call([thisObj[,arg1[, arg2[, [,.argN]]]]])
    定义:调用一个对象的一个方法,以另一个对象替换当前对象。
    说明:
    call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
    如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。

    apply方法:
    语法:apply([thisObj[,argArray]])
    定义:应用某一对象的一个方法,用另一个对象替换当前对象。
    说明:
    如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
    如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

    直接看下面的例子:

    复制代码
    function Animal(){    
        this.name = "Animal";    
        this.showName = function(){    
            console.log(this.name);    
        }    
    }    
     
    function Cat(){    
        this.name = "Cat";    
    }    
       
    var animal = new Animal();    
    var cat = new Cat();    
        
    animal.showName.call(cat,",");    
    animal.showName.apply(cat,[]);
    //通过call或apply方法,将原本属于Animal对象的showName()方法交给对象cat来使用了。    
    //输出结果为"Cat"    
    复制代码

    call 的意思是把 animal 的方法放到cat上执行,原来cat是没有showName() 方法,现在是把animal 的showName()方法放到 cat上来执行,所以this.name 应该是 Cat

     后面的话:

    关于this,平时在遇到的时候,多想想几个问题:this出现在了哪?this指向什么?什么决定this的值?

    感觉学面向对象有难度,看着例子好像是可以理解,但是实际不会用。每次想写点东西的时候,总觉得自己的思路是混乱的,不知道大家有没有什么好的方法推荐?欢迎大家在下面留言,文中有不对的地方也请指出来,在这里先谢谢了。

    写在前面

    工作有那么一段时间了,但是在工作中,发现自己的理论知识还是有所欠缺。特别是在javascript上,很多东西其实自己属于知道要用这个,但是不知道为什么要这么用...这种情况很是尴尬了,所以写博客的很重要一个目的就是锻炼我自己的总结能力,把学到的东西总结出来,感觉这样能让我更快的去理解所学到的东西。

    ◇ 关于javascript理论

    刚开始做前端的时候还是以完成功能为主,所以忽略掉了理论知识的重要性,但是随着工作的慢慢深入,发现很多原理还是要建立在对理论知识的理解与掌握上。

    作为一个合格的前端工程师,这个确实有点不能忍...所以还是要沉下心来,一点点的去提升自己。话说回来,其实javascript的理论在我看来并没有那么的枯燥难懂,但是需要你去实验、去调试。兴趣永远是学习最好的动力,我想保持这份兴趣,持续的去研究javascript的理论,去探寻其中的秘密和让人惊叹的地方。

    关于this

    闲话扯了那么多,希望各位看官不要在意...只是本人一点点心声罢了...言归正传,关于this,其实在我看来确实算是javascript中很基础、很重要、也是很难理解的一个点;

    this的定义,借助下阮一峰大大的总结,感觉比较好理解些:

    this是Javascript语言的一个关键字。
    它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。比如,
    1
    2
    3
    function test(){
      this.x = 1;
    }
    随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是,调用函数的那个对象。

    this的指向

    其实this之所以难以理解,主要就是在不同情况下,this的指向都是不一样的。以下几种情况,基本归纳了常见的this的指向:

    1.在全局代码或者普通的函数调用中,this指向全局对象,在浏览器里面既为window对象。
    1
    2
    3
    4
    5
    6
    console.log(this);//输出window
     
    function foo(){
        console.log(this);
    }
    foo();//输出window
    在浏览器环境里运行上述代码,两处输出结果均为window对象。
     
    2.通过call或apply方法调用函数,this指向方法调用的第一个参数。
    1
    2
    3
    4
    5
    6
    var obj = {name:'test'};
    function foo(){
        console.log(this);
    }
    foo.call(obj);//输出obj
    foo.apply(obj);//输出obj
    call和apply的区别在于call的调用需要两个参数,用逗号做分割,而apply只需要一个参数,这个参数必须是数组;
     
    插入的小知识点:
    利用apply的特点实现不创建新的对象把两个数组拼装成一个数组:
    1
    2
    3
    4
    var arr1 = [1, 2 , 3],
        arr2 = [4, 5, 6];
    Array.prototype.push.apply(arr1, arr2);
    console.log(arr1);//输出[1, 2, 3, 4, 5, 6]

    call与apply的定义:

    call方法: 

    语法:call(thisObj,Object)
    定义:调用一个对象的一个方法,以另一个对象替换当前对象。
    说明:
    call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。 
    如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。 
     
    apply方法: 
    语法:apply(thisObj,[argArray])
    定义:应用某一对象的一个方法,用另一个对象替换当前对象。 
    说明: 
    如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。 
    如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数
     
    3.调用对象的方法,this指向该对象。
    1
    2
    3
    4
    5
    var obj = {name:'test'};
     function foo(){
        console.log(this);
    }
    obj.foo = foo; obj.foo();//输出obj
    这个也就是所谓的谁调用,指向谁
     
    4.构造方法中的this,指向新构造的对象。
    1
    2
    3
    4
    5
    6
    7
    function C(){
        this.name = 'test';
        this.age = 18;
        console.log(this);
    }
    var c = new C();//输出 c
    console.log(c);//输出 c
    执行以上代码后,控制台输出均为c所指向的对象。当new操作符用于函数时,会创建一个新对象,并用this指向它
     

    特殊情况

    上述四种情况基本概述了this的常见指向,但是也有些特殊的情况下,this的指向并不在上诉的范围中:

    a.bind方法

    这个方法会创建一个函数实例,其this值会被绑定到传给bind()函数的值。也就是说会返回一个新函数,并且使函数内部的this指向为传入的第一个参数:

    1
    2
    3
    4
    5
    6
    7
    window.color = 'red';
    var o = {color : 'blue'};
    function sayColor(){
        alert(this.color)
    }
    var objectSayColor = sayColor.bind(o);
    objectSayColor();//blue

    b.eval

    对于eval函数,其执行时候似乎没有指定当前对象,但实际上其this并非指向window,因为该函数执行时的作用域是当前作用域,即等同于在该行将里面的代码填进去。下面的例子说明了这个问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var name = "window";
     
    var Bob = {
        name: "Bob",
        showName: function(){
            eval("alert(this.name)");
        }
    };
     
    Bob.showName();

    总结

    • 默认的,this指向全局对象
    • 当一个函数被作为一个父对象的属性调用时,函数中的this指向父对象
    • 当一个函数被new运算符调用时,函数中的this指向新创建的对象
    • 当使用call或apply调用函数时,函数代码中的this被设置为call或apply中的第一个参数。如果第一个参数是null或不是个对象,this指向全局对象。

    其实除去上面的特殊情况,我们只要记住这四种情况,那么对于this的指向应该就有一个较为清楚的认识。

    博文中如有叙述不清或者错误,欢迎各位批评指正!完结撒花~

  • 相关阅读:
    应用JConsole学习Java GC
    删除MySQL重复数据
    Linux后台运行程序
    Jvm基础(2)-Java内存模型
    一个word合并项目的分布式架构设计
    Jvm基础(1)-Java运行时数据区
    【JPA】01 快速上手
    【Ubuntu】下载安装 20.04.版本 桌面端
    【Ubuntu】下载安装 12.04.5版本 桌面端
    【CentOS】tar包安装Tomcat
  • 原文地址:https://www.cnblogs.com/libin-1/p/5999134.html
Copyright © 2020-2023  润新知