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

版权声明:本文为博主原创文章,未经博主允许不得转载。更多学习资料请访问我爱科技论坛: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>
上一篇:为什么kill进程后socket一直处于FIN_WAIT_1状态


下一篇:Office Web Apps安装部署