JavaScript中this之全面解析

this一直都是一个谈论的话题,其实我感觉this不是仅仅看一篇this的总结就能理解的东西;this是一个综合的知识体现:它需要你对原型、作用域和引用的综合理解,才能透彻理解这个多变的this;小菜我在这里献丑一下了;

为什么要用this

首先看两端代码:

(1)about this

 function sayName(){
             return this.name.toUpperCase();
         }
         function intro(){
               var myself = "Hello,I am "+sayName.call(this); 
               console.log(myself);
         }
         var me = {
            name : "jack"
         }

         var you ={
            name : "rose"
         }

         sayName.call(me);
         sayName.call(you);

         intro.call(me); //Hello,I am JACK
         intro.call(you);//Hello,I am ROSE

(2)显示传递上下文

function sayName(context){
             return context.name.toUpperCase();
         }
         function intro(context){
               var myself = "Hello,I am "+sayName(context); 
               console.log(myself);
         }
         var me = {
            name : "jack"
         }

         var you ={
            name : "rose"
         }

         sayName(me); 
         sayName(you);

         intro(me);  //Hello,I am JACK
         intro(you);  //Hello,I am ROSE

上面两段代码,可以看到一样的效果;

  • 通过this隐式”传递”一个对象的应用,看起来简洁、容易复用;
  • 显式传递上下文,结构复杂的话,会使代码变得越来越复杂,或许参数context就看着越来越混乱

this的误解

误解:this理解成指向函数自身

上代码:

 function foo(num){
            console.log("foo: "+num);
            this.count++;
         }

         foo.count = 0;

         var i;
         for (var i = 0; i < 10; i++) {
                if (i>5) {
                  foo(i);
            }
        }
        console.log(foo.count);
        console.log("window count:"+this.count);

结果

    foo: 6
    foo: 7
    foo: 8
    foo: 9
    0
    window count:NaN

结果可以看出:

  • foo.count依然是0,如果this指向自身的话,怎么不是4呢!!
  • 如果是this指向自身,this.count又怎么会是NaN呢
    原因:这里的this.count其实是在window(也就是global)里面创建了一个count,并不是foo.count,然而初始值是Undefined,所以,在this.count++的过程返回了NaN;

this的绑定规则

通过上面我们可以看出,函数中的this到底指的谁,其实完全取决于函数调用的位置;

默认绑定

 function foo(){
            console.log(this.a);
         }
         var a=2;
         foo();//2
  • 这里foo()是window在调用(window.foo());所以这里的this也就是window,this.a自然是全局的2了;当然,严格模式下会报错的;

    隐式绑定

var a = 3;
         function test(){
             console.log(this.a);
         }
         var obj = {
             a:2,
             foo:test
         }
         obj.foo();//2
  • 结果:obj.foo()是2,分析可以看出,test()函数是不属于obj对象,跟obj没毛线关系,就像声明了一个函数一样;在obj对象里面,有一个属性foo引用,指向test这个函数;所以obj调用foo()的时候,this指向了obj对象,this.a就是2喽;

    再看一个隐式的例子

         var a = "Hello World";
         function test(){
             console.log(this.a);
         }
         var obj = {
             a:2,
             foo:test
         }
         var bar = obj.foo;
         bar();  //Hello World
  • 这里输出的是全局的Hello World;这也更说明obj和test没毛线关系,obj.foo是函数名,一个引用类型,赋值给bar,这时候bar也指向test;所以相当于全局调用test()喽;

    在看一个,传入回调函数会怎样

        var a = "Hello World";
         function test(){
             console.log(this.a);
         }
         function doFoo(fn){
            fn();    //调用位置
         }
         var obj = {
             a:2,
             foo:test
         }
         doFoo(obj.foo);  //Hello World
  • 这里把obj.foo,(函数的引用/名字)作为doFoo函数的参数,在里面才调用;这时候同上一个例子一样,也相当于执行test();

再再看一个

     var name = "Hello";
        var obj = {
          name: 'World',
          foo: function() {
            console.log(this.name);
          },
          foo2: function() {
            console.log(this.name);
            setTimeout(this.foo, 1000);
          }
        }
      obj.foo2();
  • 结果先输出World,1S后输出Hello;
  • 第一次是 foo2 中直接输出”World”,指向 obj 这个对象
  • setTimeout 也只是一个函数而已,把 this.foo 当作一个参数传给 setTimeout 这个函数,就像上面的fn,和obj无关了,所以输出Hello

    显示绑定

  function foo(){
            console.log(this.a);
         }
         var obj ={
            a:2
         }
         foo.call(obj);//2
  • 强制把它的this绑定到obj上;

new绑定

使用new初始化构造函数,在这个过程一定要透彻的知道做了那些事!!!

使用new操作符经历4个步骤:

  • 创建一个新对象;
  • 将构造函数的作用域给新对象(因此this就指向了这个新对象);
  • 执行构造函数中的代码(为这个新对象添加属性)
  • 返回新对象

看个面试题或许就明白了

function MyObj(){
            this.p.pid++;
         }
         MyObj.prototype.p = {"pid":0};
         MyObj.prototype.getNum = function(num){
             return this.p.pid + num;
         }

         var _obj1 = new MyObj();
         var _obj2 = new MyObj();
         console.log(_obj1.getNum(1)+_obj2.getNum(2)); //7
  • 结果是7,分析:在new MyObj()过程都会执行this.p.pid++,根据原型链,自己找不到去原型里面找,这里的pid是引用类型所以每次都会++,this.p.pid++最终得到2,同时this的作用域分别是_obj1和_obj2;

当你好好去理解面向对象里面的东西,这些就迎刃而解了,当然还有箭头函数指定this,这个我还没有深入研究;以后会补上;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值