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


    <!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>
  • 相关阅读:
    poj 2378 删点最大分支不超过一半
    poj 3107 删点最大分支最小
    hdu 3586 最小代价切断根与叶子联系
    hdu 4276 树形m时间1进n出
    hdu 4044 树形DP 炮台打怪 (好题)
    poj 3345 树形DP 附属关系+输入输出(好题)
    poj 2486 树形DP n选m连续路径
    hdu 1561 树形DP n个选m个价值最大
    poj 1947 树形背包
    hdu 1011 树形背包
  • 原文地址:https://www.cnblogs.com/52tech/p/9325103.html
Copyright © 2020-2023  润新知