资讯专栏INFORMATION COLUMN

浅谈-this

archieyang / 1224人阅读

摘要:回调函数中调用在回调函数中一般有两种情况回调函数为匿名函数时,回调函数的会指向,需要对回调函数。回调函数为箭头函数时,回调函数的会指向他的直接上层。

浅谈-this

this简单而又神秘,使用场景多变而又复杂,这造就了它成为了初级javascript开发人员不愿接触的东西,高级javascript都想探究的东西。文本亦是对this的致敬。

this是什么?
this是当前执行环境的上下文,通常由函数的调用方式决定其值。

this的原理

首先,从函数的调用开始

函数的调用一般有三种情况(ES5中)

1.foo(p1,p2);
2.obj.foo(p1,p2);
3.foo().call(context,p1,p2);//或者apply

通常情况下,大部分童鞋常用的都是前两种方式,只有在不得不绑定context的情况下才会使用第三种。其中,第三种方式,才是函数调用的正确方式。

foo().call(context,p1,p2);

之所以,我们在使用前两种方式也能正常的运行,这其实就是一种语法糖而已,在js运行机制中,会把前两种调方式,当做下面的方式进行处理

foo(p1, p2) 等价于  
foo.call(undefined, p1, p2)

 obj.foo(p1, p2) 等价于
 obj.foo.call(obj, p1, p2)  

因此,如果我们以后再调用函数时,能准确的找到context,就可以唯一的确认this的值

this的使用场景

3.1 全局环境使用

 无论是否在严格模式下,在全局执行环境中(在任何函数体外部)this 都指向全局对象。

// 在浏览器中, window 对象同时也是全局对象:
console.log(this === window); // true
var a=1;
console.log(this.a) //1
console.log(window.a) //1

3.2 普通函数中调用

  在非严格模式下,且this的值没有被调用函数设置,this 的值默认指向全局对象。
   funnction func(){
     console.log(this)
   }
   //浏览器环境中
   func()  // window
   //node环境中
   func()  // global
  
  在严格模式下,this的值如果不设置,就是是undefined
  
   funnction func(){
     "use strict"
     console.log(this)
   }
  func() === undefined; // true

3.3 作为对象中的方法调用

var obj={

    name:"我是对象obj",
    ofun:function(){
    console.log(this.name)
    }
}
var name="我是全局name";
var func= obj.ofun;
obj.ofun(); //我是对象obj
func(); //我是全局name

这里有两点需要注意:

   1.函数作为对象的方法进行调用时,this指向当前的对象。                  
   2.对象中的函数方法名存储的仅是一个函数的地址(地址中会有该函数的属性:[[value]、[[writable]]、[[enumerable]]、[[congifable]])
   当把一个对象的方法赋值给另一个变量(例如:func)时,引擎会将函数多带带保存在内存中,然后再将函数的地址赋值给foo属性的value属性。

3.4 构造函数中使用

  this在构造函数中使用,值为实例化的对象

function Fun(name){
     this.name=name;
     this.speak=function(){
        console.log(this.name);
     }
   }
   var fun1=new Fun("jack");
   fun1.speak();
   var fun2=new Fun("rose");
   fun2.speak();//rose

3.5 bind/call/apply

this再被bind/call/apply强制绑定上下文执行环境时,属于硬绑定。
 
  function foo(somerthing){
     console.log(this.a);
   }
   var obj={
     a:2
   }
   var bar = function(){
     foo.call(obj);
   };
   bar(); //2
   //硬绑定的bar不可能再修改它的this
   bar.call(window);//2
 }

硬绑定的典型应用场景就是创建一个包裹函数,传入所有的参数并返回接收到的所有值;

  function foo(somerthing){
     console.log(this.a,something);
     return this.a +something;
   }
   var obj={
     a:2
   }
   var bar = function(){
     return foo.apply(obj,arguments);
   };
   var b=bar(3);// 2 3
   console.log(b);//5

由于硬绑定是一种非常常用的模式,所以在ES5中提供了内置的方法Function.prototype.bind,它的用法如下;

   function foo(somerthing){
     console.log(this.a,something);
      return this.a +something;
   }
   var obj={
     a:2
   }
   var bar=foo.bind(obj);
   var b=bar(3);// 2 3
   console.log(b);//5

call,apply,bind方法的区别:

  a:第一个参数都是要绑定的上下文执行环境,即this的值。
  b:都可在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
  c:call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。
  d:改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that/self等变量来固定this的指向。

3.6 回调函数中调用

  在回调函数中一般有两种情况:
   1. 回调函数为匿名函数时,回调函数的this会指向window,需要对回调函数bind(this)。
   2. 回调函数为箭头函数时,回调函数的this会指向他的直接上层。
   

  var obj = {
      name: "test for call-func",
      ofun: function(){
            //undefined 丢失
            setTimeout(function(){
              console.log(this.name)
            }, 100);
           //work well 硬绑定
            setTimeout(function(){
               console.log(this.name)
            }.bind(this), 100);//test for call-func
           // arrow function  test for call-func
           setTimeout( () => console.log(this.id), 100)
      }
    };

    obj.ofun();

3.7 自执行函数
自执行或者立即执行函数中的this指向Window
首先自执行函数的几种调用方式

//常见的有两种:
(function(){})()    (function(){}())//w3c推荐方式
//只有表达式才能被执行符号()执行
+function test(){}();//+ - ! =等运算符可以使前面的函数成为表达式,加上后面()可立即执行。
//函数声明无法立即执行一个函数,但是函数表达式可以
var a = function(){}();//这种是函数表达式,后面有()可以立即执行。成为一个立即执行函数。
var obj = {
    number: 3,
    xxx: (function () {
        console.log(this + "--")//立即执行函数中的this指向window,因为立即执行函数是window调用的
        console.log(this.number + "~~~")//删除上面一行,此处this.number返回undefined
        return function () {
            console.log(this.number + "】")
            this.number += 7;
            console.log(this + "+")
        }
    })()
}

obj.xxx() //相当于obj.xxx.call(),所以此处的this指向obj
console.log(obj.number) //10

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102849.html

相关文章

  • 浅谈js中的this

    摘要:相信很多刚刚学习的新手都会有同感,当看一段代码时,发现里面有很多,但是这些到底是指向哪里却没有那么清楚,为了搞清楚这些到底是什么情况,特地花点时间总结如下几点最普遍的表示全局对象表示全局对象输出为解析设置全局变量初始值为,当调用函数之后改变 相信很多刚刚学习js的新手都会有同感,当看一段js代码时,发现里面有很多this,但是这些this到底是指向哪里却没有那么清楚,为了搞清楚这些th...

    GHOST_349178 评论0 收藏0
  • 浅谈Javascript闭包中作用域及内存泄漏问题

    摘要:将作用域赋值给变量这里的作用域是,而不是将作用域赋值给一个变量闭包返回浏览器中内存泄漏问题大家都知道,闭包会使变量驻留在内存中,这也就导致了内存泄漏。 上一章我们讲了匿名函数和闭包,这次我们来谈谈闭包中作用域this的问题。 大家都知道,this对象是在运行时基于函数的执行环境绑定的,如果this在全局就是[object window],如果在对象内部就是指向这个对象,而闭包却是在运行...

    source 评论0 收藏0
  • 浅谈OOP Javascript [1]

    摘要:工厂模式优点集中实例化,可以传参等缺点分不清属于哪个对象我们先来谈谈优点,看例子集中实例化返回实例化对象返回返回不难看出,工厂模式比上面的例子减少了很多代码。 ECMAscript开发的两种模式:1.过程化 2.OOP(面向对象) 面向对象的语言有一个标志,那就是类的概念,而通过类可以创建任意多个具有相同属性的方法的对象。但是ECMAscript中没有类的概念! 又谈作用域 首先...

    xinhaip 评论0 收藏0
  • 浅谈原型式继承、借助构造函数、组合方式继承

    摘要:想要解决这样的问题的话,可以借助构造函数也可以叫做伪造对象或经典继承。这种方式实现非常简单,就是在子对象的构造函数中调用父对象的构造函数。 原型式继承 原型式继承,就是一定一个函数,该函数中创建一个临时性的构造函数,将作为参数,传入的对象作为这个构造函数的原型,最后返回这个构造函数的实例对象 /*定义函数:用于实现对象之间的继承 参数: obj:表示继承关系中的父级对象...

    wangjuntytl 评论0 收藏0
  • 浅谈在JS中使用Object的watch方法监控对象属性

    摘要:对其的解释为概述监视一个对象的某个属性是否发生变化在该属性变化时立即触发指定的回调函数语法参数想要监视值是否发生变化的指定对象的某个属性的属性名称当指定的属性发生变化时执行的回调函数在内查看其声明如下可以看到这两个方法是只针对内核的浏览器使 MDN 对其的解释为: 概述: 监视一个对象的某个属性是否发生变化,在该属性变化时立即触发指定的回调函数. 语法: object....

    noONE 评论0 收藏0

发表评论

0条评论

archieyang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<