最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 春招面试复盘,重拾this~ 【JS Plan】

    正文概述 掘金(jingda)   2021-03-21   551

    春招面试复盘,重拾this~ 【JS Plan】


    文章导图先来一下:

    春招面试复盘,重拾this~ 【JS Plan】

    一、this 初探 ???

    1、为什么要使用this?

    如何更好的理解this,我想需要先了解this解决了什么问题。在写文章的过程中也看了一些其他人写的文章和博客,其中大都是将this是什么,this的使用场景,this的指向。当然这些是需要掌握的一些this知识点。但在开篇之前想先提个问题?

    你知道javascript中为什么需要this吗?

    看到这个问题,我在心里想的就是,this是一个执行上下文的属性,在调用时确定指定什么,但直接问我javascript为什么需要this,可能我一下回不上来。下面就来理一理吧

    让我们先来看看下面这个例子:

    var person = {
      name:'jingda',
      age:'23',
      phone:'1234567',
      FuncHi: function() {
        //实现功能:打印出「你好,我是 jingda,今年 23 岁」
      },
      FuncBye: function() {
        //实现功能:打印出「再见,记得我叫 jingda ,我的电话是1234567
      }
    }
    

    上面这段代码定义了一个person对象,其中有name,age,phone三个属性,以及FuncHi,FuncBye两个方法,各自实现自己的功能。我们可以看到,此时的两个方法中并没有传递任何参数,因此它是无法达到输出这个对象的属性的,当我们尝试采取一些方法,比如说去传递参数,我们可以把代码写成这样:

    var person = {
        ...
        FuncHi: function(name, age){
          console.log('你好,我是 ${name},今年 ${age} 岁')
        },
        FuncBye: function(name, phone){
          console.log('再见,记得我叫 ${name} 我的电话是 ${phone}')
        }
        
    	person.FuncHi(person.name, person.age)
    	person.FuncBye(person.name, person.phone)
    

    可以在控制台打印

    春招面试复盘,重拾this~ 【JS Plan】

    这种传递参数的方式虽然能实现功能,但使用起来就知道,它让代码变得很笨,比如你看调用过程的代码。

    于是我们尝试改进一下调用时的代码,我们可以在调用的时候把person当做参数传入到两个方法中,当方法里需要用到person当中的属性时,自己取就可以了。 于是代码改成这样:

    var person = {
        ...
        FuncHi: function(p){
          console.log('你好,我是 ${p.name},今年 ${p.age} 岁')
        },
        FuncBye: function(p){
          console.log('再见,记得我叫 ${p.name} 我的电话是 ${p.phone}')
        }
    	person.FuncHi(person);
    	person.FuncBye(person);
    

    这样似乎比刚才的代码,参数缩短了很多。

    但是开发者可能最终更想要的代码是

    var person = {
        ...
        FuncHi: function(){
          console.log('你好,我是 ${this.name},今年 ${this.age} 岁')
        },
        FuncBye: function(){
          console.log('再见,记得我叫 ${this.name} 我的电话是 ${this.phone}')
        }
    	person.FuncHi();
    	person.FuncBye();
    

    这么一下就把this丢出来是个啥意思嘞?实际上 this 是隐藏的第一个形参。在你调用 person.FuncHi() 时,这个 person 会「变成」 this。也就是说,参数隐藏了,而我们使用的this.相当于person.

    但this远远不会就只是由对象.出来的,会涉及很多情形,下面再聊哈。

    2、你对this如何定义?

    首先要理解的就是单单这个“this”,在javascript中到底指的是什么呢?这里我参考了 MDN上的解释,得出的结果:

    (话说,我能有什么定义,打扰了。。。)下一个:

    二、不同场合下的this指向 ???

    在这一节会涉及很多this使用场景,因为在浏览器和node下执行的结果可能并不一致,所以这里如果没有特殊说明,即运行在浏览器中。 自己也可尝试哦

    1、全局上下文

    • 浏览器

    春招面试复盘,重拾this~ 【JS Plan】

    • node
    console.log(this) //{}
    

    2、函数上下文

    在非严格模式下:

    • 浏览器

    春招面试复盘,重拾this~ 【JS Plan】 因为this 的值不是由该设置的,所以 this 的值默认指向全局对象,浏览器中就是 window。

    • node
    function f() {
      return this;
    }
    
    console.log(f() === globalThis) //true
    console.log(globalThis) //Object [global]
    

    在严格模式下

    浏览器和node下都是undefined: 春招面试复盘,重拾this~ 【JS Plan】

    function f() {
      "use strict";
      return this;
    }
    
    console.log(f() === undefined) //true
    

    这里在严格模式下,如果进入执行环境没有设置this的值,this会保持为undefined,就像上面这个例子,f()被直接调用,不是作为对象的属性或者方法调用。

    3、构造函数

    当一个函数用做构造函数时,也就是使用了new关键字的时候,它的this就被绑定到正在构造的新对象。 首先来看看构造函数是如何工作的?

    function constructorFun() {
      this.name = 'jingda'
      //当然你可以设置更多值
    
      //当函数具有返回对象的return语句时
      //该对象是new表达式的结果
      //否则,表达式的结果是当前绑定到this的对象
    }
    

    好吧,这里自觉的想到了new的实现原理:

    1、创建一个新的空的对象

    2、把这个对象链接到原型对象上

    3、这个对象被绑定为this

    4、如果这个函数不返回任何东西,那么就会默认return this

    但是new这个关键字,并不是所有返回值都原封不动地返回的。如果返回的是undefined,null以及基本类型的时候,都会返回新的对象;而只有返回对象的时候,才会返回构造函数的返回值。

    好了,new说到这里,继续我们的this,来看下面两个例子:

    function C() {
      this.a = 37;
    }
    var o = new C();
    console.log(o.a);//37
    function C2() {
      this.a = 37;
      return {a:38};
    }
    o = new C2();
    console.log(o.a);//38
    

    因为C中没有return对象,所以this就是指向的创建的实例 ,o.a就是37,而在C2,因为在调用构造函数的过程中,手动的设置了返回对象,与this绑定的默认对象被丢弃了,此时this就是指向return返回的对象,o.a为38

    4、原型链中的this

    首先大致理解一下原型链 JavaScript 常被描述为一种基于原型的语言 ——每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型,并从中继承方法和属性,一层一层、以此类推。这种关系常被称为原型链 (prototype chain)

    来个例子:

    var o = {
      f: function() {
        return this.a + this.b;
      }
    };
    var p = Object.create(o);
    p.a = 1;
    p.b = 4;
    console.log(p.f());//5
    

    我们通过Object.create(o),指定o作为原型对象,创建出了p这个对象实例。但是在对象p上并没有属于它自己的f属性,这个f属性继承于它的原型,也就是o。

    5、对象方法

    当函数作为对象里的方法被调用时,this 被设置为调用该函数方法的对象。该函数方法赋值给另一个对象,就会改变this的指向。

    var obj = {
      name:"jing",
      foo: function () {
        return this.name;
      }
    };
    console.log(obj.foo()); //jing
    

    当 obj.foo() 被调用时,函数内的this 将绑定到 o 对象。

    需要注意的问题!!

    先改一下上面的代码,以便理解:

    var obj = {
      foo: function () {
        console.log(this)
      }
    };
    obj.foo();//指向obj
    
    • 当函数作为一个值,而不是对象的属性或是方法
    (obj.foo = function () {
      console.log(this);
    })()
    //指向全局
    
    • 当this所在的方法不是在对象的第一层,这时this只是指向当前一层的对象,而不会继承更上面的层。
    var a = {
      p: 'jing',
      b: {
        m: function() {
          console.log(this.p);
        }
      }
    };
    a.b.m() //undefined
    

    a.b.m方法在a对象的第二次,该方法的内部this不是指向a,而是指向a.b,如果我们需要打印出p的值:

    var a = {
      b: {
        m: function() {
          console.log(this.p);
        },
        p: 'Hello'
      }
    };
    a.b.m() //'Hello'
    
    • 将嵌套对象内部的方法赋值给一个变量,this依然会指向全局对象。还是上面的例子,当我们这么写:
    var a = {
      b: {
        m: function() {
          console.log(this.p);
        },
        p: 'Hello'
      }
    };
    var hello = a.b.m;
    hello() // undefined
    

    上面这个例子,m是多层对象内部的一个方法,如果将它赋值给hello变量,this指向了顶层对象。如何解决这个问题,可以只将m所在的对象赋值给hello,这样调用时,this的指向就不会变。

    var hello = a.b;
    hello.m() // Hello
    

    6、作为一个DOM事件处理函数

    当函数被用作事件处理函数时,它的 this 指向触发事件的元素

    7、箭头函数下的this

    最后不得不提的是箭头函数有关this指向的问题:

    1、箭头函数没有单独的this,箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

    function Person(){
      this.age = 1;
      setInterval(() => {
        this.age++; //正确地指向 p 实例
      }, 1000);
    }
    
    var p = new Person();
    console.log(p.age);
    

    2、严格模式下不是输出undefined

    var f = () => { 'use strict'; return this; };
    f() === window; // 或者 global
    

    3、使用call(),apply()方法调用一个函数,只能传递参数,不能绑定this

    var person = {
      age:18,
      sum: function(a) {
        var f = a => a + this.age;
        return f(a);
      },
      sumCall: function(a) {
        var f = a => a + this.age;
        var b = {
          age:20
        };
        return f.call(b,a)
        //call的第一个参数是需要绑定到的对象,上,如果成功的话,指向的b age为20,但是下面输出的是19,并没有绑定到b上
      }
    }
    console.log(person.sum(1));//19
    console.log(person.sumCall(1));//19
    

    输出两个都是19,也就是说在sumCall中,f.call(b,a),本来想把this绑定到b上,没有成功。

    三、this使用需要注意的点 ???

    1、避免多层this(包括数组处理方法中的this)

    因为this的指向是不确定的,所以尽量不要在函数中包含多层this:

    var o = {
      name:'jing',
      f1: function() {
        console.log(this.name);
        var f2 = function () {
          console.log(this.name);
        }();
      }
    }
    
    o.f1()
    //node 下执行
    // jing
    // undefined
    

    f2中的this丢失了,指向了全局。

    如果要避免,则需要在f2中改用一个指向外层的变量。

    
    var o = {
      name:'jing',
      f1: function() {
        console.log(this.name);
        var that = this;
        var f2 = function() {
          console.log(that.name);
        }();
      }
    }
    
    o.f1()
    //jing
    //jing
    

    2、 还有一个就是数组map和foreach方法,

    允许提供一个函数作为参数。这个函数内部不应该使用this。会造成和上面一样的丢失this现象,像下面这个例子,f可以去到o的this,但是f中的forEach方法中的this丢失了,指向的全局。因此为undefined。

    var o = {
      v: 'hello',
      p: [ 'a1', 'a2' ],
      f: function f() {
        this.p.forEach(function (item) {
          console.log(this.v + ' ' + item);
        });
      }
    }
    
    o.f()
    //node 下执行
    // undefined a1
    // undefined a2
    

    浏览器中输出这个东西??? 春招面试复盘,重拾this~ 【JS Plan】

    解决的方法:

    • 1、需要在中forEach改用一个指向外层的变量
    f: function f() {
        var that = this;
        this.p.forEach(function (item) {
          console.log(that.v+' '+item);
        });
      }
    
    • 2、将this当作foreach方法的第二个参数,固定它的运行环境
    f: function f() {
        this.p.forEach(function (item) {
          console.log(this.v + ' ' + item);
        }, this);
      }
    

    3、null undefined传入call apply bind

    function foo() {
      console.log(this.a);
    }
    var a = 2;
    foo.call(null) //2
    

    这里的call方法传递的参数是null,this指向的是全局 (严格模式下是undefined)

    四、测试几个题目(答案在结尾)✍️✍️✍️

    1、对象属性方法相关

    const object = {
      message:'hello,world',
      getMessage() {
        const message = 'hello,earth';
        return this.message;
      }
    };
    console.log(object.getMessage());
    

    不熟悉的话可以看 场合5,此时调用的是object中的this。

    2、原型链相关

    function Person(name) {
      this.name = name;
      this.getName = () => this.name;
    }
    const cat = new Person('jing');
    console.log(cat.getName());
    const { getName } = cat;
    console.log(getName());
    

    3、setTimeout()延迟相关

    const object = {
      message:'hello world',
    
      logMessage() {
        console.log(this.message);
      }
    };
    setTimeout(object.logMessage,1000);
    

    4、箭头函数相关

    const object = {
      who: 'World',
     
      greet() {
        return `Hello, ${this.who}!`;
      },
     
      farewell: () => {
        return `Goodbye, ${this.who}!`;
      }
    };
    console.log(object.greet());   
    console.log(object.farewell());
    

    5、指向window

    var length = 4;
    function callback() {
      console.log(this.length);
    }
    const object = {
      length:5,
      method(callback) {
        callback();
      }
    };
    object.method(callback,1,2);
    

    6、最后一个前两天看到的

    var myObject = {
      foo:"bar",
      func:function() {
        var self = this;
        console.log(this.foo);
        console.log(self.foo);
        (function() {
          console.log(this.foo);
          console.log(self.foo);
        }());
      }
    }
    myObject.func();
    

    春招面试复盘,重拾this~ 【JS Plan】 答案(可以自己运行哈)

    有任何问题可以评论区回复,也可以自己查资料,看小黄书。

    好啦,this就先到这了。文章也是看了书看博客看题,总结的一些东西,可能写的并不系统。也可能我理解的不好的地方,欢迎评论区批评建议。

    我是婧大,一名大三学崽,你的建议和点赞是给我最大的鼓励。?

    目前在默默学习中,也在寻找合适的实习岗位,如果有小伙伴一起学习,欢迎加我wx:lj18379991972 ???

    春招面试复盘,重拾this~ 【JS Plan】

    参考链接:

    你不知道的javascript (看书哦,this节)

    MDN this

    网道 javascript教程 this关键字

    饥人谷 -- JS 里为什么会有 this


    起源地下载网 » 春招面试复盘,重拾this~ 【JS Plan】

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元