• 前端基础进阶(五):全方位解读this


    https://segmentfault.com/a/1190000012646488  https://yangbo5207.github.io/wutongluo/

    说明:此处只是记录阅读前端基础进阶的理解和总结,如有需要请阅读上面的链接

    一、this的指向在执行上下文的创建阶段确定,即是在函数的调用阶段确定的,因此不同的调用方式this的指向可能不同

        var a = 10;
        var obj = {
            a: 20,
            GetA:function(){
                console.log(this.a);
            }
        }
    
        obj.GetA(); //20
        var f = obj.GetA;
        f();//10
    f()独立调用,this指向全局环境;obj.GetA()不是独立调用,this指向函数所属的对象。

    关于this指向的结论:在一个函数的全局上下文中,this用调用者提供,由函数的调用方式决定。如果函数被调用时被某一个对象所拥有(即写法如obj,GetA()),那么函数内部的this指向改对象;
    如果函数是独立调用,那么内部的this指向undifined。在非严格模式下当this指向undefined时,它会被自动指向全局对象。

    注意事项:全局环境中的this指向全局环境本身,this指向在函数执行过程中不能改变,所以给this赋值会报错,如this=obj;

    说明:this指代的是对象,函数中的this并不是表示函数作用域。如下例子刚开始以为输出a=10,a表示函数fn的作用范围,其实不是a表示的是全局对象。
        var a = 20;
        function fn() {
            var a=10;
            function foo() {
                console.log(this.a);
            }
            foo();//独立调用,所以输出结果还是20
        }
        fn();

    严格模式下的foo()是独立调用,this指向undifined,故this.a报错,而window.foo()不是独立调用,this指向window,所以this.a=20,故结果40

     'use strict';
        var a = 20;
        function foo() {
            var a = 1;
            var obj = {
                a: 10,
                c: this.a + 20,
                fn: function () {
                    return this.a;
                }
            }
            return obj.c;
    
        }
        console.log(window.foo());  // 40
        console.log(foo());    // TypeError: this is undefined
    三、使用call,apply显示指定this

    JavaScript可使用call和apply方法手动设置函数中this的指向,每个函数都支持call和apply方法

        var a = 10;
        var obj={
            a:10
        };
    
        function fn() {
            console.log(this.a);
        }
    
        fn.call(obj);//10

    call和apply的用法

    第一个参数为this的指向,剩下的参数是函数本身的参数,区别是call方法中函数参数是一个一个传入,apply方法以数组方式传入

       var a = 10;
        var obj={
            a:10
        };
    
        function fn(num1,num2) {
            console.log(num1+num2+this.a);
        }
    
        fn.call(obj, 1, 2); //13
        fn.apply(obj, [1, 2]); //13

    四 call/apply的用途

    1.将类数组转换为数组

     function add(num1, num2, mum3) {
            console.log(arguments); //打印出类数组原来的样子Arguments { 0: 1, 1: 2, 2: 3, … }
            var arg = [].slice.call(arguments); //把类数组转换成数组 Array [ 1, 2, 3 ]
            console.log(arg);
        }
        add(1, 2, 3);

    2.根据自己需要灵活指定this

    var foo = {
            name: 'joker',
            showName: function () {
                console.log(this.name);
            }
        }
        var bar = {
            name: 'rose'
        }
        foo.showName.call(bar);//rose

    3.实现继承

        //定义父级构造函数
        var Person = function (name, age) {
            this.name = name;
            this.age = age;
        }
    
        //定义子类构造函数
        var Student = function (name, age, high) {
            Person.call(this, name, age);
            this.high = high;
        }
    
        Student.prototype.message = function () {
            console.log('name:' + this.name + 'age:' + this.age + 'high:' + this.high);
        }
    
        var stu = new Student('xiaoming', 10, '150cm');
        stu.message(); //name:xiaomingage:10high:150cm

    要理解上面的例子,首先要搞清楚构造函数中this的指向。this指向是在函数调用时确定的,所以要弄明白构造函数中的this指向就要搞清楚new之后经历了什么。

    调用new运算符之后会经历一下阶段:

    1)创建一个新的对象

    2)将构造函数中的this指向这个新的对象

    3)执行构造函数的代码为这个新对象添加属性,方法等

    4)返回新对象

    上面的例子在Student的构造函数中利用call方法把新创建的对象传递给Person,从而给新对象添加name,age属性,也就相当于实现了继承。

    4.保存this指向正确的对象

        var a = 20;
        var obj = {
            a:10,
            getA:function(){
                setTimeout(function(){
                    console.log(this.a);
                },1000);
            }
        }
        obj.getA();//20

    上例本意是想打印出对象obj中a的值,但是由于setTimeout函数的存在,导致实际执行的时候this指向了全局对象,所以打印结果是20。

    注意:setTimeout的作用是向JavaScript注册函数,并在指定时间之后执行注册的函数,因此等到函数运行时这个函数就相当于是独立调用,this在费严格模式下自动指向全局对象。

    最简单的改法是利用闭包把this指向的对象保存下来

     var a = 20;
        var obj = {
            a: 10,
            getA: function () {
                var self = this;
                setTimeout(function () {
                    console.log(self.a);
                }, 1000);
            }
        }
        obj.getA();//10

    另一个方式是使用call或者apply封装一个bind方法,确保函数指向obj

     var a = 20;
        var obj = {
            a: 10,
            getA: function () {
    
                setTimeout(bind(function () {
                    console.log(this.a);
                },this), 1000);
            }
        }
    
        function bind(fn, obj) {
            return function () {
                fn.call(obj); //或者fn.apply(obj);
            }
        }
    
        obj.getA();//10

    还可以用JavaScript自带的bind方法,作用是把函数fn.bind(obj)的this指向绑定到obj

        var a = 20;
        var obj = {
            a: 10,
            getA: function () {
    
                setTimeout(function () {
                    console.log(this.a);
                }.bind(this), 1000);
            }
        }
    
        obj.getA();//10
     
  • 相关阅读:
    动态SQL的注意
    关于数据库抛出异常:Incorrect string value: 'xE1x...' for column '字段名' at row 1 问题的解决方法
    让.bashrc文件在终端自动生效
    期中考试题
    RAP、Mock.js、Vue.js、Webpack
    全局变量变为局部变量 & MVC思想
    用 JS + LeanCloud 给网页添加数据库(留言功能)
    闭包的使用
    从发请求到AJAX到同源政策
    从实现HTML页面局部刷新到JSONP
  • 原文地址:https://www.cnblogs.com/lidaying5/p/8484777.html
Copyright © 2020-2023  润新知