JS 面向对象编程、原型链、原型继承(个人学习总结)

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/Mr_hermit/article/details/79102002

一、面向对象

1. 面向对象 是所有语言 都有的一种编程思想,组织代码的一种形式
  • 基于对象的语言:JS语言
  • 面向对象的语言:c++ java c#
2. 面向对象 3大特征
封装:将重用代码封装到函数 / 对象中,实现代码复用
继承:继承方法、属性(JS通过原型实现继承、其他语言通过类实现继承)
多态:同一操作针对不同对象,表现出不同的行为(JS中没有多态)
3. 面向对象的优势
  • 模块化,便于维护:将功能相近的代码封装成一个的对象,有代码更改,只需找到对应的对象进行修改即可

  • 减少全局污染,只暴露出一个构造函数,需要的话 new 一个对象就可以

4. 分析 面向过程 、面向对象
  • 面向过程:

  • 所有的细节、步骤、过程,要一步一步亲历亲为(执行者)
  • 代码量少功能简单 的场景 适用
  • 代码执行效率高,创建的变量全局变量太多,环境污染严重(ES5)
  • 面向对象:

    • 把一些功能逻辑,赋予给一个个独立的对象,对象中封装了一些列方法
    • 找到能完成这个事情的对象,让它帮你完成就行(调度者)
    • 对于大型项目,有利于团队合作开发、有利于项目代码的维护扩展,项目更新迭代;
    • 代码执行效率较低;使用面向对象思想编程可能导致代码复杂度提高
    • JQ操作DOM就是一个面向对象的方式
  • 两者关联:面向对象是对面向过程的封装

  • 二、JS 中实现继承的3种方式

    1. 混入式继承for-in:遍历为新对象添加属性、方法
    <script>
        var obj = {
            name: 'zhang',
            age: 11
        };
    
        var o2 = {};
    
        for (var key in obj) {
            o2[key] = obj[key];
        }
    
        console.log(o2);
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • js 原生语法:没有 类似JQ中的 extend() 方法,封装如下:
    <script>
        var obj = {
            name: 'zhang',
            age: 11
        };
    
        var extend = function (obj) {
            var o2 = {};
            for (var key in obj) {
                o2[key] = obj[key];
            }
            return o2;
        }
    
        console.log(extend(obj));
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2. Object.create() 继承 :ES5中; IE8及以下不兼容
    • Object.create(参数的对象) 返回新对象,继承了参数对象上的所有属性、方法
    <script>
        var o1 = {name: 'zhangxin'};
        var create = Object.create(o1);
    
        console.log(create.name);  // 'zhangxin'
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    3. 原型继承:实例对象 继承自 原型对象的方法/属性 【重要】

    三、构造函数

    1. 概念:用于创建对象(对象初始化)的一种普通的函数,一般在 new 运算符后面调用
    • 构造函数名的第一个字母,约定大写;用于区分普通函数

    • new 的作用:

    • 申请内存,创建空对象
    • 改变this指向
    • 给新对象赋值
    • 返回新对象
  • 构造函数中this的作用:为对象添加成员(属性、方法)

  • 构造函数 与 普通函数的区别:

    • 函数内部this指向不同
    • 返回返回值不同
    2. 函数一创建,就有了 prototype 属性,指向原型对象
    • Math 除外,Math 是对象,不是构造函数,没有 prototype 属性
    3. 构造函数中的返回值
    • 构造函数中:一般不写返回值,默认返回新创建的对象

    • 若写了返回值:

    • 返回值为引用类型:忽略新创建的对象,直接返回引用类型的返回值
    • 返回值为基本类型:忽略基本类型,直接返回新创建的对象
    4. 常见的构造函数,但 Math 不是构造函数
    • ObjectFunctionArrayStringNumberRegExpData 这些构造函数都有 prototype属性

    • Math 是对象,不是函数,没有 prototype 属性

    5. 构造函数的作用:对new出来的函数,进行初始化(为属性、方法赋值)

    四、实例(对象)

    1. 对象一创建,就有了 __proto__ 属性,指向原型对象
    • 这个属性是浏览器私有属性,一般不常用
    2. 对象( null除外) 在被创建的那一刻,原型就定下来了, 即: 对象.__proto__
    • 即使修改了 构造函数.prototype 的指向,也不会影响到 已经创建好的对象 的原型对象、原型链

    • 原型对象不会被默认改变,除非手动改变指针方向,即 对象.__proto__的指向

    3. 任何对象 都直接 或 间接的继承自 Object.prototype
    4. 实例化过程:即创建实例对象的过程,new 构造函数

    五、原型(对象)

    1. 理解原型:
    • 原型:用来存放一些公共的属性或方法,让多个实例对象 访问同一个对象中的内容

    • 作用:原型继承,节省内存,实现数据共享

    2. 原型对象 默认有 constructor 属性,指当前的构造函数
    • 改变构造函数.prototype原型指针方向时,最好在新的原型对象上,添加 constructor 属性
    3. 读取 原型对象 指针
    • 构造函数.prototype

    • 实例对象.__proto__ 【生产环境中不使用】

    • 两个属性的区别仅仅是:站在不同的角度访问同一个对象

    4. 原型对象 添加属性、方法
    • 构造函数 . prototype . 属性/方法 =‘’;

    • 实例对象 . proto . 属性/方法 =‘’; 【一般不使用】

    5. 顶级原型 Object.prototype , 万物皆对象
    • Objet.prototype = null
    6. 顶级原型上的属性 —> 任何一个对象都能直接使用(对象本身有同名属性除外)
    (1) Object.prototype.constructor 指向构造函数 Object
    (2) Object.prototype.toString() 判断 当前变量 属于哪种 引用类型
    • Array / String / Number / Date 都有自己的 toString() 方法,即:转为字符串 ; 验证是属于哪个引用类型,可借用 顶级对象上的toString()方法
    <script>
        console.log(Object.prototype.toString());               // [object Object]
        console.log(Math.toString());                           // [object Math]
    
        console.log(Object.prototype.toString.call([]));        // [object Array]
        console.log(Object.prototype.toString.call('aaa'));     // [object String]
        console.log(Object.prototype.toString.call(111));       // [object Number]
        console.log(Object.prototype.toString.call(new Date())); // [object Date]
    
        console.log(Object.prototype.toString.call(Array));     // [object Function]
        console.log(Object.prototype.toString.call(String));    // [object Function]
        console.log(Object.prototype.toString.call(Number));    // [object Function]
        console.log(Object.prototype.toString.call(Date));      // [object Function]
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 对象在隐式转换时,调用 toString()方法
    <script>
        var obj = {};
        console.log(obj + '222');  // [object Object]222
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    (3) Object.prototype.valueOf()
    (4) Object.prototype.toLocaleString()
    • 转化为本地n的字符串
    <script>
        var date = new Date();
    
        console.log(date);  // Sun Nov 12 2017 16:57:57 GMT+0800 (CST)
        console.log(date.toLocaleString()); // 2017/11/12 下午4:57:57
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    (5) 对象.hasOwnProperty("属性名") 判断该属性是不是对象本身提供的,返回布尔值
    <script>
        var Fn = function () {
            this.name = 'zhangxin'
        }
    
        Fn.prototype = {
            age: 18
        };
    
        var obj = new Fn();
    
        var result1 = obj.hasOwnProperty('name');
        var result2 = obj.hasOwnProperty('age');
        console.log(result1);  // true
        console.log(result2); // false
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    (6) 原型对象.isPrototypeOf(对象) 判断括号中对象是否在原型对象的原型链上,返回布尔值
    <script>
        var arr = [];
    
        var result = Array.prototype.isPrototypeOf(arr);
        console.log(result);  // true
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    (7) 对象.properyIsEnumerable(属性名) 属性是否是对象自身的 且 可枚举(遍历)

    六、原型链

    1. 概念
    • 任何一个对象都有原型对象, 原型对象也是对象, 所以, 原型对象也有原型对象。 这样一直往上, 就形成了一条原型对象的链式结构, 我们把这个链式结构称为: 原型链。

    • 各个对象之间:通过 proto 连接起来,形成原型链

    2. 常见的原型链
    obj对象的原型链:obj  ---> Object.prototype  --->  null  【最短的原型链】
    
    arr数组的原型链:arr ---> Array.prototype  --->  Object.prototype  --->  null
    
    fn函数的原型链:fn ---> Function.prototype ---> Object.prototype ---> null
    
    str字符串的原型链:str ---> String.prototype ---> Object.prototype ---> null
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    3. Objet.prototype = null;所以 Objet.prototype是原型链结构的最上层,即万物皆对象
    定义一个对象,它的原型链 就确定下来了,不会再变
    定义一个函数,它的作用域链 就确定下来了,不会再变
    4. 原型链分析
    • 对象( null除外) 在被创建的那一刻,原型就定下来了, 即: 对象.__proto__ ; 即使改变构造函数.prototype的指向,也不会改变已创建好对象的原型链

    • 已创建好的对象,若想改变它的原型链,设置构造函数.prototype的指向 不管用;需要设置对象.__proto__ 指向

    • in 运算符 判断的是:属性是否在 对象的原型链上

    5. 完整原型链

    5. 属性搜索原则 沿着 原型链 进行搜索
    • 读取: 属性延原型链,一级一级向上找,一直查找到 Object.prototype 对象;属性找不到undefined;方法找不到,找不到的话报错

    • 实例对象 可以直接访问 原型对象的所有属性和方法,因为对象继承 自 原型对象。

    6. 类比 变量搜索原则
    • 读取: 变量延作用域链查找声明,一级一级向外找,首先在当前作用域找声明,若没有就到n-1级链查找,直到找到0级链(全局变量);找不到 就报错,因为未声明的变量

    七、JS面向对象编程 —> 【原型继承】

    1. 基于原型链重新理解 原型继承:(实例对象 继承自 原型对象的方法/属性)
    • 任何对象都有一条原型链存在,所谓的原型继承就是通过任何手段,改变原型链的层次结构(即:构造函数.prototype 的指向),对象通过访问原型链中的属性或者方法,从而实现继承。

    • 应用了:实例对象可以直接访问原型对象中的属性、方法

    2. 面向对象编程, 最佳实践:
    • 将对象的大部分属性:放到构造函数中

    • 将对象的所有方法、公共属性:放到原形对象中

    • 构造函数中属性复用,原型对象中方法继承

    • 通过 new 构造函数 创建的对象,实例对象 继承自原型对象上的属性 / 方法

    3. 理解面向对象编程
    • 面向对象编程是根据功能,将代码拆解为一个个独立的功能体;

    • 独立的功能体 即 模块,模块化编程,降低了耦合度;较少全局污染;

    • 一般情况下一个单独个体封装在一个JS文件中,JS文件中值暴露出一个构造函数

    • 引入JS文件,模块外部,需要这个功能体时,new 构造函数 即可

    (function(window) {
    
        var Bird = function(options) {
            this.name = options.name;
            this.age = options.age;
        };
    
        Bird.prototype = {
            constructor: Bird,
            action() {
                console.log(this.name);
                console.log(age);
            }
        };
    
        window.Bird = Bird;
    })(window);
    
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    八、instanceof — 被检测对象是否在 构造函数的原型链上

    • 语法:被检测对象 instanceof 构造函数 返回布尔值

    • 可类比:原型对象.isPrototypeOf(对象) 判断括号中对象是否在原型对象的原型链上,返回布尔值

    • 作用:

    • 检测 对象是否在构造函数的原型链上
    • 检测 数组
  • 规律:

    • 创建对象后:修改 构造函数.prototype的值, 检测表达式 返回 false
    • 创建对象后:不修改 构造函数.prototype的值, 检测表达式 返回 true
  • 任何对象 instanceof Object 值都是 true

  • <script>
        var Person = function () {}
    
        var a = new Person();
        Person.prototype = {};
    
        console.log(a instanceof Person);  // false
        console.log(Person.prototype.isPrototypeOf(a));   // false
        // 此时:a的原型链: a --- {} --- Object.prototype --- null
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    九、in — 判断 属性是否在对象的原型链上

    <script>
        var Fn = function () {
            this.name = 'zhang';
        }
    
        Fn.prototype.age = 19;
    
        var obj = new Fn();
    
        console.log('name' in obj);     // true
        console.log('age' in obj);      // true
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 任何一个未声明的变量,都在 window的原型链上
    console.log('a' in window); // true
     
     
    • 1

    十、delete — 删除 对象上的属性

    <script>
        var obj = {
            name: 'zhangxi',
            age: 18
        };
    
        delete obj.age;
    
        console.log(obj);  // {name: 'zhangxi'}
    </script>
     
     
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    十、静态成员 、 实例成员

    成员:属性 和 方法
    私有/静态成员
    • 由构造函数直接能够访问到的,跟构造函数相关的属性和方法。
    共有/实例成员
    • 由实例对象直接访问到的,与实例对象向关联的属性和方法。
    最佳实践
    • 如果静态成员、实例成员中有一个功能相似的方法,将逻辑代码放到静态成员中,实例成员只需调用静态成员的方法即可使用!
    • $ 或 jQuery,在jQuery库中可以被看作是 构造函数,其后跟的方法,静态成员!

    • $() 这个方法的返回值就是:jQuery对象(jQuery的实例对象),其后跟的方法,实例成员!

    each 方法由两种使用方式:
    $('div').each(function(index,value) {});   实例成员
    $.each(arr,function(index,value) {});     静态成员 $.ajax()
     
     
    • 1
    • 2
    • 3

    十一、易混知识点

    1. Function 是JS中的一等公民,自生;在原型链中即作为对象,又作为函数
    2. Function: Function创造 Object 和 function
    3. 构造函数的类型:function;【特殊】:Math 是对象,不是构造函数,其类型object
    4. 构造函数的原型的类型:object;【特殊】:Function.prototype 的类型为function
    5. 引用类型的 类型:object;【特殊】:function fn() {} 的类型为function
    5. null 不是对象,但位于原型链的最顶层; 通常用 null 来代表一个空对象
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值