zoukankan      html  css  js  c++  java
  • javascript中this的指向问题

    使用 JavaScript 开发的时候,很多开发者多多少少会被 this 的指向搞蒙圈,但是实际上,关于 this 的指向,记住最核心的一句话: 

    哪个对象调用函数,函数里面的this指向哪个对象。

    分几种情况谈论下:

    一、普通函数调用

    二、对象函数调用

    三、构造函数调用

    四、apply和call调用

    五、箭头函数调用

    文章同步交流社区地址:http://www.mwcxs.top/page/427.html

    一、普通函数调用

    这个情况没特殊意外,就是指向全局对象-window。

    1、使用let

    /*普通函数调用*/
    let username = "程新松";
    function fn(){
        console.log(this.username);   //undefined
    }
    fn();

    使用node输出的是:undefined

    使用谷歌浏览器console输出的是:undefined

    2、使用var

    var name = "程新松";
    function fn(){
        console.log(this.name);
    }
    fn();

    使用node输出的是:undefined

    使用谷歌浏览器console输出的是:程新松

    3、使用window

    window.username='程新松'
    function fn(){
        console.log(this.username);
    }
    fn();

    使用node输出的是:报错,window没有定义

    使用谷歌浏览器console输出的是:

     

    PS:为什么会出现这个错误呢,因为node里面没有window 对象,浏览器中有window对象。

    4、let和var区别:

    (1)let 允许把变量的作用域限制在块级域中;var 申明变量要么是全局的,要么是函数级的,而无法是块级的。

    let varClass = function(){
        var name='程新松';
        if(true){
            var name='saucxs';
            console.log(name);
        }
        console.log(name);
    }
    varClass();
    // saucxs
    // saucxs

    let letClass = function(){
        let name='程新松';
        if(true){
            let name='saucxs';
            console.log(name);
        }
        console.log(name);
    }
    letClass(); 

    上面的结果说明了let只在{}内使用。

    (2)先let后var

    let subClass = function(){
        let name='程新松';
        if(true){
            var name='saucxs';
            console.log(name);
        }
        console.log(name);
    }
    subClass();

    var 是函数级作用域,相当于一个作用域中有两个n的变量了

    var 作用于整个 subClass ,和let冲突了,let不能重复声明,already been declared=已经被声明

     (3)先var后let

    let subClass = function(){
        var name='程新松';
        if(true){
            let name='saucxs';
            console.log(name);
        }
        console.log(name);
    }
    subClass();

    先申明var,再申明let,这个没有问题。

    二、对象函数调用

     这个相信不难理解,就是哪个函数调用,this指向哪里

    /*对象函数调用*/
    //window.name='程新松';
    //var name='程新松';
    let name='程新松';
    let obj={
        id:201102304,
        fn:function(){
            console.log(this.name);  //undefined
            console.log(this.id);   //201102304
        }
    }
    obj.fn();

    ,,

    很明显,第一次就是输出 obj.name ,但是没有这个name属性,输出的结果undefined。而第二次输出obj.id,有这个id属性,输出 201102304,因为 this 指向 obj 。

     有一种情况需要注意:

    /*需要注意的情况*/
    let obj1={
        a:111
    }
    let obj2={
        a:222,
        fn:function(){
            console.log(this.a);
        }
    }
    obj1.fn=obj2.fn;
    obj1.fn();  //111

     

    这个也不难理解,虽然 obj1.fn 是从 obj2.fn 赋值而来,但是调用函数的是 obj1 ,所以 this 指向 obj1 。

    三、构造函数调用

    /*构造函数调用*/
    let structureClass=function(){
        this.name='程新松';
    }
    let subClass1=new structureClass();
    console.log(subClass1.name);
    
    let subClass=new structureClass();
    subClass.name='成才';
    console.log(subClass.name);

    但是有一个坑,虽然一般不会出现,但是有必要提一下。

    在构造函数里面返回一个对象,会直接返回这个对象,而不是执行构造函数后创建的对象

    let structureClass=function(){
        this.name='程新松';
        return {
            username:'saucxs'
        }
    }
    let subClass1=new structureClass();
    console.log(subClass1);
    console.log(subClass1.name);

     四、apply和call调用

     1、apply和call简单来说就是会改变传入函数的this。

    /*apply和call调用*/
    let obj1={
        name:'程新松'
    };
    let obj2={
        name:'saucxs',
        fn:function(){
            console.log(this.name);
        }
    }
    obj2.fn.call(obj1);

    此时虽然是 obj2 调用方法,但是使用 了 call ,动态的把 this 指向到 obj1 。相当于这个 obj2.fn 这个执行环境是 obj1 。

    call 和 apply 两个主要用途:

    1.改变 this 的指向(把 this 从 obj2 指向到 obj1 )

    2.方法借用( obj1 没有 fn ,只是借用 obj2 方法)

    2、call与apply区别

     call 和 apply 的作用,完全一样,唯一的区别就是在参数上面。

    call 接收的参数不固定,第一个参数是函数体内 this 的指向,第二个参数以下是依次传入的参数。

    apply接收两个参数,第一个参数也是函数体内 this 的指向。第二个参数是一个集合对象(数组或者类数组)

    /*apply和call区别*/
    let fn=function(a,b,c){
        console.log(a,b,c);
    }
    let arrArray=[1,2,3];
    fn.call(window,arrArray);
    fn.apply(window,arrArray);

      五、箭头函数调用

     首先不得不说,ES6 提供了箭头函数,增加了我们的开发效率,但是在箭头函数里面,没有 this ,箭头函数里面的 this 是继承外面的环境

    /*箭头函数调用*/
    let obj={
        name:'程新松',
        fn:function(){
            setTimeout(function(){console.log(this.name)})
        }
    }
    obj.fn();

    不难发现,虽然 fn() 里面的 this 是指向 obj ,但是,传给 setTimeout 的是普通函数, this 指向是 window , window 下面没有 name ,所以这里输出 underfind 。

     换成箭头函数

    //换成箭头函数
    let obj={
        name:"程新松",
        fn:function(){
            setTimeout(()=>{console.log(this.name)});
        }
    }
    obj.fn();

    这次输出 程新松 是因为,传给 setTimeout 的是箭头函数,然后箭头函数里面没有 this ,所以要向上层作用域查找,在这个例子上, setTimeout 的上层作用域是 fn 。而 fn 里面的 this 指向 obj ,所以 setTimeout 里面的箭头函数的 this ,指向 obj 。所以输出 程新松

  • 相关阅读:
    mongodb一个关键字对多个字段同时查询,mongodb $or $and查询
    用Supervisord管理Python进程
    ImportError No module named memcache
    eclipse项目显示标尺
    Eclipse 安装插件后不显示的解决办法
    Flutter入门到放弃笔记(一)--Mac电脑配置Flutter环境
    iOS 动态库、静态库相关
    iOS 获取手机后台音频状态以及类别
    Swift 懒加载
    Swift中@ojbc 重载用法
  • 原文地址:https://www.cnblogs.com/chengxs/p/8679313.html
Copyright © 2011-2022 走看看