专栏首页前端与Java学习前端day18-JS高级(完整的原型链)学习笔记
原创

前端day18-JS高级(完整的原型链)学习笔记

01-面向对象三大特征(封装、继承、多态)

  • a.封装:将某个具体功能封装在对象中,只对外部暴露指定的接口,外界在使用的时候,只考虑接口怎么用,不用考虑内部怎么实现(前面学习的api其实就是一种封装思想) ​
  • b.继承:一个对象拥有其他对象的属性和方法 ​
  • c.多态:一个对象在不同情况下的多种状态

1.1-多态(js中了解即可)

<script>
    /*多态(JS中了解即可,使用不多):一个对象在不同情况的多种状态
        饲养员对象Person : 给动物对象喂养食物  funtion work(animal,food){ animal.eat(food) }
        动物对象Animal : 吃东西  eat(food){ }
        多态 : 给不同的动物喂养食物,虽然都是调用eat()方法,但是不同的动物会执行不同的eat()
    */
    //示例:饲养员给动物喂食物
    
    //动物
    function Animal ( name ) {
        this.name = name;
    };
    //猫
    var cat = new Animal('猫咪');
    cat.eat = function ( food ) {
        console.log ( "喵喵猫" + "我吃了" + food );
    };
    //狗
    var dog = new Animal('小狗狗');
    dog.eat = function ( food ) {
        console.log ( "汪汪汪" + "我吃了" + food );
    };
    //饲养员
    function Person (  name ) {
        this.name = name;
    };
    
    Person.prototype.work = function (animal,food ) {
        //animal接收一个由Anmiaml构造函数生成的实例化对象,调用它的eat方法
        //同一对象表现出来不同的状态,就叫做多态
        animal.eat(food);
    };

    var p1 = new Person('林绿裙');
    p1.work(cat, '饼干');
    p1.work(dog, '翔');


</script>

1.2-继承(三种实现方式)
  • 1.混入式继承 : 遍历 父对象 的所有属性值,添加给 子对象
    • 特点:每继承一次,就要执行一次循环
    • 应用场景:单个对象继承
  • 2.替换原型继承 : 将 父对象 作为 子对象构造函数的原型
    • 特点:会丢失原型之前的成员变量
    • 应用场景:多个对象继承
  • 3.混合式继承 : 混入式 + 替换原型
    • 特点 : 遍历 父对象 所有的属性值,添加给 子对象构造函数 的原型

<script>
​
    /*学习目标 : 继承的三种实现方式 
        1.混入式继承 : 遍历 父对象 的所有属性值,添加给 子对象
            特点:每继承一次,就要执行一次循环
            应用场景:单个对象继承
​
        2.替换原型继承 : 将 父对象 作为 子对象构造函数的原型
            特点:会丢失原型之前的成员变量
            应用场景:多个对象继承
​
        3. 混合式继承 : 混入式 + 替换原型
            特点 : 遍历 父对象 所有的属性值,添加给 子对象构造函数 的原型
​
     */
    //继承:让一个对象拥有另一个对象的属性和方法
    var wangjianlin = {
        house:{
            address:'北京一环',
            price:100000000
        },
        car:{
            brand:'劳斯莱斯',
            price:5000000
        }
    };
    var wangsicong = {
        girlFriends:['雪梨','豆得儿','林更新','王建刚','赵铁柱']
    };
    //wangsicong这个对象想要继承wangjianlin这个对象的属性和方法
​
    //1.混入式
    //解决方案:遍历wangjianlin的所有属性值,添加给wangsicong对象
    //特点:每继承一次,就要执行一次循环
    //应用场景 : 单个对象继承
/*
    for (var key in wangjianlin){
        wangsicong[key] = wangjianlin[key];
    }
    console.log ( wangsicong );
*/
​
    //2.替换原型
    //解决方案:将wangjianlin对象作为构造函数的原型
    //特点:会丢失原型之前的成员变量
    //应用场景:多个对象继承
/*
    function SonWang (name,gfs  ) {
        this.name = name;
        this.gfs = gfs;
    };
    //每一个SonWang构造函数实例化的对象都有一个花钱的方法,那这个方法就可以写在原型中
    SonWang.prototype.flowerMoney = function (  ) {
        console.log ( "我很会花钱哄女孩子吃六块钱的麻辣烫…………" );
    }
​
    //让wangjianlin对象成为SonWang构造函数的原型,所有SonWang构造的实例化对象都可以访问wangjianlin的成员变量
    SonWang.prototype  = wangjianlin;
​
    //实例化对象
    var son1 = new SonWang('聪聪',['雪梨','豆得儿','林更新','王建刚','赵铁柱']);
    console.log ( son1 );
    var son2 = new SonWang('班长',['苍老师','吉泽老师','结衣老师','白石老师']);
    console.log ( son2 );
*/
​
​
    //3.  混合式(混入+替换原型)
    //解决方案:遍历wangjianlin对象所有的属性值,添加给构造函数的原型
    function SonWang (name,gfs  ) {
        this.name = name;
        this.gfs = gfs;
    };
    //每一个SonWang构造函数实例化的对象都有一个花钱的方法,那这个方法就可以写在原型中
    SonWang.prototype.flowerMoney = function (  ) {
        console.log ( "我很会花钱哄女孩子吃六块钱的麻辣烫…………" );
    }
​
   //将wangjianlin对象的所有属性添加到SonWang构造函数的原型中
    for(var key in wangjianlin){
        SonWang.prototype[key] = wangjianlin[key];
    }
​
    //实例化对象
    var son1 = new SonWang('聪聪',['雪梨','豆得儿','林更新','王建刚','赵铁柱']);
    console.log ( son1 );
    var son2 = new SonWang('班长',['苍老师','吉泽老师','结衣老师','白石老师']);
    console.log ( son2 );
</script>

1.3-混合式继承函数封装

/**混合式继承
     *
     * @param method 要继承的子对象构造函数
     * @param father 被继承的父对象
     */
    function extend (method,father  ) {
        for(var key in father){
            method.prototype[key] = father[key];
        }
    }

//继承:让一个对象拥有另一个对象的属性和方法
    var wangjianlin = {
        house:{
            address:'北京一环',
            price:100000000
        },
        car:{
            brand:'劳斯莱斯',
            price:5000000
        }
    };
    var wangsicong = {
        girlFriends:['雪梨','豆得儿','林更新','王建刚','赵铁柱']
    };
    //wangsicong这个对象想要继承wangjianlin这个对象的属性和方法
    //解决方案:遍历wangjianlin对象所有的属性值,添加给构造函数的原型
    function SonWang (name,gfs  ) {
        this.name = name;
        this.gfs = gfs;
    };
    //每一个SonWang构造函数实例化的对象都有一个花钱的方法,那这个方法就可以写在原型中
    SonWang.prototype.flowerMoney = function (  ) {
        console.log ( "我很会花钱哄女孩子吃六块钱的麻辣烫…………" );
    }
    //将wangjianlin对象的所有属性添加到SonWang构造函数的原型中
    // for(var key in wangjianlin){
    //     SonWang.prototype[key] = wangjianlin[key];
    // }
    //调用封装好的继承函数
    extend(SonWang,wangjianlin);

    //实例化对象
    var son1 = new SonWang('聪聪',['雪梨','豆得儿','林更新','王建刚','赵铁柱']);
    console.log ( son1 );
    var son2 = new SonWang('班长',['苍老师','吉泽老师','结衣老师','白石老师']);
    console.log ( son2 );

02-原型链

2.1-原型链介绍

  • 1.原型链:每一个对象都有原型,原型本身又是对象,所以原型又有原型,以此类推形成一个链式结构,称为原型链
  • 2.对象访问原型链中的成员规则:就近原则
    • 当访问一个对象的成员变量时,会首先访问它自身的成员变量,如果有则访问。没有则在原型中寻找,能找到就访问,不能找到则继续往原型的原型中寻找,以此类推,如果找到原型链的顶端还是找不到,则程序报错:xxx is not a function
<script>
        //1.构造函数
        function Person(name,age){
            this.name = name;
            this.age = age;
        };

        //2.原型对象
        Person.prototype.sayHi = function(){
            console.log('人生若只如初见,何事秋风悲画扇');
        };

        Person.prototype.type = '哺乳动物';

        //3.实例化对象
        var p1 = new Person('又又',18);
        console.log(p1);

        //请说出以下代码执行结果
        console.log(p1.name);//又又      p1自己有name属性
        console.log(p1.type);//哺乳动物   p1自己没有type,但是p1的原型有
        console.log(p1.hobby);//undefined p1自己没有hobby,原型也没有
        p1.sayHi();// 人生若只如初见,何事秋风悲画扇   p1自己没有这个方法,原型有
        
       // p1.eat();//报错 xxx is not defined    p1自己没有这个方法,原型也没有

       //为什么不报错?  p1自己没有这个方法,原型也没有这个方法,但是原型的原型有
        p1.toString();

        //查看p1的原型链
        console.log(p1.__proto__.constructor);//Person
        console.log(p1.__proto__ === Person.prototype);//true

        //查看p1的原型的原型
        console.log(p1.__proto__.__proto__.constructor);//Object
        console.log(p1.__proto__.__proto__ === Object.prototype);//true

        //查看p1的原型的原型的原型
        console.log(p1.__proto__.__proto__.__proto__);//null
    </script>

1.2-原型链详解:内置对象的原型链

  • 1.通过查看Array的原型链
    • 了解构造函数的原型本身是一个对象,只要是对象就有原型
  • 2.通过查看Date的原型链
    • 学会举一反三,所有的内置对象(Math Array 基本包装类型等)的原型链都是一样的,最终都指向Object
  • 3.通过查看String的原型链:了解这里的String值得是内置对象String(是一个基本包装类型),其他的Number、Boolean原型链和String是一样的
    • 只有对象才有原型,这里一定要把基本数据类型string、number、boolean,和基本包装类型(特殊的引用类型对象)String、Number、Boolean区分开来,不要搞混淆
/*查看内置对象的原型链*/

    //1.Array
    var arr = new Array(10,20,30);
    console.log ( arr );
    //查看arr的原型
    console.log ( arr.__proto__.constructor );//Array
    console.log ( arr.__proto__ === Array.prototype );
    //查看arr的原型的原型
    console.log ( arr.__proto__.__proto__.constructor );//Object
    console.log ( arr.__proto__.__proto__ === Object.prototype );//true

    //2.Date
    var date1 = new Date();
    //细节:日期对象直接console.log会转成string,查看对象需要使用console.dir打印
    console.dir(date1);
    console.log ( date1.__proto__ === Date.prototype );//true
    console.log ( date1.__proto__.__proto__.constructor );//Object
    console.log ( date1.__proto__.__proto__ === Object.prototype );//true

    //3.String
    var str = new String('123');
    console.log ( str.__proto__ === String.prototype );//true
    console.log ( str.__proto__.__proto__.constructor );//Object
    console.log ( str.__proto__.__proto__ === Object.prototype );//true

    //4.Number
    var num = new Number(666);
    console.log(num.__proto__.constructor);//Number
    console.log(Number.prototype);
    console.log(num.__proto__ === Number.prototype);//true

    //4.界面元素
    var div1 = document.getElementById('div1');
    var p1 = document.getElementById('p1');
    console.log(p1.__proto__);//HTMLParagraphElement
    console.log(div1.__proto__);//HTMLDivElement
    console.log(div1.__proto__.__proto__);//HTMLElement
    console.log(div1.__proto__.__proto__.__proto__);//Element
    console.log(div1.__proto__.__proto__.__proto__.__proto__);//Node
    console.log(div1.__proto__.__proto__.__proto__.__proto__.__proto__);//EventTarget
    console.log(div1.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);//Object
    console.log(div1.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__);//null

1.3-函数也是对象

  • 1.function函数属于对象类型
    • 如何验证呢?
      • 对象特征:点语法动态赋值
  • 2.既然函数是对象,那它是由哪一个构造函数来创建的呢?
    • Function构造函数
  • 3.既然函数是对象,那么构造函数Function本身也是对象,它又是由谁构造生成的呢?
    • Object构造函数
 <script>
        /* 
        函数 : 属于对象类型。
            如何验证 :对象可以点语法动态赋值,如果函数也可以像对象一样使用点语法取值赋值,
            就可以证明函数也是对象
         */

        function fn(){
            //存储代码
            console.log('1111');
        };

        fn.aaa = '啊啊啊';
        fn.eat = function(){
            console.log('我中午请你吃饭');
        };
        fn.eat();

        console.log(fn); // log:只能打印函数中存储的代码
        console.dir(fn); // dir:打印函数对象内存

        //查看 函数对象 的原型链
        console.log(fn.__proto__.constructor);//Function
        console.log(fn.__proto__ === Function.prototype);//true

        //查看 函数对象 原型的原型
        console.log(fn.__proto__.__proto__.constructor);//Object
        console.log(fn.__proto__.__proto__ === Object.prototype);//true
        
    </script>

1.4-Function构造函数

  • 1.函数属于对象类型,它是由Function()构造函数生成
    • js中的函数都是由Function()构造函数实例化的对象,包括Object构造函数
  • 2.介绍Function构造函数的语法
<script>
        /* 
        1.js中所有的函数对象 , 都是被 Function构造函数创建
        */

        //1. new Function()
        //参数 (1)前面所有的参数都是函数形参  (2)最后一个参数是函数体代码
        //返回值 : 函数对象
        var fn =  new Function('a','b','console.log("6666");return a+b;');
        var res =  fn(10,20);
        console.log(res);
        

        //2.js基础函数两种声明方式
        //这两种声明方式底层都是调用构造函数 new Function()
        //2.1 函数式声明
        function fn1(a,b){
            return a+b;
            
        };

        //2.2 表达式声明
        var fn2 = function(){

        };
    </script>

1.5-完整原型链

  • 1.完整原型链:了解实例化对象,构造函数,原型对象三者之间的关系
  • 2.完整原型链的总结(不考虑个别特殊情况)
    • 对象与构造函数关系(js中的对象都是构造函数生成)
      • a.原型对象由Object构造函数生成
      • b.函数对象由Function构造函数生成
      • c.实例对象由对应的构造函数生成
    • 原型与构造函数关系
      • a.只要是构造函数就有prototype属性指向自身的原型对象
      • b.只要是原型对象就有constructor属性指向对应的构造函数
      • c.只要是对象就有proto指向与之对应的构造函数的原型对象
        • 特殊情况:Object.prototype的原型对象是null
      • d.函数本身也是对象
<script>
        /* 
        完整原型链 : 了解 函数对象 , 原型对象 , 实例化对象三者的关系
            1. js中所有的对象都是被构造函数生成
            2. 不同的对象被不同的构造函数生成
                a. 原型对象由Object构造函数生成
                b. 函数对象由Function构造函数生成
                c. 实例对象由对应的构造函数生成
         */
        //js中有两种构造函数 :

        //1.js作者写好的 : 内置构造函数
        var obj = {};//new Object
        //查看obj的原型
        console.log(obj.__proto__.constructor);//Object
        console.log(obj.__proto__ === Object.prototype);//true
        
        //2.程序员自己写的构造函数:自定义构造函数
        //自定义构造函数
        function Person(name,age){
            this.name = name;
            this.age = age;
        };

        //原型对象
        console.log(Person.prototype);
        //实例化对象
        var p1 =  new Person('小帅',18);

        //函数也是对象 : 函数对象都是被Function构造函数创建
        //1.查看person构造函数对象的原型链
        console.log(Person.__proto__.constructor);//Function
        console.log(Person.__proto__ === Function.prototype);//true
        
        //2.查看Object构造函数原型链
        console.log(Object.__proto__.constructor);//Function
        console.log(Object.__proto__ === Function.prototype);//true
        
        //3.查看Function构造函数的原型链
        console.log(Function.__proto__.constructor);//Function
        console.log(Function.__proto__ === Function.prototype);//true
    </script>

1.6-instanceof运算符原理

  • instanceof语法: 对象 instanceof 构造函数
  • 作用:检测 一个构造函数的原型(prototype) 在不在 一个对象的原型链中(其意思就是判断对象是否是某一数据类型(如Array)的实例,请重点关注一下是判断一个对象是否是数据类型的实例)
	//1.示例
    var arr = [10,20,30];
    //数组原型链  arr->Arr.prototype->Object.prototype->null
    console.log ( arr instanceof Array );//true
    console.log ( arr instanceof Object );//true

    //2.示例
    //根据instanceof语法:左边Function表示对象,右边Function表示构造函数
    //Function原型链  Function对象->Function.prototype->Object.prototype->null
    console.log ( Function instanceof Function );//true
    console.log ( Function instanceof Object );//true

    //3.示例
    //根据instanceof语法:左边Object表示对象,右边Object表示构造函数
    //Object原型链 Object对象->Function.prototype->Object.prototype->null
    console.log ( Object instanceof Object );//true
    console.log ( Object instanceof Function );//true

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 前端day17-JS高级(原型对象)学习笔记

    帅的一麻皮
  • 前端day13-JS(WebApi)学习笔记(attribute语法、DOM节点操作)

    小技巧:如果API写的是Emement复数的形式,也就是后面加了s(Emements)那么它返回的就是一个伪数组 否则就是单个对象,一般只有id才会是单个对象,...

    帅的一麻皮
  • 前端day21-JS正则表达式

    1.字符类: /[abc]/ 含义:只要字符串中有 a 或者有 b 或者有 c 就满足条件

    帅的一麻皮
  • 前端基础-ES5继承

    实现方式:在子类构造函数中,调用父类构造函数的(call, apply, bind)方法,使用子类构造函数的this去冒充父类构造函数的this。

    cwl_java
  • 【阳光私塾】四个版本的《当你老了》,总有一个让你泪奔

    大数据文摘
  • 用U盘或移动硬盘安装Windows7 (超简单制作Win7安装U盘方法)

    本文来源:http://www.iplaysoft.com/win7-usb-dvd-download-tool.html

    跟着阿笨一起玩NET
  • Centos7下yum安装配置nginx与php

    实现LNMP环境搭建。 开始安装Nginx和PHP-FPM之前,首先卸载系统中以前安装的Apache和PHP保证安装不会冲突。用root登录输入下面的命令: y...

    庞小明
  • 完整教程:Springboot 2.2整合

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    程裕强
  • css(1)

    1 z-index就是网页的z轴,用相对定位绝对定位把两个层重叠在一起,z-index的值越大,就越靠上,注意,z-index没有单位,z-index:99;这...

    城市中的游牧民族
  • React Native仿美团下拉菜单

    在很多产品中都会涉及到下拉菜单选择功能,用的最好的当属美团了,其效果如下: ? 要实现上面的效果,在原生中比较好做,直接使用PopWindow组件即可。如果使...

    xiangzhihong

扫码关注云+社区

领取腾讯云代金券