继承和函数进阶

一. 继承的几种方式

1.继承

// 封装一个对象之间继承的函数
    function extend(parent, child) {
      for (var k in parent) {
        // 子级有的属性不需要继承
        if (child[k]) {
          continue;
        }
        child[k] = parent[k];
      }
    }

对象拷贝:for……in :父对象的属性拷贝给子对象。

2.原型继承

   // 封装的构造函数就是用来创建一类对象
   // 继承指的是 类型 和 类型之间的继承
   // 人类类型
    function Person(name,age,sex) {
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    // 学生类型
    function Student(score) {      
      this.score = score;
    }
    // 老师类型
    function Teacher(salary) {
      this.salary = salary;
    }
    // 原型对象,可以将自己的属性和方法继承给将来的实例对象使用
    Student.prototype = new Person("zs",18,"男");
    Student.prototype.constructor = Student;
    // 生成一个实例
    var s1 = new Student(89);
    var s2 = new Student(100);
    console.log(s1.name);
    console.log(s1.constructor);

3.构造函数的继承

  • 认识call方法
// call
    // 函数本身就是一种对象,就能够有自己的属性和方法
    // call 方法本身是一种执行函数的方法
    function fn(a,b) {
      console.log(this);
      console.log(a + b);
    }
    var o = {
      name: "zs"
    }
    // 普通函数调用
    // fn(2,3);
    // call 方法在调用函数的时候,有两个功能
    // 1.更改函数内部的 this 指向
    // 2.调用函数执行内部代码
    // 参数: 第一个参数用来指定 this,第二个及以后,就是传的实参
    fn.call(o,3,4);
  • 构造函数属性的继承(举例)
// 人类类型
    function Person(name,age,sex) {
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    // 学生类型
    function Student(name,age,sex,score) {
      // 直接对父类型的构造函数进行一个普通调用
      // Person 普通调用过程中,内部的 this 指向的是 window
      // 可以通过 call 方法更改Person 内部的 this
      Person.call(this,name,age,sex); 
      this.score = score;
    }
    // 老师类型
    function Teacher(name,age,sex,salary) {
      Person.call(this,name,age,sex); 
      this.salary = salary;
    }
    // 创建学生的实例对象
    var s1 = new Student("zs",18,"男",89);
    var s2 = new Student("ls",19,"男",92);
  • 构造函数的原型方法继承(举例)
// 人类类型
    function Person(name,age,sex) {
      this.name = name;
      this.age = age;
      this.sex = sex;
    }
    // 父类型的原型对象中有方法也需要继承
    Person.prototype.sayHi = function () {
      console.log("你好");
    };
    // 学生类型
    function Student(name,age,sex,score) {
      Person.call(this,name,age,sex); 
      this.score = score;
    }
    // 子类型的原型对象上,需要继承父类型原型对象的方法
    // 方法1:对象拷贝继承
    for (var k in Person.prototype) {
      // 保留自己的 constructor 不要进行继承
      if (k === "constructor") {
        continue;
      }
      Student.prototype[k] = Person.prototype[k];
    } 

    // 方法2:原型继承
    Student.prototype = new Person();
    Student.prototype.constructor = Student;
    
    // 老师类型
    function Teacher(name,age,sex,salary) {
      Person.call(this,name,age,sex); 
      this.salary = salary;
    }
    // 创建学生的实例对象
    var s1 = new Student("zs",18,"男",89);
    s1.sayHi();

4.组合继承

  • 函数属性在构造函数内部继承,方法通过原型继承
function Person(name,age) {
      this.name = name;
      this.age = age;
    }
    Person.prototype.sayHi = function () {
      console.log("你好");
    }
    // 生成一个子类型
    function Teacher(name,age,salary) {
      // 继承父类的属性
      Person.call(this,name,age);
      this.salary = salary;
    }
    // 方法继承,通过原型对象继承
    Teacher.prototype = new Person();
    Teacher.prototype.constructor = Teacher;
    // 生成老师的一个实例
    var t1 = new Teacher("wang",45,10000);
    console.dir(t1);
    console.log(t1.name);
    t1.sayHi();

二.函数定义方式

  • 函数声明
    1.声明时必须定义函数名
 function fun() {
       console.log(1);
    }
  • 函数表达式
    1.将函数赋值给一个变量,可以是一个匿名函数
  • new Function
    1.通过构造函数方法定义函数
    2.函数本身也是一种对象
var fun = new Function('a','b','var a = "1";console.log(a+b)');
fun(2,3);

函数声明与函数表达式的区别
• 函数声明必须有名字
• 函数声明会函数提升,在预解析阶段就已创建,声明前后都可以调用
• 函数表达式类似于变量赋值
• 函数表达式可以没有名字,例如匿名函数
• 函数表达式没有函数提升,在执行阶段创建,必须在表达式执行之后才可以调用

三.函数的调用

  1. 普通的函数,是通过 给函数名或者变量名添加 () 方式执行,
  • 内部的 this 默认指向 window

2.构造函数,是通过 new 关键字进行调用

  • 内部的 this 指向的是将来创建的实例对象
function Person(name) {
     this.name = name;
     console.log(this);
}
var p1 = new Person("zs");
Person();

3.对象中的方法,是通过对象打点调用函数,然后加小括号

  • 内部的 this 默认指向的是调用的对象自己
 var o = {
      sayHi: function () {
        console.log("haha");
   },
}
o.sayHi();

this 的指向是要联系执行的上下文,在调用的时候,是按照什么方式调用,指向是不一样的

4.事件函数,不需要加特殊的符号,只要事件被触发,会自动执行函数

  • 事件函数的内部 this 指向的是事件源

5.定时器和延时器中的函数,不需要加特殊的符号,只要执行后,在规定的时间自动执行

  • 默认内部的 this 指向的是 window
setInterval(function () {
      console.log("time");
  },1000);

推荐阅读更多精彩内容