【js高级 Day3】深入理解原型的方式继承,借用构造函数继承,组合继承,拷贝继承

01 课程介绍

在这里插入图片描述

02 复习

面向过程和面向对象都是编程的思想,方式不一样

  • 面向过程:凡事都是亲力亲为,所有的代码都要自己写,每一步都要很清楚,注重的是过程
  • 面向对象:执行者成为指挥者,只要找对象,然后让对象做相关的事情,注重的是结果

面向对象的特性:封装,继承,多态
封装;就是代码的封装,把一些特征和行为封装在对象中.

面向对象的编程思想:根据需求,抽象出相关的对象,总结对象的特征和行为,把特征变成属性,行为变成方法,然后定义(js)构造函数,实例化对象,通过对象调用属性和方法,完成相应的需求.—编程的思想

对象:具体特指的某个事物,有特征(属性)和行为(方法)

如何创建对象?

  • 通过调用new Object(),还有{},自定义构造函数

创建对象的方式

**1. 调用系统Object()----->创建出来的对象都是Object类型的,不能很明确的指出这个对象是属于什么类型

  • 字面量的方式{}----->只能创建一个对象(一次只能创建一个)**

3.工厂模式创建对象----->----->推论---->自定义构造函数的方式
自定义构造函数(优化后的工厂模式)

自定义构造函数创建对象:4件事
1.在内存中申请一块空闲的空间,存储创建的对象
2.this就是当前实例化的对象
3.设置对象中的属性和方法(为对象添加属性和方法,为属性和方法赋值)
4.把创建后的对象返回
都是需要通过new的方式

什么是原型?

  • 构造函数中有一个属性prototype,是原型,程序员使用的
  • 实例对象中有一个属性__proto__,是原型,浏览器使用的,不是很标准的,
  • 实例对象中的__proto__指向的就是该实例对象中的构造函数中的prototyp
  • 构造函数中的prototype里面的属性或者方法,可以直接通过实例对象调用

正常的写法:
实例对象.__proto__才能访问到构造函数中的prototype中的属性或者方法

 per.__proto__.eat();//__proto__不是标准的属性
 per.eat();

原型就是属性,而这个属性也是一个对象

Person.prototype--->是属性
Person.prototype.属性或者Person.ptototype.方法()

本身在构造函数中定义的属性和方法,当实例化对象的时候,实例对象中的属性和方法都是在自己的空间中存在的,如果是多个对象。这些属性和方法都会在单独的空间中存在,浪费内存空间,所以,为了数据共享,把想要节省空间的属性或者方法写在原型对象中,达到了数据共享,实现了节点内存空间

 function Person(name){
  this.name=name;
 }
 Person.prototype.sex="男";
 var per=new Person("小明");
 per.sex
 var per2=new Person("小芳");
 per2.sex

原型的作用之一:数据共享,节省内存空间

原型的写法:

  • 构造函数.prototype.属性=值
  • 构造函数.prototype.方法=值---->函数.prototype,函数也是对象,所以,里面也有__proto__
  • 实例对象.prototype-------->实例对象中没有这个属性,只有__proto__(暂时的)

简单的原型的写法
缺陷:—>新的知识点---->原型直接指向{}---->就是一个对象,没有构造器

 构造函数.prototype={
 切记:如果这这种写法,要把构造器加上

 };

通过原型为内置对象添加原型的属性或者方法----->原因:
系统的内置对象的属性和方法可能不满足现在需求,所以,可以通过原型的方式加入属性或者方法,为了方便开发

为内置对象的原型中添加属性和方法,那么这个内置对象的实例对象就可以直接使用了

  • String.prototype.方法=匿名函数;
  • var str=“哈哈”;
  • str.方法();---->实例对象可以直接调用原型中的属性或者方法
String.prototype.fdsfdsf=function(){};

凡是string的实例对象都可以调用刚刚加入的方法

案例分析:
面向对象的思想来做: 分析对象,抽象出对象的特征和行为,定义构造函数,属性可以不共享
部分方法需要共享,方法加到prototype中定义(在原型中定义方法,数据共享,节省内存空间)

食物对象(食物的横纵坐标,宽和高,背景颜色)

食物需要画出来—渲染出来–画,随机的画,在画食物的时候要先删除原来的食物

小蛇对象(宽,高,方向)
蛇需要画出来—渲染出来–画,每走一次,需要把前一次的小蛇删除
蛇走的时候,需要方向,是否吃到了食物
小蛇移动的时候,是否吃了食物(吃了就要把小蛇的后面加一个食物的宽和高,颜色,无非就是把原来的蛇尾复制了一个加入到body中,------>把蛇尾拿出来再次加入到蛇尾的后面)

游戏对象(初始化食物,初始化小蛇,自动移动小蛇,判断按键)
自动的设置小蛇移动,判断小蛇是否撞墙,用户按下了什么方向键

window.变量=值;把这个局部变量的值暴露给window,成为了全局变量

 function Person(age) {
    this.age=age;
    this.study=function () {

    }
  }
  Person.prototype.sex="男";//属性,属性在原型中
  Person.prototype.sayHi=function () {//方法,方法在原型中
    console.log("您好");
  };
  //实例化对象同时进行初始化
  var per=new Person(10);
//    console.log(per.__proto__.sex);
//    per.__proto__.sayHi();

  console.log(per.sex);
  per.sayHi();

  Person.prototype={
    //简单的原型的写法,缺少构造器
    constructor:Person
  };


 //为内置对象添加原型方法
  String.prototype.sayHi=function () {
    console.log("字符串的打招呼的方法");
  };
  //是一个实例对象
  var str="字符串";
  str.sayHi();
  //实例对象调用属性或者方法,属性或者方法肯定是在构造函数中或者是构造函数的原型中

03 原型及原型链

使用对象---->使用对象中的属性和对象中的方法,使用对象就要先有构造函数
构造函数

 function Person(name,age) {
   //属性
   this.name=name;
   this.age=age;
   //在构造函数中的方法
   this.eat=function () {
     console.log("吃好吃的");
   };
 }

添加共享的属性

Person.prototype.sex="男";

添加共享的方法

Person.prototype.sayHi=function () {
   console.log("您好啊,怎么这么帅,就是这么帅");
 };

实例化对象,并初始化

var per=new Person("小明",20);
 per.sayHi();

如果想要使用一些属性和方法,并且属性的值在每个对象中都是一样的,方法在每个对象中的操作也都是一样,那么,为了共享数据,节省内存空间,是可以把属性和方法通过原型的方式进行赋值

console.dir(per);//实例对象的结构
 console.dir(Person);//构造函数的结构

实例对象的原型__proto__和构造函数的原型prototype指向是相同的

实例对象中的__proto__原型指向的是构造函数中的原型prototype

 console.log(per.__proto__==Person.prototype);

实例对象中__proto__是原型,浏览器使用的
构造函数中的prototype是原型,程序员使用的

原型链:是一种关系,实例对象和原型对象之间的关系,关系是通过原型(proto)来联系的

04 原型的指向是否可以改变

构造函数中的this就是实例对象
原型对象中方法中的this就是实例对象

function Person(age) {
  this.age=age;
  console.log(this);
}
Person.prototype.eat=function () {
  console.log(this);
  console.log("您吃了没,走着,吃点臭豆腐去");
};
var per=new Person(10);
per.eat();
console.log(per);
 function Student() {

 }
 Student.prototype.study=function () {
   console.log("就是天天学习,学习如何做人,如何敲代码,如何成为人");
 };
 Student.prototype={
   eat:function () {
     console.log("哈哈,好吃的榴莲酥");
   }
 };

 var stu=new Student();

 stu.eat();
//人的构造函数
  function Person(age) {
    this.age=10;
  }
  //人的原型对象方法
  Person.prototype.eat=function () {
    console.log("人的吃");
  };
  //学生的构造函数
  function Student() {

  }
  Student.prototype.sayHi=function () {
    console.log("嗨,小苏你好帅哦");
  };
  //学生的原型,指向了一个人的实例对象
  Student.prototype=new Person(10);
  var stu=new Student();
  stu.eat();
  stu.sayHi();

原型指向可以改变

  • 实例对象的原型__proto__指向的是该对象所在的构造函数的原型对象
  • 构造函数的原型对象(prototype)指向如果改变了,实例对象的原型(proto)指向也会发生改变

原型的指向是可以改变的

  • 实例对象和原型对象之间的关系是通过__proto__原型来联系起来的,这个关系就是原型链

05 原型最终指向了哪里

function Person() {

 }
 Person.prototype.eat=function () {
   console.log("吃东西");
 };
 var per=new Person();
 console.dir(per);
 console.dir(Person);

实例对象中有__proto__原型
构造函数中有prototype原型
prototype是对象
所以,prototype这个对象中也有__proto__,那么指向了哪里
实例对象中的__proto__指向的是构造函数的prototype
所以,prototype这个对象中__proto__指向的应该是某个构造函数的原型prototype

Person的prototype中的__proto__的指向
console.log(Person.prototype.proto);
per实例对象的__proto__------->Person.prototype的__proto__---->Object.prototype的__proto__是null

 console.log(per.__proto__==Person.prototype);
 console.log(per.__proto__.__proto__==Person.prototype.__proto__);
 console.log(Person.prototype.__proto__==Object.prototype);
 console.log(Object.prototype.__proto__);

浏览器显示结果:
在这里插入图片描述

06 原型指向改变如何添加方法和访问

//人的构造函数
   function Person(age) {
     this.age=age;
   }
   //人的原型中添加方法
   Person.prototype.eat=function () {
     console.log("人正在吃东西");
   };
   //学生构造函数
   function Student(sex) {
     this.sex=sex;
   }

   //学生的原型中添加方法----先在原型中添加方法
   Student.prototype.sayHi=function () {
     console.log("您好哦");
   };
   //改变了原型对象的指向
   Student.prototype=new Person(10);

   var stu=new Student("男");
   stu.eat();
   stu.sayHi();
   //人的构造函数
     function Person(age) {
       this.age=age;
     }
     //人的原型中添加方法
     Person.prototype.eat=function () {
       console.log("人正在吃东西");
     };
     //学生构造函数
     function Student(sex) {
       this.sex=sex;
     }
 
     //改变了原型对象的指向
     Student.prototype=new Person(10);
     //学生的原型中添加方法----先在原型中添加方法
     Student.prototype.sayHi=function () {
       console.log("您好哦");
     };
     var stu=new Student("男");
     stu.eat();
     stu.sayHi();
 
     console.dir(stu);

如果原型指向改变了,那么就应该在原型改变指向之后添加原型方法

  function Person(age) {
    this.age = age;
  }

  //指向改变了
  Person.prototype = {
    eat: function () {
      console.log("吃");
    }
  };
  //先添加原型方法
  Person.prototype.sayHi = function () {
    console.log("您好");
  };
  var per = new Person(10);
  per.sayHi();

07 实例对象的属性和原型对象中的属性重名问题

function Person(age,sex) {
    this.age=age;
    this.sex=sex;
  }
  Person.prototype.sex="女";
  var per=new Person(10,"男");
  console.log(per.sex);

因为JS是一门动态类型的语言,对象没有什么,只要点了,那么这个对象就有了这个东西,没有这个属性,只要对象.属性名字,对象就有这个属性了,但是,该属性没有赋值,所以,结果是:undefined

  console.log(per.fdsfdsfsdfds)
  console.log(fsdfdsfds);

实例对象访问这个属性,应该先从实例对象中找,找到了就直接用,找不到就去指向的原型对象中找,找到了就使用,找不到呢?=====
通过实例对象能否改变原型对象中的属性值?不能
就想改变原型对象中属性的值,怎么办?直接通过原型对象.属性=值;可以改变

  Person.prototype.sex="哦唛嘎的";
  per.sex="人";
  console.log(per.sex);

  console.dir(per);

08 一个很神奇的原型链

原型链:实例对象和原型对象之间的关系,通过__proto__来联系

 var divObj=document.getElementById("dv");
  console.dir(divObj);

divObj.proto
---->HTMLDivElement.prototype的__proto__
—>HTMLElement.prototype的__proto__-
—>Element.prototype的__proto__---->Node.prototype的__proto__---->EventTarget.prototype的__proto__---->Object.prototype没有__proto__,所以,Object.prototype中的__proto__是null

09 继承

面向对象编程思想:根据需求,分析对象,找到对象有什么特征和行为,通过代码的方式来实现需求,要想实现这个需求,就要创建对象,要想创建对象,就应该显示有构造函数,然后通过构造函数来创建对象.,通过对象调用属性和方法来实现相应的功能及需求,即可

首先JS不是一门面向对象的语言,JS是一门基于对象的语言,那么为什么学习js还要学习面向对象,因为面向对象的思想适合于人的想法,编程起来会更加的方便,及后期的维护…

面向对象的编程语言中有类(class)的概念(也是一种特殊的数据类型),但是JS不是面向对象的语言,所以,JS中没有类(class),但是JS可以模拟面向对象的思想编程,JS中会通过构造函数来模拟类的概念(class)

小明,小红,小丽,小白,小花 都是人
共同的特征和行为
特征—>属性
行为—方法

面向对象的特性:封装,继承,多态

封装:就是包装
一个值存储在一个变量中–封装
一坨重复代码放在一个函数中–封装
一系列的属性放在一个对象中–封装
一些功能类似的函数(方法)放在一个对象中–封装
好多相类似的对象放在一个js文件中—封装

继承: 首先继承是一种关系,类(class)与类之间的关系,JS中没有类,但是可以通过构造函数模拟类,然后通过原型来实现继承
继承也是为了数据共享,js中的继承也是为了实现数据共享

原型作用之一:数据共享,节省内存空间
原型作用之二:为了实现继承

继承是一种关系:
父类级别与类级别的关系

例子:
小杨—>人, 姓名, 有钱, 帅, 有功夫–降龙十八掌
小杨子–>人,

继承:
姓氏----继承
外表----继承
财产----继承
功夫—继承

人: 姓名, 性别, 年龄 ,吃饭, 睡觉
学生类别: 姓名, 性别, 年龄 ,吃饭, 睡觉 学习行为
老师类别: 姓名, 性别, 年龄 ,吃饭, 睡觉 工资,教学行为
程序员: 姓名, 性别, 年龄 ,吃饭, 睡觉 工资, 敲代码
司机类别: 姓名, 性别, 年龄 ,吃饭, 睡觉 工资 开车
动物类别: 体重, 颜色, 吃
狗类别: 体重,颜色, 吃, 咬人
二哈类别: 体重,颜色, 吃, 咬人 逗主人开心,汪汪,你好帅

多态:一个对象有不同的行为,或者是同一个行为针对不同的对象,产生不同的结果,要想有多态,就要先有继承,js中可以模拟多态,但是不会去使用,也不会模拟,

例子:
人,都有姓名,性别,年龄, 吃饭, 睡觉, 玩
学生,都有姓名,性别,年龄, 成绩, 吃饭, 睡觉, 玩 ,学习的行为

js中通过原型来实现继承

  function Person(name,age,sex) {
    this.name=name;
    this.sex=sex;
    this.age=age;
  }
  Person.prototype.eat=function () {
    console.log("人可以吃东西");
  };
  Person.prototype.sleep=function () {
    console.log("人在睡觉");
  };
  Person.prototype.play=function () {
    console.log("生活就是不一样的玩法而已");
  };


  function Student(score) {
    this.score=score;
  }
  //改变学生的原型的指向即可==========>学生和人已经发生关系
  Student.prototype=new Person("小明",10,"男");
  Student.prototype.study=function () {
    console.log("学习很累很累的哦.");
  };

  //相同的代码太多,造成了代码的冗余(重复的代码)

  var stu=new Student(100);
  console.log(stu.name);
  console.log(stu.age);
  console.log(stu.sex);
  stu.eat();
  stu.play();
  stu.sleep();
  console.log("下面的是学生对象中自己有的");
  console.log(stu.score);
  stu.study();

10 继承案例

动物有名字,有体重,有吃东西的行为
小狗有名字,有体重,有毛色, 有吃东西的行为,还有咬人的行为
哈士奇名字,有体重,有毛色,性别, 有吃东西的行为,还有咬人的行为,逗主人开心的行为

//动物的构造韩素
 function Animal(name,weight) {
   this.name=name;
   this.weight=weight;
 }
 //动物的原型的方法
 Animal.prototype.eat=function () {
   console.log("天天吃东西,就是吃");
 };

 //狗的构造函数
 function Dog(color) {
   this.color=color;
 }
 Dog.prototype=new Animal("哮天犬","50kg");
 Dog.prototype.bitePerson=function () {
   console.log("哼~汪汪~咬死你");
 };

 //哈士奇
 function ErHa(sex) {
   this.sex=sex;
 }
 ErHa.prototype=new Dog("黑白色");
 ErHa.prototype.playHost=function () {
   console.log("哈哈~要坏衣服,要坏桌子,拆家..嘎嘎...好玩,开心不,惊喜不,意外不");
 };
 var erHa=new ErHa("雄性");
 console.log(erHa.name,erHa.weight,erHa.color);
 erHa.eat();
 erHa.bitePerson();
 erHa.playHost();

11 借用构造函数

function Person(name,age,sex,weight) {
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.weight=weight;
  }
  Person.prototype.sayHi=function () {
    console.log("您好");
  };
  function Student(score) {
    this.score=score;
  }
  //希望人的类别中的数据可以共享给学生---继承
  Student.prototype=new Person("小明",10,"男","50kg");

  var stu1=new Student("100");
  console.log(stu1.name,stu1.age,stu1.sex,stu1.weight,stu1.score);
  stu1.sayHi();

  var stu2=new Student("120");
  stu2.name="张三";
  stu2.age=20;
  stu2.sex="女";
  console.log(stu2.name,stu2.age,stu2.sex,stu2.weight,stu2.score);
  stu2.sayHi();
  var stu3=new Student("130");
  console.log(stu3.name,stu3.age,stu3.sex,stu3.weight,stu3.score);
  stu3.sayHi();

为了数据共享,改变原型指向,做到了继承—通过改变原型指向实现的继承
缺陷:因为改变原型指向的同时实现继承,直接初始化了属性,继承过来的属性的值都是一样的了,所以,这就是问题
只能重新调用对象的属性进行重新赋值,

解决方案:继承的时候,不用改变原型的指向,直接调用父级的构造函数的方式来为属性赋值就可以了------借用构造函数:把要继承的父级的构造函数拿过来,使用一下就可以了

借用构造函数:构造函数名字.call(当前对象,属性,属性,属性…);
解决了属性继承,并且值不重复的问题
缺陷:父级类别中的方法不能继承

function Person(name, age, sex, weight) {
    this.name = name;
    this.age = age;
    this.sex = sex;
    this.weight = weight;
  }
  Person.prototype.sayHi = function () {
    console.log("您好");
  };
  function Student(name,age,sex,weight,score) {
    //借用构造函数
    Person.call(this,name,age,sex,weight);
    this.score = score;
  }
  var stu1 = new Student("小明",10,"男","10kg","100");
  console.log(stu1.name, stu1.age, stu1.sex, stu1.weight, stu1.score);

  var stu2 = new Student("小红",20,"女","20kg","120");
  console.log(stu2.name, stu2.age, stu2.sex, stu2.weight, stu2.score);

  var stu3 = new Student("小丽",30,"妖","30kg","130");
  console.log(stu3.name, stu3.age, stu3.sex, stu3.weight, stu3.score);

12 组合继承

原型实现继承
借用构造函数实现继承
组合继承:原型继承+借用构造函数继承

 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;
 }
 //改变原型指向----继承
 Student.prototype=new Person();//不传值
 Student.prototype.eat=function () {
   console.log("吃东西");
 };
 var stu=new Student("小黑",20,"男","100分");
 console.log(stu.name,stu.age,stu.sex,stu.score);
 stu.sayHi();
 stu.eat();
 var stu2=new Student("小黑黑",200,"男人","1010分");
 console.log(stu2.name,stu2.age,stu2.sex,stu2.score);
 stu2.sayHi();
 stu2.eat();

 //属性和方法都被继承了

13 拷贝继承

拷贝继承;把一个对象中的属性或者方法直接复制到另一个对象中

  var obj1={
    name:"小糊涂",
    age:20,
    sleep:function () {
     console.log("睡觉了");
    }
  };

  //改变了地址的指向
  var obj2=obj1;
  console.log(obj2.name,obj2.age);
  obj2.sleep();



   var obj1={
     name:"小糊涂",
     age:20,
     sleep:function () {
       console.log("睡觉了");
     }
   };  
   var obj2={};
   for(var key in obj1){
     obj2[key]=obj1[key];
   }
   console.log(obj2.name);



  function Person() {
  }
  Person.prototype.age=10;
  Person.prototype.sex="男";
  Person.prototype.height=100;
  Person.prototype.play=function () {
    console.log("玩的好开心");
  };
  var obj2={};

Person的构造中有原型prototype,prototype就是一个对象,那么里面,age,sex,height,play都是该对象中的属性或者方法

 for(var key in Person.prototype){
   obj2[key]=Person.prototype[key];
 }
 console.dir(obj2);
 obj2.play();

14 总结继承

面向对象特性:封装,继承,多态

继承,类与类之间的关系,面向对象的语言的继承是为了多态服务的,
js不是面向对象的语言,但是可以模拟面向对象.模拟继承.为了节省内存空间

继承:

原型作用: 数据共享 ,目的是:为了节省内存空间,
原型作用: 继承 目的是:为了节省内存空间

原型继承:改变原型的指向
借用构造函数继承:主要解决属性的问题
组合继承:原型继承+借用构造函数继承
既能解决属性问题,又能解决方法问题
拷贝继承:就是把对象中需要共享的属性或者犯法,直接遍历的方式复制到另一个对象中

15 逆推继承看原型

 function F1(age) {
   this.age = age;
 }
 function F2(age) {
   this.age = age;
 }
 F2.prototype = new F1(10);
 function F3(age) {
   this.age = age;
 }
 F3.prototype = new F2(20);

 var f3 = new F3(30);
 console.log(f3.age);//

16 函数的角色

//函数的角色:
//函数的声明
function f1() {
  console.log("我是函数");
}
f1();
//函数表达式
var ff=function () {
  console.log("我也是一个函数");
};
ff();

17 函数声明和函数表达式的区别

//函数声明
if(true){
   function f1() {
     console.log("哈哈,我又变帅了");
   }
 }else{
   function f1() {
     console.log("小苏好猥琐");
   }
 }
 f1();
 //函数表达式
 var ff;
 if(true){
   ff=function () {
     console.log("哈哈,我又变帅了");
   };
 }else{
   ff=function () {
     console.log("小苏好猥琐");
   };
 }
 ff();

函数声明如果放在if-else的语句中,在IE8的浏览器中会出现问题
以后宁愿用函数表达式,都不用函数声明

18 函数中的this指向的问题

函数中的this的指向

普通函数中的this是谁?-----window
对象.方法中的this是谁?----当前的实例对象
定时器方法中的this是谁?----window
构造函数中的this是谁?-----实例对象
原型对象方法中的this是谁?—实例对象

严格模式:

"use strict";//严格模式
function f1() {
  console.log(this);//window
}
f1();
普通函数
function f1() {
   console.log(this);
 }
f1();

定时器中的this

 setInterval(function () {
   console.log(this);
 },1000);

构造函数

function Person() {
  console.log(this);

对象的方法

this.sayHi=function () {
    console.log(this);
  };
}

原型中的方法

  Person.prototype.eat=function () {
      console.log(this);
    };
    var per=new Person();
    console.log(per);
    per.sayHi();
    per.eat();

BOM:中顶级对象是window,浏览器中所有的东西都是window的

19 函数的不同的调用方式

普通函数

function f1() {
  console.log("文能提笔控萝莉");
}
f1();

构造函数—通过new 来调用,创建对象

function F1() {
  console.log("我是构造函数,我骄傲");
}
var f=new F1();

对象的方法

  function Person() {
    this.play=function () {
      console.log("玩代码");
    };
  }
  var per=new Person();
  per.play();

20 函数也是对象

函数是对象,对象不一定是函数

对象中有__proto__原型,是对象
函数中有prototype原型,是对象

function F1() {
 }

 console.dir(F1);

 console.dir(Math);//中有__proto__,但是没有prorotype
  • 对象中有__proto__,函数中应该有prototype
  • 如果一个东西里面有prototype,又有__proto__,说明是函数,也是对象
 function F1(name) {
   this.name=name;
 }

 console.dir(F1);

所有的函数实际上都是Function的构造函数创建出来的实例对象

 var f1=new Function("num1","num2","return num1+num2");
 console.log(f1(10,20));
 console.log(f1.__proto__==Function.prototype);

所以,函数实际上也是对象

 console.dir(f1);
 console.dir(Function);

21 数组的函数调用

数组可以存储任何类型的数据

  var arr=[
      function () {
        console.log("hls1183676168");
      },
      function () {
        console.log("hls1183676168");
      }
      ,
      function () {
        console.log("hls1183676168");
      }
      ,
      function () {
        console.log("hls1183676168");
      },
      function () {
        console.log("hls1183676168");
      }
  ];
  

回调函数:函数作为参数使用

arr.forEach(function (ele) {
  ele();
});

其他参考链接

【js高级 Day1】深入理解原型及作用,构造函数和实例对象和原型对象之间的关系

【js高级 Day2】深入理解原型添加方法,私有函数,面向对象的编程思想(案例小贪吃蛇)

【js高级 Day3】深入理解原型的方式继承,借用构造函数继承,组合继承,拷贝继承

【js高级 Day4】深入理解apply和call方法,作用域,闭包,递归

【js高级 Day5】深入理解浅拷贝,深拷贝,遍历DOM树,正则表达式

【如果你是新手】推荐链接

【 js基础 Day1】js的介绍及基本语法变量,运算符

【 js基础 Day2】js的流程控制:分支语句,循环.顺序结构

【 js基础 Day3】关键字的使用,数组(重点)和函数(重点)

【 js基础 Day4】面向过程,面向对象,自定义对象,内置对象

【 js基础 Day5】函数(重点),作用域,预解析,arguments,对象

【 js基础 Day6】内置对象和基本包装类型等知识

发布了227 篇原创文章 · 获赞 41 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_42554191/article/details/104357046