zoukankan      html  css  js  c++  java
  • Live2D 看板娘

      this关键字:

       JavaScript的this关键字,总是指向一个对象,具体指向哪个对象,是根据运行时函数指向环境动态绑定的。简单来说,this就是谁调用指向谁。具体使用中,this的指向,大致可以分为以下这几种情况:

      1、作为对象的方法调用,this指向该对象

            var obj = {
                a:1,
                getA: function(){
                    alert(this === obj);    //true
                    alert(this.a);        //1
                }
            };
            obj.getA();

      2、作为普通函数调用,this指向全局对象。在浏览器的JavaScript里,全局对象就是window对象。

            var name = 'globalName';
            var getName = function(){
                alert(this.name);
            };
            getName();//globalName      

      或者:

            window.name = "globalName";
            var myObj = {
                name:"sven",
                getName:function(){
                    alert(this.name);
                }
            };
            myObj.getName(); //sven
            var getName = myObj.getName; 
            getName(); //globalName

      上面这个小栗子myObj.getName()和getName()的结果不一样,是因为调用他们的对象不一样,myObj.getName()中的this指向的就是myObj对象,这个对象的name值是"sven",而getName()的this指向的是我们新声明的变量getName,myObj对象的getName()的方法,应用在了变量getName上,这时候this指向的就是全局变量name = "globalName"了。

      由于调用this的对象不同,它的指向也不一样,有时候会有一些困扰,如下代码:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1">我是div1</div>
        <script>
            document.getElementById("div1").onclick = function () {
                alert(this.id);//div1
                var getId = function(){
                    alert(this.id);
                };
                getId();//undefined
            };
        </script>
    </body>
    </html>

      上面的代码中,我们想让getId()的这个回调函数的this.id是div的节点,但是它给我们的是undefined,对于这种情况,我们怎么解决呢?有一个简单的方案,就是把当前的this对象赋值给一个变量,这个被赋值的变量指向的就是当前的this对象,就不会变喽,具体使用如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1">我是div1</div>
        <script>
            document.getElementById("div1").onclick = function () {
                var that = this;
                alert(this.id);//div1
                var getId = function(){
                    alert(that.id);
                };
                getId();//div1
            };
        </script>
    </body>
    </html>

      是不是一个很实用的小技巧?在this作为普通函数调用的时候,我们还需要注意一点就是,在ES5的严格模式下,thi是undefined。

      3、作为构造器调用,这种调用方式,其实就是用new操作符生成一个对象,而this指向的就是这个新的对象。下面的示例帮我们理解一下this的这种调用方式:

            var myClass = function(){
                this.name = 'sven';
            };
            var obj = new myClass();
            alert(obj.name);

      但构造器的这种方式,我们需要注意一个问题,如果构造器显示地返回了一个object对象(只能是对象类型,如果是基础数据类型,则不会影响this的输出),那最终返回的回事这个对象,而不是我们之前定义的this:

            var myClass = function(){
                this.name = 'sven';
                return {
                    name:'anne'
                }
            };
            var obj = new myClass();
            alert(obj.name);

      call和apply:

      ES3中,给Function的原型定义了两个方法,他们是Function.prototype.callheFunction.prototype.apply。

      相同点:功能一样,都可以用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象。

      区别:传入参数形式不同

        apply接受两个参数,第一个参数指定了函数体内this对象的指向,第二个参数为一个数组,B.apply(A, arguments);即A对象应用B对象的方法。

        call可以接受多个参数,第一个参数与apply一样,后面则是一串参数列表,B.call(A, args1,args2);即A对象调用B对象的方法。

      等价写法:foo.call(this,arg1,arg2,arg3) == foo.apply(this, arguments)==this.foo(arg1, arg2, arg3)

      call和apply的用途:

      1、改变this指向,call和apply最常见的用法就是改变函数内部this的指向,如:

            var obj1 = {
                name:'sven'
            };
            var obj2 = {
                name:'anne'
            };
            window.name = 'window';
            var getName = function(){
                console.log(this.name);
            };
            getName();//window
            getName.call(obj1);//sven
            getName.call(obj2);//anne

      在前面this的小栗子里,有一个将当前this对象保持下来以方便在回调函数中使用当前的this对象,避免this重新指向的问题,从而可以操作div节点,这的问题,我们使用call或者apply也可以解决,具体代码如下:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1">我是div1</div>
        <script>
            document.getElementById("div1").onclick = function () {
                alert(this.id);//div1
                var getId = function(){
                    alert(this.id);
                };
                getId.call(this);//div1
            };
        </script>
    </body>
    </html>

      我们也可以使用call和apply来修正this的场景,这样说不是很清楚,我们通过这个例子来理解一下:对于js获取元素ID的方法,大家都知道,是document.getElementById,这个方法名很长,所以我们想用一个短的函数来代替它:

            var getId = function(id){
                return document.getElementById(id);
            };
            getId("div1");

      将上面的方法再简化:

            var getId = document.getElementById;
            getId("div1");

      但是这个简化过的方法,我们在浏览器里测一下,会报错,用不了,为什么呢?这是因为浏览器引擎的document.getElementById()这个方法,在内部实现的时候,有用到this,当我们直接使用的时候,this是指向调用他的div对象的,但是当我们把这个方法赋给getId这个变量的时候,this指向的其实就是window对象了,而不是我们期望的div节点,现在我们用call或者apply来修正一下this的指向:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <div id="div1">我是div1</div>
        <script>
            document.getElementById = (function(func){
                return function(){
                    return func.apply(document, arguments);
                }
            })(document.getElementById);
            var getId = document.getElementById;
            var div = getId('div1');
            console.log(div);
        </script>
    </body>
    </html>

      这样我们就修正了在document.getElementById中丢了的this。

      2.Function.prototype.bind:

      大部分浏览器都实现了内置的Function.prototype.bind,用来指定函数内部的this指向,即使没有原生的Function.prototype.bind,我们也可以模拟一个,代码如下:

            Function.prototype.bind = function(context){
                var self = this;    //保存原函数
                return function(){        //返回一个新的函数
                    return self.apply(context,arguments);    //执行新函数的时候,会把之前传入的context当作新函数体内的this
                }
            };
            var obj = {
                name: 'sven'
            };
            var func = function(){
                alert(this.name);  //sven
            }.bind(obj);
            func();

      这是一个简化版的bind方法,我们还可以把它变得更复杂一点,以方便我们向func里传入一些参数:

    Function.prototype.bind = function(context) {
        console.log(context);
        console.log(arguments);
        var self = this, //保存原函数
            //context = [].shift.call(arguments), //需要绑定的this上下文
            args = [].slice.call(arguments); //剩余的参数转成数组
        console.log(context);
        console.log(args);
        return function() { //返回一个新的函数
            return self.apply(context, [].concat.call(args, [].slice.call(arguments))); //执行新函数的时候,会把之前传入的context当作新函数体内的this 并且组合两次分别传入的参数 作为新函数的参数
        }
    };
    var obj = {
        name: 'sven'
    };
    var func = function(a, b, c, d) {
        console.log(this.name); //sven
        console.log([a, b, c, d]);
    }.bind(obj, 1, 2);
    func(3);

      3.借用其他对象的方法

      借用方法的第一种使用场景是“借用构造函数”,通过这种方法,可以实现类似继承的效果:

    var A = function(name){
        this.name = name;
    };
    
    var B = function(){
        A.apply(this, arguments);
    };
    
    B.prototype.getName = function(){
        return this.name;
    };
    
    var b = new B('sven');
    console.log(b.getName());

      借用方法的第二个场景,主要是借用数组对象的方法,借用数组的方法,在使用的过程中,需要注意这两点:

        a.操作的对象本身要可以存取属性;

        b.操作对象的length属性可读写;

      例子如下:

    var a = {};
    Array.prototype.push.call(a, 'first');
    
    console.log(a);
    console.log(a.length);
    console.log(a[0]);

      如果上面例子中,a不是对象类型,而是基础数据类型,如Number等,这种借用方法是不可行的。

  • 相关阅读:
    Web APIs
    变量替换
    用shell脚本实现文件、代码同步上线
    20.31 expect脚本同步文件 20.32 expect脚本指定host和要同步的文件 20.33 构建文件分发系统 20.34 批量远程执行命令
    20.27 分发系统介绍 20.28 expect脚本远程登录 20.29 expect脚本远程执行命令 20.30 expect脚本传递参数
    20.23/20.24/20.25 告警系统邮件引擎 20.26 运行告警系统
    20.16/20.17 shell中的函数 20.18 shell中的数组 20.19 告警系统需求分析
    20.5 shell脚本中的逻辑判断 20.6 文件目录属性判断 20.7 if特殊用法 20.8/20.9 case判断
    16进制数据拆分
    16进制数据拼接成一个
  • 原文地址:https://www.cnblogs.com/jiangtengteng/p/9667769.html
Copyright © 2011-2022 走看看