• 正确理解JavaScript中的this关键字


    JavaScript有this关键字,this跟JavaScript的执行上下文密切相关,很多前端开发工程师至今对this关键字还是模棱两可,本文将结合代码讲解下JavaScript的this关键字

    this和对象的关系

    首先来看下面的代码:

    var person = {
    	name:'Theo Wong',
    	gender:'male',
    	getName:function(){
    		console.log(person.name);
    	}
    };
    person.getName();

    定义了一个person对象,对象中包含了name、gender属性,还包括了一个getName的方法,其作用是输出person对象的name。在 这种情况下,我们可以使用this来在person对象中代替person对象本身,所以上面的代码跟下面的直接结果是一样的:

    var person = {
    	name:'Theo Wong',
    	gender:'male',
    	getName:function(){
    		console.log(this.name);
    	}
    };
    person.getName();

    请记住一点:this永远指向的是函数所属的对象!上面的例子中getName的所属的对象是person对象,所以this指代的是person。

    this和全局对象

    我们再来看看再全局对象中,this指代的是什么,我们知道JavaScript是脚本语言,所以JavaScript的执行需要有一个宿主环境, 在浏览器中这个宿主环境就是window对象,所以在全局函数中,this指代的是window对象(除非使用new,call,apply方法来改变 this的指代关系)。懂得了这个关键点,下面的代码就好理解了:

    var a = 1;
    console.log(a);//1
    console.log(this.a);//1
    console.log(window.a);//1

    很多前端开发工程师经常使用在函数名字之前添加个window来调用函数,这是因为在浏览器中全局对象就是window,所有的函数变量都是在window对象之中,所以下面的代码中的this指代window对象就好理解了:

    var a = 1;
    function foo(){
    	var b = 2;
    	console.log(this.a+b);//3
    }
    foo();

    所以说,只要记住:this永远指向的是函数对象的所有者,即this的值是由激活执行上下文代码的调用者决定的,就好理解this的指代关系了。

    函数构造器中的this

    当函数作为构造器使用new关键字实例化时,this的指代关系又是怎样的呢?看下面的代码:

    var Person = function(){
    	this.name = 'Theo Wong';
    }
    var person = new Person();
    console.log(person.name);

    new执行过程会首先执行Person的构造器[[construct]],然后在调用[[call]]方法给this赋值,这个执行过程可以简单理解为三步

    1. 首先建立一个空的对象object,类似var obj={}
    2. 然后将空对象使用Person的call操作,类似Person.call(obj)
    3. 执行完Person之后再return this,完成new过程,赋值给person变量

    所以经过new加工过的函数,this的函数调用者是Person本身,而不是window了。

    嵌套函数中的this

    在嵌套函数中,this的指代关系有会是怎样的呢?看下面的代码:

    var myObject = {
      func1:function() {
         console.log(this); //myObject
         var func2=function() {
            console.log(this); //window
            var func3=function() {
               console.log(this); //window
            }();
         }();
      }
    }; 
    myObject.func1();

    在嵌套函数中,由于嵌套函数的执行上下文是window,所以this指代的是window对象,其实这是ECMA-262-3的一个bug,在最新的ECMA-262-5中已经修复。

    事件处理中的this

    在JavaScript中处理事件函数中,this的指代关系就更加扑朔离迷了。我们建立一个showValue函数,函数内容如下:

    var showValue = function(){
    	console.log(this.value);
    };

    现在有个input,我们给input元素添加click事件,当点击input时触发showValue函数,看看现在的this指代的是什么对象。

    <input id="test" type="text" />

    通过dom.onclick绑定事件

    document.getElementById('test').onclick = showValue;

    运行代码会得到预期的结果,showValue虽然定义在全局对象中,但是当采用了onclick的绑定方式时,showValue是作为dom的onclick方法被调用的,所以它的this应该指代的是dom对象,而不再是window对象。

    写在html标签内

    <input id="test" type="text" onclick="showValue();" />

    当点击dom时,我们获取不到正确的this,这是为什么呢?

    此时的this指代的是window对象,因为window对象中没有定义value的值,所以获取不到this.value。其实此时的不是将showValue函数赋值给dom对象的onclick,而是引用!所以上面的代码跟下面的代码关系是一样的:

    document.getElementById('test').onclick = function(){
        showValue();
    };

    根据上面说的JavaScript嵌套函数的this值,我们可以得出现在showValue的this其实是window。

    通过addEventListener/attachEvent绑定事件监听

    <input type="text" id="test" />
    <script type="text/JavaScript">
    	var dom = document.getElementById('test');
    	id = 'window';
    	function test(){
    		alert(this.id);
    	}
    	dom.addEventListener ? dom.addEventListener('click', test, false) : dom.attachEvent('onclick', test);
    	//addEventListener test
    	//attachEvent window
    </script>


    这种绑定事件监听的方式,attachEvent this是window对象,而addEventListener则是dom对象的。@魔堕轮回 提出来的bug~嘎嘎

    使用call和apply方法改变this

    在Function对象原型(Function.prototype)中有两个方法:call和apply,通过call和apply可以改变 this的值, 它们都接受第一个参数作为调用执行上下文中this的值。它们的不同点就是apply第二个参数为数组,call接收的参数是依次传入的。

    var obj = {
    	name:'Theo Wong',
    	desc:'一个前端开发者'
    };
    var getInfo = function(){
    	console.log(this.name+this.desc);
    };
    getInfo.call(obj);
    //Theo Wong一个前端开发者

    总结

    this是JavaScript的重要关键字,理解掌握this关键字在不同的执行上下文指代关系,才能避免代码犯一些不必要的错误。深入了解JavaScript的代码执行过程,及其执行上下文,推荐阅读《JavaScript的词法作用域

  • 相关阅读:
    Hadoop命令手册
    编程算法
    综合8种子排序算法总结和比较
    android 创建一个新的每次project什么时候 请问自己主动 参加 V7依赖?
    【JDBC】java PreparedStatement操作oracle数据库
    【cocos2dx 加载资源目录】
    Project Euler:Problem 39 Integer right triangles
    矿Java开发学习之旅------&gt;Java排序算法经典的二分法插入排序
    [React Intl] Render Content with Placeholders using react-intl FormattedMessage
    [React Intl] Install and Configure the Entry Point of react-intl
  • 原文地址:https://www.cnblogs.com/52php/p/5657875.html
Copyright © 2020-2023  润新知