面向对象编程

前面学习的JavaScript的内容,属于初学JavaScript必经之路,为了更有效率的编写代码,我们必须理解JavaScript面向对象的精髓。

什么是对象

老师用了一句话:万物皆对象。

  • 对象是对单个事物的抽象。
  • 对象是一个容器,封装了属性和方法。属性-对象的状态。方法:对象的行为
  • 数据集或功能集
  • ECMAScript-262把对象定义为:无序属性的集合,其属性可以包含基本值,对象或者函数。

什么是面向对象

简而言之,把相关数据和方法组织为一个整体来看待,从更高层次来进行系统建模,更贴近事物的自然运行模式。网上看到一句话觉得很逗(你个土豪,你们全家都是土豪)。
面向对象有三大要素:封装,继承,多态

  • 封装:不管你昨天做了什么,别人都不知道,除非你自己告诉他们
  • 继承:冰冻三尺非一日之寒,想想那些富几代就明白了吧!
  • 多态:就算双胞胎也不可能完全一模一样。即使都是从父亲那里继承来的,也会有些差别。
    面向对象不是面向过程的替代,而是面向过程的封装。

优点:灵活,代码可复用,高度模块化。容易维护和开发。更适合多人合作的大型软件项目。

面向对象的设计思想

  1. 抽象出class(构造函数)
  2. 根据class(构造函数)创建instance(实例)
  3. 指挥instance得到结果

创建对象的几种方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        // 创建对象的几种方式
        //new Object方法
        // new Object()
        // var person=new Object();
        // person.name="Bob";
        // person.age="18";
        // person.sayName=function(){
        //     console.log(this.name);
        // };
        // person.sayName();

        //对象字面量化简方式
        // var person1={
        //     name:"bob",
        //     age:"18",
        //     sayName:function(){
        //         console.log(this.name);
        //     }
        // };
        // var person2 = {
        //         name: "May",
        //         age: "16",
        //         sayName: function () {
        //             console.log(this.name);
        //         }
        //     };
        // person1.sayName();
        // person2.sayName();

        //工厂函数
        // function createPerson(name,age){
        //     //添加一个新对象
        //     var person=new Object();
        //     person.name=name;
        //     person.age=age;
        //     person.sayName=function(){
        //         console.log(this.name);
        //     };
        //     //必须有返回值
        //     return person;
        // }
        // //定义一个新对象
        // var person1=createPerson("bob","18");
        // person1.sayName();

        //自定义函数
            function createPerson(name,age){
                return{
                    name:name,
                    age:age,
                    sayName:function(){
                        console.log(this.name);
                    }

                };
            }
            var person1=createPerson("May","18");
            person1.sayName();
    </script>
</body>
</html>

构造函数,实例对象,原型对象三者的关系

老师讲的那堆专业名词我真的有点晕圈,所以去浏览了一下百度百科

  • 构造函数:一种特殊的方法,主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与new运算符一起使用。
  • 实例对象:多数语言中,实例化一个对象就是为对象开辟一个内存空间,或者不声明,直接使用new构造函数名,建立一个临时对象。
  • 原型对象:每创建一个函数,该函数都会有一个自带的prototype属性,该属性指向一个对象,该对象称之为原型对象。JS中一切继承都是用原型对象实现的!

原型对象上默认有一个constructor属性,指向相关联的构造函数。通过调用构造函数产生的实例对象,拥有一个内部属性_proto_,指向了原型对象。实例对象能够访问原型对象上的所有属性和方法。
故此:所有构造函数都有一个原型对象,原型对象上包含一个指向构造函数的指针,而实例对象内部有一个指向原型的指针。实例可以通过内部指针访问原型对象,原型对象可以通过constructor找到构造函数。
三者关系

静态成员和实例成员

  • 使用构造函数创建对象时,可以给构造函数和创建的实例对象添加属性和方法,这些属性和方法称为成员。
  • 实例成员:在构造函数内部添加给this的成员,属于实例对象的成员,在创建后,必须由对象调用
  • 静态成员:添加给构造函数自身的成员,只能使用构造函数调用,不能使用生成的实例对象调用。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        //自定义构造函数
        function createPerson(name,age){
            //实例成员,添加在函数内部
            this.name=name;
            this.age=age;
            this.sayName=function(){
                console.log(this.name);
            };
        }
        //直接给构造函数添加成员
        createPerson.version="1.0";
        // //生成对象实例
        // var person1=new createPerson("bob","18");
        // //调用实例成员
        // person1.sayName();

        //调用静态成员
        console.log(createPerson.version);



    </script>
</body>
</html>

构造函数的问题(浪费内存)

解决方法:使用原型对象可以更好的解决浪费内存的问题。根据前面说明的三者关系,将所有对象实例需要共享的属性和方法直接定义在prototype对象上。

<script>
        //将多个公共函数封装到一个对象
        var fnc={
            sayName:function(){
                console.log(this.name);
            },
            sayAge:function(){
                console.log(this.age);
            }
        };
        function person(name,age){
            this.name=name;
            this.age=age;
            this.sayAge=fnc.sayAge;
            this.sayName=fnc.sayName;
        }
        //生成实例对象
        var person1=new person("Bob","13");
        var person2= new person("May", "18");
    </script>

原型链

在JavaScript中,每一个函数都有一个原型,函数被实例化后,实例对象可以通过prototype属性访问原型,实现继承机制。
下面附上一张图,用来理解原型在JavaScript对象系统中的位置和关系

在这里插入图片描述Object和Function是两种不同类型的构造函数,利用new运算符可以创建不同类型的实例对象。实例对象,类,Object和Function之间的关系如图所示:
在这里插入图片描述
使用点语法,可以通过function.prototype访问和操作原型对象。
示例:下面为函数M定义原型

<script>
        function M(name){
            //构造函数
            this.name=name;//声明私有属性
        }
        M.prototype.name="Bob";
        //实例化对象
        var person1=new M("May");
        M.prototype.name=person1.name //设置原型属性为私有属性
        console.log(M.prototype.name);//输出May
    </script>

原型对象也可能有原型,并从中继承属性和方法。一层层类推,这种关系称之为原型链。
原型链查找
下面来分析一下原型链的查找过程

  • 搜索首先从本身开始,即P1实例对象
  • 如果在实例对象中找到了具有给定名字的属性,则返回该属性的值。
  • 如果没有找到,则继续搜索指针指向的原型对象,在原型对象中查找该属性。
  • 如果在原型对象中找到了该属性,则返回属性值,否则返回undefined。

实例对象读写原型对象成员

读取:

  • 现在自己身上查找,找到即返回
  • 自己身上找不到,则沿着原型链向上寻找,找到即返回。
  • 如果一直到原型链末端还没有找到,返回undefined。

值类型成员写入(P1.name=“Bob”)

  • 当实例想要重置原型对象中的某个普通数据成员时,会把该成员添加到自己身上。
  • 也就是说该行为实际上会屏蔽掉对原型对象成员的访问

复杂类型成员修改

  • 先在自己身上找,如果找到则直接修改,
  • 否则,继续向上寻找,找到则修改
  • 如果一直在末端找不到,则报错(P1.undefined.xx=xx)

原型对象使用建议

在定义构造函数时,可以根据成员的功能不同,分别进行设置

  • 私有成员:放到构造函数中
  • 共享成员:放到原型对象中
  • 如果重置了prototype,记得修正constructor的指向。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值