• 译文:javascript function中的this


    个人理解+google翻译。如有错误,请留言指正。原文来自MDN: this

    简介

    Javascript中一个函数的this关键字的行为相对其它语言有些不同。在严格模式和非严格模式间也有区别。

    在大多数情况下,this的值由函数如何调用来决定。this值不能在函数执行过程中赋值设置,并且每次函数调用时this值可能也不相同。ES5通过添加bind方法设置函数的this值,无论函数如何被调用。(this值永久不变)

    全局上下文中

    全局执行环境中(函数外部),无论在与不在严格模式下this指向全局对象。

    console.log(this.document === document); //true
    //在web浏览器中,window对象即是全局对象:
    console.log(this === window); // true
    this.a=37;
    console.logn(window.a); //37

    function上下文

    在函数内部,this值依赖于函数如何调用。

    简单调用

    function f2(){
        "use strict";//使用严格模式
        return this;
    }
    f2() === undefined;

    在上面的例子中,this值没有在函数调用的时候被设置。由于代码没有在严格模式下,this值肯定总会是默认为全局对象。

    function f2(){
        "use strict";//使用严格模式
        return this;
    }
    f2() === undefined;

    严格模式下,this值保持在进入执行环境时设置的值。如果this值未定义,则为undefined;this值也能被设置为任意值:如null、42或"I am not this";

    注意:在第二例子中,this值应为undefined,因为f2函数被调用时没有提供任何引用[原文:base],(例如:window.f2())。这一特性在某些浏览器初始支持严格模式时没有实现,造成返回错误的对象:window

    function作为对象方法

    当函数作为对象方法调用时,该函数的this值设为调用该方法的对象。

    在下例中,当o.f()被调用,函数内部this绑定为o对象(inside the function this is bound to the o object).

    var o={
        prop:37;
        f:function(){
            return this.prop;
        }
    };
    console.log(o.f());// 37

    注意:this的这种特性不受其函数如何定义或函数的定义位置的影响。在上例,我们把函数定义为对象o的内部成员f。然而我们也可以轻易的先定义这个函数,后面再把它附加到o.f上,结果是一样的。

    var o ={prop:37};
    function independent{
        return this.prop;
    }
    o.f=independent;
    console.log(o.f());//37

    这段代码表明:函数的调用来自对象o的f方法;同样,this的绑定只受最近参考成员的影响。在下面的例子里,调用该函数的时候,则为对象o.b的g方法。此次函数执行时,函数内的this指向o.b.事实上,与o.b对象是o对象的成员没有任何关系,最近参考才是重要的。

    var o ={prop:37};
    function independent{
        return this.prop;
    }
    o.f=independent;
    o.b{prop:42,g:independent};
    console.log(o.f());//37
    console.log(o.b.g());//42

    function在原型链上

    同样的概念也适用于在原型链上某些地方定义方法。如果该方法定义在对象的原型链上,this指向调用该方法的对象。【假设该方法是对象的成员】

    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

    在上面的例子中,对象o分配给变量p,p没有自己的属性f,p从其原型中继承f属性。原型中f属性的查找最终会在对象o上以一个成员的身份找到;查找开始以p.f为参考,所以函数内的this取值为对象p。由于f作为p的方法被调用,this指向p,这Javascript原型继承一个有意思的特性。

    个人添加了一个Object.create()例子,方便自我解惑:详情请参考MDN:Object.create()

    o = Object.create(Object.prototype, {//对象内属性对应于Object.defineProperties的第二个参数
            // foo is a regular "value property" --foo是一个普通值属性
          foo: { writable:true, configurable:true, value: "hello" },
          // bar is a getter-and-setter (accessor) property --bar是一个getter、setter存取属性
        bar: {
            configurable:false,//默认:false,属性的类型能被修改或该属性可以被删除时为true
            enumerable:false,//默认:false,对象属性枚举属性时显示该属性为true
            //writable:false, //默认:false,当属性值能通过赋值操作而改变时为true
            //value:"hi",//与属性相关联的值。可以是任何有效的JavaScript值(数字,对象,函数等)。
            get: function() { return this.value || 10 },//以一个函数作为getter方法的属性,如果没有指定函数则为undined。返回其属性值
            set: function(value) {this.value=value}//以一个函数作为setter方法的属性,如果没有指定函数则为undined。接收新的参数值成为属性值
        }
    });
    console.log(o.bar);//10
    o.bar="hi";
    console.log(o.bar); //hi

    bar定义中有两行注释,如果取消注释符号,在Firefox下会报错:不允许在指定get 或 set时 指定其value属性或为定义writable属性。[writable为true或false都会报错]

    function作为(Object.defineProperty中的)getter方法或setter方法

    同样的概念再次适用于函数作为getter方法或setter方法。函数用作getter或setter方法则其this绑定到已经设置set或set属性的所属对象。(原文: A function used as getter or setter has its this bound to the object from which the property is being set or gotten.)

    function modulus(){
        return Math.sqrt(this.re * this.re + this.im * this.im);
    }
    var o ={
        re : 1,
        im : -1,
        get phase(){//ES5的写法,还是建议用__defineGetter__这种API比较好,ie7 8 不支持
            return Math.atan2(this.im,this.re);
        },
        set txt(value){
            this.re=value.re;
            this.im=value.im;
        }
    };
    Object.defineProperty(o,'modulus1',{get : modulus,enumerable : true,configurable : true});//ie7 不支持此方法 ie8 不支持get:
    console.log(o.phase,o.modulus1);// -0.78 1.414
    o.txt={re:12,im:3};//o.txt({re:12,im:3});报错:o.txt is not a function
    console.log(o.phase,o.modulus1);//0.24 12.36

    ES5 的getter、setter方法在ie7 8上不支持,汗的没汗了……

    function作为构造函数

    当函数通过new关键字做为构造函数时,函数的this指向该构造函数实例化后的对象。

    注意:构造函数默认返回的对象被this引用,构造函数也可以返回其它对象。如果返回值不是一个对象,那么返回默认this引用的对象。( 原文:while the default for a constructor is to return the object referenced by this, it can instead return some other object (if the return value  isn't an object, then the this object is returned))

    /*
     * Constructors work like this:构造函数以类似下面的方式运行:
     *
     * function MyConstructor(){
     *   // Actual function body code goes here.  Create properties on |this| as
     *   // desired by assigning to them.  E.g.,
     *   // 译:实际的代码放在这里,通过 this 创建需要的属性及赋值。如:
     *   this.fum = "nom";
     *   // et cetera...译:其它代码             
     *   // If the function has a return statement that returns an object, that
     *   // object will be the result of the |new| expression.  Otherwise, the
     *   // result of the expression is the object currently bound to |this|
     *   // (i.e., the common case most usually seen).
     *   //如果构造函数通过return语句返回一个对象,这个对象将会通过new表达式返回的实际对象。
     *   //如果函数体内没有return语句,则通过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

    在c2函数中,因为在构造函数运行并返回了一个对象,this默认绑定的对象则被简单的丢弃。(实际上是使语句this.a = 37;成为废弃代码。也没有完全被废弃,因为它得到运行,只是在没有外部影响的情况下而被排除。)

    通过call或apply方法调用

    函数内使用this关键字,通过call或apply方法调用该函数时,this值被指定为一个特定的对象,全部function继承于Function.prototype(all functions inherit from Function.prototype)

    function add(c,d){
        return this.a + this.b + c + d;
    }
    var o ={a:1,b:3};
    //第一个参数是一个对象作为this,随后的参数作为函数调用参数
    add.call(o,5,7); //1+3+5+7 = 16
    //第一个参数是一个对象作为this,第二个参数是一个数组,该数组成员做函数调用参数
    add.apply(o,[10,20]);//1+3+10+20 = 34

    ES5 bind 方法

    ES5 添加Function.prototype.bind。调用f.bind(someObject)创建与f具有相同内容和作用域的新函数,但原来的函数中的this在新函数中永久指向bind方法第一个参数,不管该函数如何调用。

    function f(){
        return this.a;
    }
    var g = f.bind({a:"azerty"});
    console.log(g()); //azerty
    var o ={a:37,f:f,g:g};
    console.log(o.f(),o.g()); // 37,azerty

    作为DOM事件处理函数

    当function作为事件处理函数,this指向触发该事件的DOM元素。(有些浏览器不支持下面通过addEventListener方法为监听动态添加方法,如:IE)。

    //作为监听器时 改变相关元素为蓝色
    function bluify(e){
        console.log(this === e.currentTarget);     //一直为true
        console.log(e.currentTarget);
        console.log(this === e.target);            //当currentTarge和target为同一对象时为true
        console.log(e.target);
        this.style.backgroundColor="#A5D9F3";
        //e.stopPropagation(); //阻止事件冒泡
    }
    //获取document下元素列表
    var elements = document.body.getElementsByTagName('*');
    //添加bluify方法作为点击事件监听器,使元素被点击后变为蓝色
    for(var i = 0;i < elements.length; i++){
        elements[i].addEventListener('click',bluify,false);
    }

    上面的代码在某个结构层叠在3层或以上的页面下的控制台中(firebug/google chrome console)运行一下,会表现出一种怪异现象,无论点哪个元素,整个页的背景全部变为蓝色。试着把代码e.stopPropagation()的注释取消掉,或审查下元素,就应该知道为什么了。还不懂?请搜索 javascript 事件冒泡 相关资料。

    在内联事件处理中

    当代码在内联处理器中执行时,代码中的this被设为其上有事件监听的DOM元素:

    <button onclick="alert(this.tagName.toLowerCase());">Show this</button>

    上面的警告弹出框显示button。 Note however that only the outer code has its this set this way:【实在翻译不出来了,将就的这么翻译吧:但是要注意,这种方式只有函数外面的代码中的this值才会被设置为事件监听DOM元素】

    <button onclick="alert((function(){return this}()));">Show inner this</button>

    这种情况下,函数内部的this没有被指定,所以该函数返回全局对象或window对象。(即非严格模式下调用代码中的this没有被指定时的默认对象)。

    function's this总结(自加)

    • 指向全局对象
    1. 函数体外部,script标签内直接调用this
    2. 简单调用函数(非严格模式下)
    • 指向对象
    1. 函数作为对象方法(无论函数是否在对象内定义),this指向调用该方法的最近参考对象
    2. 函数在对象的原型链上
    3. 函数作ES5下对象的getter或setter方法
    • 指向实例化对象或普通(hash)对象
    1. 函数作为构造函数或构造函数内返回一个普通对象
    • 指向特定对象
    1. 函数被call或apply调用。如:fun.call(obj,param),fun.apply(obj,[param1,param2])
    • 永久指向一个对象(ES5)
    1. 函数通过bind方法永久指向一个对象,无论该函数如何调用
    • 指向事件触发DOM元素
    1. 函数作为事件处理器(动态添加)
    2. 在内联事件处理器代码中(如果有function(){},则为function的代码外部)的this,如<button onclick="alert(this.tagName.toLowerCase());functiong(){//代码}"></button>

    PS:用脑子里的半吊子英语水平+google翻译+有道翻译 这三种工具耗时3天按个人理解翻译出这篇文章。总算体会到了IT英语翻译的苦闷之处,不过自己也算有了翻译的经验,小自豪一把。如有错误,请列位拍砖指正。谢谢!

  • 相关阅读:
    深入探究分布式锁
    Java的类加载器有几种?什么是双亲委派机制?
    Java的Arrays.sort()方法到底用的什么排序算法
    什么是SPI
    Go语言学习笔记(八)golang 操作 Redis & Mysql & RabbitMQ
    Go语言学习笔记(七)杀手锏 Goroutine + Channel
    Go语言学习笔记(六)net & net/http
    Go语言学习笔记(五)文件操作
    Go语言学习笔记(四)结构体struct & 接口Interface & 反射reflect
    Go语言学习笔记(三)数组 & 切片 & map
  • 原文地址:https://www.cnblogs.com/cyl-record/p/3472758.html
Copyright © 2020-2023  润新知