JS高级—继承和函数进阶

继承和函数进阶

继承
对象之间的继承
  • 通过for…in实现对象间的拷贝

    //继承的函数
            function extend(parent, child) {
                for (var k in parent) {
                    if (child[k]) {
                        continue;
                    }
                    child[k] = parent[k];
                }
            }
    
原型继承
  • 可以将公共有的样式单独列出来,通过实例对象可以继承原型对象属性,给原型对象进行添加

     // 原型对象,可以将自己的属性和方法继承给将来的实例对象
            Student.prototype = new Person("zs", 18, "男");
            // 生成实例
            var s1 = new Student(89);
            var s2 = new Student(100);
            console.log(s1);
            console.log(s1.constructor); //Person函数
            Student.prototype.constructor = Student;
            console.log(s1.constructor); //Student函数
    
    • 传参只能传一次
    • 其中的construtor属性需要手动修改
函数的call方法
  • 更改函数内部的this指向

  • 调用函数执行内部代码,第一个给的是this的指向,从第二个开始传入的是实参

    function fn(a, b) {
                console.log(this); //{name: "zs"}
                console.log(a + b); //6
            }
            var o = {  name: "zs" }
            fn.call(o, 2, 4)
    
借用构造函数继承属性
  • 与call方法结合,通过更改this指向问题可以解决原型继承中只能传入一个参数的问题

     function Student(name, age, sex, score) {
                // 直接对父类型的构造函数进行一个普通调用
                // Person 普通调用过程中,内部的 this 指向的是 window
                // 可以通过 call 方法更改Person 内部的 this
                Person.call(this, name, age, sex);
                this.score = score;
            }
    
构造函数方法的继承
  • 方法写入到原型对象之上就可以节省空间

  • 方法的拷贝(for…in)继承

     // 通过拷贝方法子原型继承父原型方法
            for (var k in Person.prototype) {
                // 需要保留自己的construtor属性
                if (k === "construtor") {
                    continue;
                }
            Student.prototype[k] = Person.prototype[k];
            }
    
  • 原型继承

    // 将子原型直接指向父的实例,就可以继承父原型中的方法
            Student.prototype = new Person();
    // 保留construtor,返回结果construtor: ƒ Student(name, age, sex, score)
            Student.prototype.construtor = Student;
    //返回的原型是__proto__: Person
    
组合继承
  • 属性在构造函数内部继承,方法通过原型继承

    function Teacher(name, age, sex, salary) {
    // 属性的继承通过构造函数
                Person.call(this, name, age, sex);
                this.salary = salary;
            }
    // 方法的继承通过原型
            Teacher.prototype = new Person();
            Teacher.prototype.construtor = Teacher;
            var t1 = new Teacher("li_sir", 45, "男", 10000);
    

在这里插入图片描述

函数进阶
函数声明和函数表达式
  • 函数声明

    • 必须定义函数名
    • f1()调用写在前后都行,因为有函数声明提升
    function f1() {
                console.log(1);
            }
    
  • 函数表达式

    • 将函数赋值给一个变量,也可以是一个匿名函数
    • 如果在前面调用,返回的只是一个undefined的变量
    var f2 = function() {
                console.log(2);
            }
    
  • if语句中添加函数,容易产生高低版本不兼容,结果一致的现象,我们可以直接使用变量定义函数

  • 对象方法

    var fn = new Function('a', 'b', 'var a="1";console.log(a+b)');
    fn(2, 3); //13字符串
    
函数调用和this
  • 普通函数的调用通过函数名或者变量名()方法执行

    // 1、普通函数
            function fun() {
                console.log(1);
            }
            fun();
    
  • 构造函数通过new关键字调用

    // 2、构造函数
            function Person(name) {
                this.name = name;
            }
            var p1 = new Person("zs");
    
  • 对象中的方法通过打点调用,然后加小括号

    // 3、对象中的方法,打点调用
            var o = {
                sayhi: function() {
                    console.log("hello");
                }
            }
            o.sayhi();
    
  • 事件函数,触发事件则执行

     // 4、事件函数,被触发则执行
            document.onclick = function() {
                console.log("事件");
            };
    
  • 定时器或延时器函数,在规定时间后执行

    // 5、定时器或延时器中函数,一段时间后执行函数
            setInterval(function() {
                console.log("timer");
            }, 100)
    
  • this指向问题,在不同的执行环境默认指向会改变

在这里插入图片描述

call、apply、bind方法

解决函数内部调用时this指向的问题

  • call方法

    • 可以指定函数的 this

    • 可以执行函数传参,第一个参数传入一个指定的this更改对象,第二个参数即以后都是函数参数列表

        function fun(a, b) {
                  console.log(this);
                  console.log(a + b);
              }
              var o = {
                  name: "zs"
              }
              fun.call(o, 1, 2); 
              //{name: "zs"},this指向了o
      
    • 作用,{}的对象自己是没有Array的方法,我们可以将数组Array的原型对象的this指向更改为我们自己定义的函数,就可以处理类数组对象的数据

      Array.prototype.push.call(o, 60);
      console.log(o); 
      //{0: 10, 1: 20, 2: 30,  4: 60, length: 4}
      
  • apply方法

    • 可以修改this的指向

    • 也可以进行函数的传参,所有的参数写在一个数组中

      fun.apply(o, [3, 4]);
      
    • 可以指定一个函数的this,并且通过数组的方法进行传参

      var arr = [1, 3, 7, 4, 8];
      console.log(Math.max.apply(null, arr)); //8
      console.log.apply(console, arr); //可以将数组打散进行输出1 3 7 4 8
      
  • bind方法

    • 可以修改this的指向

    • 可以传参,但是不执行函数,返回一个新的制定了this的函数,也可以叫绑定函数

      var fn = fun.bind(o, 2, 3);
      fn();
      
    • 只想修改this的指向,不想执行函数

       // 更改定时器内部函数的this
              var o = {
                  age: 18,
                  s: function() {
                      setInterval(function() {
                          console.log(this.age);
                      }.bind(this), 1000);
                  }
              }
              o.s(); //undefined
              o.s(); //添加this后指向的是18
      // 更改事件的触发对象
              document.onclick = function() {
                  console.log(this); //#document
              }.bind(o); //{age: 18, s: ƒ}
      
函数的其他成员
  • arguments:存储的是函数在调用时,传入的所有实参组成的一个类数组对象,实际应用直接使用arguments关键字

    • 可以灵活使用arguments类数组对象,可以记录所有的实参
    • arguments.callee函数本身,arguments的一个属性
  • caller:函数的调用者,函数在那个作用域中调用,caller就是谁,如果在全局调用,值就是null

  • length:形参的个数

  • name:函数的名字

    function fn(a, b) {
                console.log(fn.arguments);
                //Arguments(4) [1, 2, 3, 4, callee: ƒ, Symbol(Symbol.iterator): ƒ]
                console.log(fn.caller); //null
                console.log(fn.length); //2
                console.log(fn.name); //fn,形参个数
            }
    fn(1, 2, 3, 4);
    
高阶函数
  • 函数可以作为另一个函数的参数

    function eat(fn) {
                console.log("吃晚饭");
                fn();
            }
            eat(function() {
                console.log("看电影");
            })
    
  • 函数可以作为返回值

     // 实现两个加数m、n均可以随意传入参数
            function outer(n) {
                return function inner(m) {
                    console.log(m + n);
                }
            }
            var fun = outer(100);
            fun(3); //103
            fun(23); //123
            var fun = outer(1000);
            fun(3); //1003
    
闭包
概念
  • 一个函数和其周围的引用捆绑在一起

  • 记住自己生成的作用域环境和函数自己,将它们形成一个密闭的环境,无论函数以任何方式在任何地方进行调用,都会回到自己定义时的密闭环境进行执行

            function outer() {
                var a = 10;
    
                function inner() {
                    console.log(a);
                }
                return inner; //将inner作为函数返回值
            }
            var inn = outer(); //全局下定义的inn,按道理返回的是全局的a变量
            inn(); //10,返回的是自己闭包环境中的a变量的值
    
理解和应用
  • 闭包是天生存在的,可以记住内部作用环境的变量,函数就是一个闭包、里面的变量并不是一成不变的

  • 闭包内部的变量可以被inner在任何地方被调用

  • 可以在函数外部读取函数内部成员,让函数内成员始终活在内存中

  • 在外部想了一个方法,把构造函数传到外面,指针只想就可以调用内部的函数

问题
  • 闭包内部函数无法记住自己当前的值并返回

  • 我们可以使用自调用函数来封闭作用域,变量作为局部变量使用

     var arr = [];
            for (var i = 0; i <= 10; i++) {
                // 使用自调用函数
                (function(i) {
                    arr[i] = function() {
                        console.log(i);
                    }
                })(i);
            }
            arr[0](); //11  0
            arr[1](); //11  1
    
  • 闭包内部函数无法记住自己当前的值并返回

  • 我们可以使用自调用函数来封闭作用域,变量作为局部变量使用

     var arr = [];
            for (var i = 0; i <= 10; i++) {
                // 使用自调用函数
                (function(i) {
                    arr[i] = function() {
                        console.log(i);
                    }
                })(i);
            }
            arr[0](); //11  0
            arr[1](); //11  1
    

    下一篇更精彩噢~正则表达式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值