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>
相关文章
|
15天前
|
XML 前端开发 JavaScript
JavaScript进阶 - AJAX请求与Fetch API
【7月更文挑战第3天】前端开发中的异步基石:AJAX与Fetch。AJAX,使用XMLHttpRequest,处理跨域、回调地狱和错误处理。Fetch,基于Promise,简化请求,但需注意默认无跨域头和HTTP错误处理。两者各有优劣,理解其问题与解决策略,能提升前端应用的性能和用户体验。
|
7天前
|
前端开发 JavaScript 安全
JavaScript进阶-JavaScript库与框架简介
【7月更文挑战第11天】JavaScript库和框架加速Web开发,但也带来挑战。选择适合项目、团队技能的库或框架,如React、Angular、Vue,是关键。保持依赖更新,注意性能优化,避免过度依赖。遵循最佳实践,确保安全性,如防XSS和CSRF。学习基础,结合代码示例(如React计数器组件),提升开发效率和应用质量。
|
12天前
|
资源调度 JavaScript 前端开发
JavaScript进阶 - JavaScript库与框架简介
【7月更文挑战第5天】JavaScript库和框架构成了前端开发的核心,如jQuery简化DOM操作,Angular、React和Vue提供全面解决方案。选择时要明确需求,避免过度工程化和陡峭学习曲线。使用版本管理工具确保兼容性,持续学习以适应技术变化。示例展示了jQuery和React的简单应用。正确选择和使用这些工具,能提升开发效率并创造优秀Web应用。
|
13天前
|
缓存 JavaScript 前端开发
JavaScript进阶 - Web Workers与Service Worker
【7月更文挑战第4天】JavaScript的Web Workers和Service Worker增强了Web性能。Web Workers处理后台多线程,减轻主线程负担,但通信有开销,受同源策略限制。Service Worker则用于离线缓存和推送通知,需管理其生命周期、更新策略,并确保安全。两者都带来了挑战,但也极大提升了用户体验。通过理解和优化,开发者能构建更高效、安全的Web应用。
|
16天前
|
JavaScript
js【详解】call()、apply()、bind()方法
js【详解】call()、apply()、bind()方法
24 6
|
15天前
|
存储 前端开发 安全
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第2天】探索Web存储:localStorage持久化,sessionStorage会话限定,cookies则伴随HTTP请求。了解它们的特性和限制,如localStorage的5MB容量限制、跨域问题,sessionStorage的生命周期,及cookies的安全与带宽消耗。使用时需权衡安全、效率与应用场景。示例代码展示存储与检索方法。
|
16天前
|
设计模式 前端开发 JavaScript
JavaScript进阶 - JavaScript设计模式
【7月更文挑战第1天】JavaScript设计模式增进代码复用和维护性。单例模式确保唯一实例,用闭包防止命名冲突和控制状态访问。观察者模式实现一对多依赖,通过解绑避免内存泄漏。工厂模式封装对象创建,适度使用避免复杂度。装饰者模式动态添加行为,保持简洁以保可读性。理解模式的优缺点,灵活应用,提升代码质量。
|
22天前
|
存储 JSON 前端开发
JavaScript 进阶征途:解锁Function奥秘,深掘Object方法精髓
JavaScript 进阶征途:解锁Function奥秘,深掘Object方法精髓
|
8天前
|
缓存 前端开发 JavaScript
JavaScript进阶 - Web Workers与Service Worker
【7月更文挑战第10天】在Web开发中,Web Workers和Service Worker提升性能。Workers运行后台任务,防止界面冻结。Web Workers处理计算密集型任务,Service Worker则缓存资源实现离线支持。常见问题包括通信故障、资源限制、注册错误及缓存更新。通过示例代码展示了两者用法,并强调生命周期管理和错误处理的重要性。善用这些技术,可构建高性能的Web应用。
|
9天前
|
XML 前端开发 JavaScript
JavaScript进阶 - AJAX请求与Fetch API
【7月更文挑战第9天】JavaScript进阶:AJAX与Fetch API对比。AJAX用于异步数据交换,XMLHttpRequest API复杂,依赖回调。Fetch API是现代、基于Promise的解决方案,简化请求处理。示例:`fetch(&#39;url&#39;).then(r =&gt; r.json()).then(data =&gt; console.log(data)).catch(err =&gt; console.error(err))`。注意点包括检查HTTP状态、错误处理、CORS、Cookie和超时。Fetch提高了异步代码的可读性,但需留意潜在问题。