JavaScript进阶【四】JavaScript中的this,apply,call的深入剖析-阿里云开发者社区

开发者社区> 向善的灯> 正文

JavaScript进阶【四】JavaScript中的this,apply,call的深入剖析

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79646265 ...
+关注继续查看
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79646265
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--this的使用-->
<!--(1)this的指向
作为对象的方法调用
作为普通函数调用
构造器调用
Function.prototype.callFunction.prototype.apply调用
-->
<!--1this作为对象的方法调用
当函数作为对象的方法被调用时,this指向该对象:
-->
<script>
    var obj = {
        a: 1,
        getA: function () {
            alert(this == obj); // true
            alert(this.a);  //1
        }
    }
    obj.getA();

    // 2. 作为普通函数调用使用
    window.name = "gloabalName";
    var getName = function () {
        // 这哭的this指向的是window对象
        return this.name;
    }

    var myObject = {
        name: "xiuxiu",
        getNameA: function () {
            // 这里的this指向的是myObject 对象
            alert(this);  // window
            return this.name;
        }
    }

    console.log(getName());

    var a = myObject.getNameA;    //globalName
    //console.log(a); // xiuxiu
    console.log(a());


    var innerText = "我是全局变量的innerText";
    // callback方法的使用
    var button = document.createElement("button");
    button.innerText = "打开";
    button.id = "btn";
    document.body.appendChild(button);
    button.onclick = function (ev) {

        // 定义一个that , 让这个that指向button对象
        var that = this;

        // alert(this);  button
        // 这里的this指向的是触发这个事件的那个对象
        console.log(this.innerText);

        var callback = function () {
            // 这里的this指向的是window对象
            // 注意:在ES5strict模式下,this已经被规定不会指向全局对象,而是undefined
            console.log(this.innerText);  //undifined

            // 这里的that 指向的是这个按钮对象, 不是window对象
            console.log(that.innerText);
        }
        callback();
    }


    //3. 构造器调用
    // 构造器里的this就指向返回的这个对象
    var myClass = function (name, sex) {
        this.name = name;
        this.sex = sex;

        alert(this.name + " " + this.sex);
    };
    var male = new myClass("xiaohong", "male");

    var myClass = function (name) {
        //console.log(this.name); //undifined
        this.name = name;

        console.log(this.name + " " + name);

        // 只有返回出去之后,这个name属性就会被外界修改
        return {
            name: "hahaha"
        }
    }
    var cls = new myClass("xiuxiu");
    alert(cls.name);


    // 4Function.prototype.callFunction.prototype.apply调用
    // 跟普通的函数调用相比,用Function.prototype.callFunction.prototype.apply可以动态的改变传入函数的this
    var obj1 = {
        name: "xiuxiu",
        getName: function () {
            return this.name;
        }
    }
    var obj2 = {
        name: "Jack"
    }
    console.log(obj1.name); // xiuxiu
    console.log(obj1.getName.call(obj2));   // jack

    var obj3 = {
        myname: "seven",
        getName: function () {
            return this.myname;
        }
    }
    // 此时在调用this指向 obj3对象
    console.log(obj3.getName()); // seven


    // 修改this的指向
    // 这里是通过getname2这个普通函数区调用的, 此时this 指向的是window对象
    // 但是全局中没有getname2这个方法
    var getname2 = obj3.getName;
    alert(getname2());  //undifined


    // document.getElementById的使用错误
    var getId = function (id) {
        //alert(this);  // 这里的this指向的widnow
        return document.getElementById(id);
    }
    var id = getId("btn");
    console.log("id:" + id);  // ButtonElement


    // 这里把这个函数的this修改为指向document对象
    //var getId = document.getElementById;
    //id = getId("btn");
    //console.log("id:"+id);  // this的使用理解.html?_ijt=7mjupf008evikdgvnqbeddk23d:146 Uncaught TypeError: Illegal invocation


    // 手动修改this 的指向
    document.getElementById = (function (func) {
        return function () {
            // 这里强制让func对象指向documen对象
            return func.apply(document, arguments);
        }
    })(document.getElementById);

    var getId = document.getElementById;
    var button = getId("btn");
    console.log(button); // <button id="btn">打开</button>
    console.log(button.id);


    // 二、callapply的使用
    var func = function (a, b, c) {

        "use strict";
        // 显示一下这个函数体内的this指向是个啥
        alert(this);
        console.log([a, b, c]);
    }
    // ƒ (a, b, c) {
    /*console.log([a, b, c]);
    }*/
    console.log(func);
    // func()表示直接去调用这个函数
    console.log(func());  // undifined


    // 通过apply方法可以去修改这个函数体内的 this 的指向,可以任意修改, window, document
    // 第一个参数也是代表函数体内的this指向,从第二个参数开始往后,每个参数被依次传入函数
    func.apply(null, [1, 2, 3]); // this指向window
    // 在严格模式"use strict"下上面的this指向为null, 不使用严格模式会指向window
    func.apply(null, [1]); // this指向window

    //如果我们传入的第一个参数为null,函数体内的this会指向默认的宿主对象。在浏览器中则是window
    func.apply(null, [0, 1]); // this指向window
    //console.log(func());
    func.apply(document, [0, 1, 2]);  // this指向document
    func.apply(this, [0, 1]);  // this指向window


    // 利用函数求出最大值
    console.log(Math.max.apply(null, [1, 2, 3]));
    console.log(Math.max(1, 2, 3));


    // 三、callapply在实际开发中的用途
    // 1.)修改 this的指向
    var obj1 = {
        //alert(this);
        name: "seven"
    }
    var obj2 = {
        //alert(this);
        name: "haha"

    }

    window.name = "window";
    var getName = function () {
        console.log(this.name);
    }
    // 全局调用函数
    getName();  // this指向的是window
    getName.call(obj1); // this指向的是obj1对象
    getName.call(obj2); // this指向的是obj2对象

    // 添加一个事件
    document.addEventListener("click", function (ev) {
        // 这里的this 指向的是触发这个事件的那个对象
        console.log(this);  // document

        function Add(a, b) {
            console.log(this);
        }

        // 这个相当于是全局调用,thisz指向的是window对象
        Add(10, 1); // window
        // 修正这个this 的指向
        // 这里的this指向的还是触发这个事件的那个对象
        Add.call(this); // document
    });


    // 2).Function.prototype.bind
    // Function.prototype.bind,用来指定函数内部的this指向
    Function.prototypebind = function (context) {
        var self = this;

        return function () {
        console.log(context+"is"+ this);

            // 修改thisself)的指向为context对象
            return self.apply(context, arguments);
        }
    }


    var obj = {
        name: "xiuxiuDesign"
    }
    var getName = function () {
        // 修改this的指向为obj对象
        console.log(this.name);
    }.bind(obj);
    getName();


    // 3).借用其它对象的方法
    var A = function (name) {
        this.name = name;
    }
    var B = function () {
        // 修改A这个的this对象指向B
        A.apply(this, arguments);

        // Arguments ["xiuxiu is a good man", callee: ƒ, Symbol(Symbol.iterator): ƒ]
        console.log(arguments);
    }

    B.prototype.getName = function () {
        //
        return this.name;
    }
    var b = new B("xiuxiu is a good man");
    console.log(b.getName());


    // 想往argumments中添加一个新的元素,通常会借用Array.prototype.push
    (function () {
        Array.prototype.push.call(arguments, 3);
        console.log(arguments);
    })(1, 2, 1, 3)

    // 想把arguments转成真正的数组的时候,可以借用Array.prototype.slice方法,想截取arguments列表中的头一个元素时,可以使用Array.prototype.shift方法,这种机制的内部原理,我们可以翻开V8引擎源码,以Array.prototype.push方法为例
    var a = {};
    // 修改Array这个数组的指向, 让这个数组的pushthis指向a的引用, 也就是a这个对象
    Array.prototype.push.call(a, 'first');
    Array.prototype.push.call(a, 'second');

    // 通过调用Arraypush 方法, 同时修改了this 的指向为a这个对象的引用
    console.log(a.length);
    console.log(a[0]);



    // JavaScript的一种继承方式
    var AA = function (name, age) {
        this.name = name;
        this.age = age;
    }
    AA.prototype = {
        getName : function () {
            alert(this.name);
        }
    }

    var BB = function () {
    }
    // BB对象继承于AA对象
    BB.prototype = new AA("AAA", 19);



    var aa = new AA("xiuxiu", 18);
    console.log(aa.name +" "+aa.age); // xiuxiu, 18
    var bb = new BB();
    console.log(bb.name+" "+bb.age); // AAA 19

</script>


</body>
</html>

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
阿里云服务器怎么设置密码?怎么停机?怎么重启服务器?
如果在创建实例时没有设置密码,或者密码丢失,您可以在控制台上重新设置实例的登录密码。本文仅描述如何在 ECS 管理控制台上修改实例登录密码。
4138 0
阿里云服务器端口号设置
阿里云服务器初级使用者可能面临的问题之一. 使用tomcat或者其他服务器软件设置端口号后,比如 一些不是默认的, mysql的 3306, mssql的1433,有时候打不开网页, 原因是没有在ecs安全组去设置这个端口号. 解决: 点击ecs下网络和安全下的安全组 在弹出的安全组中,如果没有就新建安全组,然后点击配置规则 最后如上图点击添加...或快速创建.   have fun!  将编程看作是一门艺术,而不单单是个技术。
4595 0
SAS进阶《深入分析SAS》之数据汇总和展现
SAS进阶《深入分析SAS》之数据汇总和展现 1. 通过Print过程制作报表 proc print &lt;data=数据集&gt;; run; 选项: obs=修改观测序号列标签 noobs不显示观测序列号 id语句在输出中取代观测序列 var选择输出的变量 where语句选择输出的观测 总结如下: proc print data=数据集&lt;选项&g
1166 0
JavaScript进阶【五】利用JavaScript实现动画的基本思路
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79659313 ...
758 0
【青训营】- TypeScript进阶笔记
【青训营】- TypeScript进阶笔记
6 0
JavaScript进阶【二】JavaScript 严格模式(use strict)的使用
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79249309 ...
781 0
JavaScript进阶【四】JavaScript中的this,apply,call的深入剖析
版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛:www.52tech.tech https://blog.csdn.net/m0_37981569/article/details/79646265 ...
847 0
【我的Android进阶之旅】解决Center OS 64位系统编译Android APP报错error=2和finished with non-zero exit value 127
一、错误描述 1、问题 java.io.IOException: error=2, 没有那个文件或目录 今天在刚重新搭建好的64位的Center OS上安装好了Android SDK,Jenkins,Git等一系列用于持续集成的环境之后,准备编译下项目试一试,然后Jenkins编译失败,错误如下所示: Caused by: java.
1648 0
Java进阶之并发编程——《我的Java打怪日记》
Java进阶之并发编程——《我的Java打怪日记》
37010 0
+关注
37
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载