zoukankan      html  css  js  c++  java
  • 对javascript this的理解

    对于this的理解,大部分时间都比较模糊,最近几天做了一些研究,记录一下

    首先应该明白,this是执行上下文的一个属性,它的值取决于执行上下文,执行上下文和函数调用方式相关,定义一个function的时候会激活一个上下文,关于上下文的介绍,参考《对javascript执行上下文的理解》一文。

    this的几种使用场景:

    一 、全局代码中的this

    在全局的上下文中,this始终是全局对象本身,看代码:

    this.a = 10;
    alert(window.a);//10
    
    b = 20;
    alert(this.b);//20
    
    var c = 30;
    alert(this.c);//30

    二、function中的this

    要彻底理解function,应该明白this的赋值原理,讲this赋值之前,先来看一下javascript的引用类型(reference type), 引用类型的值可以看作一个对象,包含两个属性,propertyName 标识属性的值,base标识该属性的拥有者,

    {
    
      base : <base object>,
    
      propertyName : <property name>
    }

    javascript处理引用类型的值只可能有两种情况:① 处理一个标识符 ②属性访问符

    先看标识符,把标识符处理成引用类型包含 声明变量,函数名,形参和全局对象中未识别的属性名

    如下

    var foo = 10;
    function bar(){}

    操作的中间结果中,引用类型的值分别被处理成如下所示:

    var fooReference = {
      base: global,
      propertyName: 'foo'
    };
     
    var barReference = {
      base: global,
      propertyName: 'bar'
    };

    属性访问器都应该熟悉。它有两种变体:点(.)语法(此时属性名是正确的标示符,且事先知道),或括号语法([])

    var foo = {
      bar : function(){}
    }
    foo.bar();
    foo['bar']();

    在中间计算的返回值中,我们有了引用类型的值。

    var fooBarReference = {
    base: foo,
    propertyName: 'bar'
    };

    那么引用类型和this的赋值有什么关系呢,在javascript中,一个函数上下文中确定this值的通用规则如下:

    在一个函数上下文中,this由调用者提供,由调用函数的方式来决定。如果调用括号()的左边是引用类型的值,this将设为引用类型值的base对象(base object),在其他情况下(与引用类型不同的任何其它属性),这个值为null。不过,实际不存在this的值为null的情况,因为当this的值为null的时候,其值会被隐式转换为全局对象。

    #demo1

    function foo(){
      alert(this);
    }
    foo();//this-> global

    上面提到,标识符包含函数名,即foo被当成引用类型的值来处理,处理过程中值为

    var fooBarReference = {
      base: global,
      propertyName: 'foo'
    };

    所以执行上下文中的this被赋值为global

    #demo2

    var foo = {
      bar : function(){
        alert(this);
      }
    }
    foo.bar();//this->foo

    demo2中方法调用属于属性访问器的方式,base被置为foo

    #demo3 看一个调用方式,

    var name ="i am from window";
    var foo = {
      name : "i am in foo",
      getName : function(){
        alert(this.name);
      }
    }
    var bar = foo.getName;
    bar();//i am from window
    
    foo.getName();//i am in foo

    bar属于标识符,解析成引用类型的值后base为global,foo.getName属性访问器访问方式调用方法,base 为foo,为什么用表达式的不同形式激活同一个函数会不同的this值,答案在于引用类型(type Reference)不同的中间值

    三、函数调用和非引用类型

    当调用括号的左边不是引用类型而是其它类型,这个值自动设置为null,结果为全局对象

    (function () {
      alert(this); // null => global
    })();

    在这个例子中,我们有一个函数对象但不是引用类型的对象(它不是标示符,也不是属性访问器),相应地,this值最终设为全局对象。

    四、引用类型和this为null

    有一种情况是这样的:当调用表达式限定了call括号左边的引用类型的值, 尽管this被设定为null,但结果被隐式转化成global。当引用类型值的base对象是被活动对象时,这种情况就会出现。

    下面的实例中,内部函数被父函数调用,此时我们就能够看到上面说的那种特殊情况。

    function foo() {
      function bar() {
        alert(this); // global
      }
      bar(); // the same as AO.bar()
    }

    活动对象总是作为this返回,值为null——(即伪代码的AO.bar()相当于null.bar())。这里我们再次回到上面描述的例子,this设置为全局对象。

    五、构造方法中的this

     构造方法中的this比较简单,

    function Foo(){
      this.a = 'inner';
      this.getA = function(){
        alert(this.a);
      }
    }
    
    var f1 = new Foo();
    f1.a;// inner
    f1.getA();//inner

    new Foo()执行的时候,首先先创建一个空对象{},然后把对象作为this传入到构造方法Foo()中执行初始化操作,然后把标识符f1指向该对象。

     六、调用函数中手动修改this

    在函数原型中定义的两个方法(因此所有的函数都可以访问它)允许去手动设置函数调用的this值。它们是.apply和.call方法。他们用接受的第一个参数作为this值,this 在调用的作用域中使用。这两个方法的区别很小,对于.apply,第二个参数必须是数组(或者是类似数组的对象,如arguments,反过来,.call能接受任何参数。两个方法必须的参数是第一个——this。

    var b = 10;
     
    function a(c) {
      alert(this.b);
      alert(c);
    }
     
    a(20); // this === global, this.b == 10, c == 20
     
    a.call({b: 20}, 30); // this === {b: 20}, this.b == 20, c == 30
    a.apply({b: 30}, [40]) // this === {b: 30}, this.b == 30, c == 40
  • 相关阅读:
    老陈与小石头运算代码
    第五次作业
    老陈与小石头
    简易四则运算
    四则运算
    对git的认识
    第一次作业
    arcgis-tomcat-cors
    jquery deferred promise
    springloaded hot deploy
  • 原文地址:https://www.cnblogs.com/teamobaby/p/3844894.html
Copyright © 2011-2022 走看看