美文网首页
前端学习笔记之this——懂不懂由你,反正我是懂了

前端学习笔记之this——懂不懂由你,反正我是懂了

作者: astak3 | 来源:发表于2018-10-20 20:47 被阅读0次

    this

    this对于初学 JS 的新人来说,是一道坎,看到this就晕头晕脑,脑容量一下不够用了。

    先来说下判断this结论

    1. this是函数调用时call的第一个参数
    2. this只有在函数执行的时候才能被确定,实际指向调用它那个对象(上一级)

    先来看下函数常用的几种调用方式

    fn(a,b)
    fn.name(a,b)
    var f = fn.name; f(a,b)
    fn.call(undefined,a,b)
    fn.apply(undefined,[a,b])
    

    上面三种调用方法对于新人很熟悉,而对后面两种方法比较陌生,自然也就弄不明白this含义了。

    改写下函数的调用方式就会发现这两种是等价的,回到上面说的结论,call的第一个参数是thisab才是传进去的参数。

    fn(a,b) === fn.call(undefined,a,b) === window.fn.apply(window,[a,b])
    

    明白了这点,大部分的this就不难判断了,新人在判断this时只需改写函数调用方式就能知道this指向了。

    this例子

    下面方法中暂且不讨论严格模式,this的指向
    例子1:

    var user = 'window'
    function fn(){
        var user = 'object';
        console.log(this.user); //windwow
    }
    fn();    //改写 window.fn.call(window)
    

    fn是全局对象window的方法

    例子2:

    var user = 'window'
    var obj = {
        user:'object',
        fn:function(){
            console.log(this.user);  //object
        }
    }
    obj.fn();    //改写 obj.fn.call(obj)
    

    这里的fn是被obj调用的,所以fn内部的this指向obj内部的user

    你可能会有疑惑了,这里是不是可以改写成window.obj.fn.call(window),往下看

    例子3:

    var user = 'window'
    var obj = {
        user:'object',
        fn:function(){
            console.log(this.user);  //object
        }
    }
    window.obj.fn();    //改写 window.obj.fn.call(window.obj)
    

    先看下面例子

    例子4:

    var user = 'window'
    var obj = {
        user:'object',
        fn1:{
            user:'function',
            fn2:function(){
                console.log(this.user)    //function
            }
        }
    }
    obj.fn1.fn2();    //改写 obj.fn1.call(obj.fn1)
    

    例子3中正常情况下都是把window给省略的,这里写出来是为了和例子4做对比。

    假设例子4中obj对象是不是window下的方法,而是和window平级(实际不存在这种假设,容易理解)。

    这里是链式调用,this的最终指向是调用它的上一层对象fn1,但是不能改写成obj.fn1.call(fn1),只有window可以省略。

    例子5:

    var user = 'window'
    var obj = {
        user:'object',
        fn1:{
            user:'function',
            fn2:function(){
                console.log(this.user)    //window
            }
        }
    }
    var a = obj.fn1.fn2;
    a()        //改写 window.a.call(window)
    

    先看下面例子

    例子6:

    var a = {user:'window'}
    var obj = {
        user:'object',
        fn1:{
            user:'function',
            fn2:function(){
                console.log(this.user)    //window
            }
        }
    }
    
    obj.fn1.fn2.call(a);
    

    看到例子5和例子6是不是已经晕了。

    例子5中,var a = obj.fn1.fn2只是赋值,并没用执行,而真正执行的时候,awindow下的方法,所以fn2内部的this指向window下的user

    例子6中,call的第一个参数是a,那this肯定指向auser,因为显示绑定优先级高于隐示绑定。

    那你可能要问什么是显示绑定,什么是隐示绑定呢?

    obj.fn()    //隐示绑定
    obj.fn.call(obj)    //显示绑定
    
    

    也就是说你改写后的调用就是显示绑定。

    new构造函数

    例子7:

    function Fn(){
        this.user = 'object';
    }
    var a = new Fn();
    console.log(a.user); //object
    

    例子7中,因为构造函数的this指向构造出来的实例,所以a是用new构造出来的对象,那么this就是指向a

    构造函数中要注意的一点是:默认情况下,构造函数是没有return,但是非要加一个return的话。

    1. 如果return的是引用类型值,那么构造函数的this就指向return的对象
    2. 如果return的是基本类型值,那么构造函数的this就指向构造出来的实例化函数

    this基本应用就是这些,做一些实操练习巩固一下

    this实操

    实操1:

    function X(){
        return object = {
            name:'object',
            f1(x){
                x.f2()        //② 改写 options.f2.call(options)
            },
            f2(){
                console.log(this)
            }
        }
    }
    
    var options = {
        name:'options',
        f1(){},
        f2(){
            console.log(this)   //③ 运行这个this,打印 options 函数
        }
    }
    
    var x = X();
    x.f1(options);    //① 改写 object.f1.call(object,options)
    

    看到this就马上改写,不改写就做,肯定错。

    分析

    1. 首先把x.f1(options)改写object.f1.call(object,options)
    2. x.f1(options)调用object对象内部f1方法,把options函数作为参数传入,所以 object内部f1(x)中的xoptions函数
    3. f2内部的this指向options

    实操2:

    function X(){
        return object = {
            name:'object',
            f1(x){
                x.f2.call(this)     //② 这里是显示绑定,改写 options.f2.call(object)
            },
            f2(){
                console.log(this)
            }
        }
    }
    
    var options = {
        name:'options',
        f1(){},
        f2(){
            console.log(this)   //③ 运行这个 this 打印 object
        }
    }
    
    var x = X()
    x.f1(options)   //① 改写 object.f1.call(object,options)
    

    分析

    1. 首先把x.f1(options)改写object.f1.call(object,options)
    2. f1内部的this指向object
    3. x.f2.call(this)改写options.f2.call(object),这里的.call(this)是显示指定
    4. f2内部的this就是object

    实操3:

    function X(){
        return object = {
            name:'object',
            options:null,        //③ options = options
            f1(x){
                this.options = x    //② 改写 object.options = options
                this.f2()            //③ 改写 object.f2.call(object)
            },
            f2(){
                this.options.f2.call(this)    //④ 显示绑定,改写
     object.options.f2.call(object)
            }
        }
    }
    
    var options = {
        name:'options',
        f1(){},
        f2(){
            console.log(this)    //⑤运行这个 this,打印 object
        }
    }
    
    var x = X()
    x.f1(options)   //① 改写 object.f1.call(object,options)
    

    分析

    1. 首先把x.f1(options) 改写object.f1.call(object,options)
    2. f1内this指向objectoptions作为参数传进来
    3. this.options = x改写object.options = options,同时也把this.f2()改写称object.f2()
    4. this.options.f2.call(this) 改写object.options.f2.call(object),.call(this)是显示绑定
    5. f2内部的this就是object

    相关文章

      网友评论

          本文标题:前端学习笔记之this——懂不懂由你,反正我是懂了

          本文链接:https://www.haomeiwen.com/subject/qeamzftx.html