JS面向对象编程

一、面向对象概念

1、ECMAScript有两种开发模型:函数式编程(过程化)、面对对象编程。

  • 类:类是对象的模型模板,可是理解为种类,例如定义People来表示人,这时People表示人的类型;
  • 实例:实例式根据类创建的对象。
  • 但是ECMAScript没有类的概念,所以它的对象也与基本类的语言中的对象有所不同。

2、对象的组成:

  • 属性——对象的具体特点描述(姓名、年龄);
  • 方法——对象的行为,动态等。

3、对象的基本特征:

  • 封装:简单来说就是把一些方法封装到类中,便于使用。这个函数封装差不多,主要是不想外界作用域直接可以访问到。
  • 继承:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展添加。
  • 多态:允许将子类类型的指针赋值给父类类型的指针。

二、面对对象的创建

  1. 字面量方式创建。就是以json格式创建,适用于创建单个对象。
// 1、字面量创建对象
        var obj = {
            name : 'yy',
            age : 18
        };
  1. 实例化创建对象。使用new Object()创建一个实例对象,然后给这个对象增加属性和方法。
// 2、实例化对象创建
        var obj = new Object();
        obj.name = 'yy';
        obj.age = 18;
        obj.sya = function () {
            console.log('加油!');
        }
  1. 工厂模式创建对象。就是函数封装,将创建对象,及对象的属性和方法都封装在函数中,最后返回这个创建的对象。
// 3、工厂模式创建对象
        function createObj() {
            var obj = new Object();
            obj.name = 'yy';
            obj.age = 18;
            obj.sya = function () {
                console.log('加油!');
            }
            return obj;     // 返回创建的对象
        }
  1. 构造函数创建对象。这个是使用最多的创建对象方法,也是将所有操作都封装在函数中,但是与工厂模式有些不同,可以明确区分对象的种类。最后创建实例的时候要用new关键字;
    构造函数的特点:

    • 构造函数的函数名首字母要大写(约定成俗的约定,为了区分普通函数);
    • 构造函数方法没有显式的创建对象;
    • 直接将对象的属性和方法赋值给this对象;
    • 没有return语句,不需要返回对象;
    • 通过构造函数创建对象,必须使用new运算符;

    new关键字的用处:

    • 创建一个新对象;
    • 将构造函数的作用域赋值给新对象(让this指向这个对象);
    • 执行构造函数中的代码(为新对象添加属性);
    • 返回新对象;
 // 4、构造函数创建对象
        function CreateObj(name, age) {
            this.name = name;
            this.age = age;
            this.sya = function () {
                console.log('加油!');
            }
        }
        var obj = new CreateObj('yy', 18);
        console.log(obj);           // CreateObj对象
  1. 原型创建对象。 每个对象都会有自己的原型对象(prototype),是这类对象共有的方法和属性的集合。而__proto__是实例对象的一个属性,指向原型对象。原型对象需要类型名词调用,如Object.prototype。原型下面还有一个constructor的属性,它又指向构造函数。通常用来判断对象类型。
// 5.原型对象创建对象
        function CreateObj () {};
        CreateObj.prototype.name= 'yy';
        CreateObj.prototype.age = 18;
        CreateObj.prototype.say = function () {
            console.log('加油!');
        }
        var obj = new CreateObj();
        console.log(obj.name);          // yy
        console.log(obj.age);          // 18
        obj.say()                       // 加油   

需要注意的是:在原型对象定义的属性和方法都是固定的值。创建的对象不能传参。

  1. 混合模式模式创建对象(构造+原型) 这个模式就可以传参和继承原型里面的方法
// 6.混合模式模式创建对象(构造+原型)
        function CreateObj (name) {
            this.name = name;
        };
        CreateObj.prototype.say = function () {
            console.log('加油!');
        }
        var obj = new CreateObj('yy');
        console.log(obj.name);          // yy
        obj.say()                       // 加油   
  1. 动态混合模式创建对象。 一般创建对象用混合模式就够了,单数严格来说这种方式破坏了封装性,所以可以使用动态混合模式创建对象,将原型对象也写在构造函数当中。
// 7.动态混合模式创建对象
        function CreateObj(name) {
            this.name = name;
            // 判断是否有这样一个方法没有,如果没有就在原型上添加
            if (typeof (this.sya) !== 'function') {
                CreateObj.prototype.sya = function () {
                    console.log('加油');
                }
            }
        };
        var obj = new CreateObj('yy');
        console.log(obj.name);          // yy
        obj.say()                       // 加油   

三、原型的继承方式

  1. 原型链继承:是指子类继承父类的属性和方法,原型链继承就是讲父类的实例对象赋值给子类的原型对象。
 // 1.原型链继承: 通过父类的实例对象传给子类的原型对象
        function ParseArr() {       // 父类构造函数
            this.arr = [5, 4, 3, 2, 1];
        }
        // 创建一个子类构造函数
        function SonArr() {};
        // 将子类的原型继承父类
        SonArr.prototype = new ParseArr();

        // 创建一个对象obj1接受子类构造函数的属性和方法
        var obj1 = new SonArr();
        console.log(obj1.arr);   // [5,4,3,2,1]
        // 改变SonArr里面的数组顺序
        obj1.arr.sort();
        console.log(obj1.arr);   // [1,2,3,4,5]
        // 再用新对象obj2接受子类构造函数的属性和方法
        var obj2 = new SonArr();
        // 这次输出发现里面的内容是对象obj1修改过的 这就说明继承了引用类型,会一改全改,一个实例对象改变了引用类型的数据
        console.log(obj2.arr);   // [1,2,3,4,5]
  1. 对象冒充继承:继承就是想用父类的属性和方法,使用call获取apply改变this的指向,让他指向父类,就可以使用,称之为对象冒充。
// 2.对象冒充继承
        function ParseObj (name, age) {
            this.name = name;
            this.age = age;
        };

        function SonObj (name, age) {
            //  调用父类的构造函数通过call来给改变this的指向对象冒充
            ParseObj.call(this,name, age); 
            
        };

        var obj1 = new SonObj('yy',18);
        console.log(obj1.name);     // yy
  1. 组合继承(对象冒充+原型链):对象冒充继承构造函数中的内容,原型链继承原型上的属性和方法。
 // 3.组合继承
        function ParentObj (name, age) {
            this.name = name;
            this.age = age;
        }

        // 给父类原型上定义方法
        ParentObj.prototype.say = function () {
            console.log('加油');
        }
        function SonObj (name, age) {
            // 通过对象冒充继承父类
            ParentObj.call(this, name, age);
        } 
        // 在子类的原型链上继承
        SonObj.prototype = new ParentObj();
        var obj1 = new SonObj('yy',18);
        console.log(obj1.age);      // 18
        obj1.say();                 // 加油

组合继承的问题是无论什么情况下,都会调用两次父类构造函数,一次在子类创建子类原型的时候,另一次在子类构造函数内部。

  1. 寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。不必为了制定子类型的原型来调用父类的构造函数,我们所需要的无非是父类型原型的一个副本,本质上就是使用寄生式继承来继承父类型的原型,然后再将结果指定给子类型的原型。
 // 4.寄生组合式继承
        function inherits(Child, Parent) {
            var F = function () { };
            // 让F函数的原型指向父类的原型
            F.prototype = Parent.prototype;
            // 让Child的原型等于F的实例化对象
            Child.prototype = new F();
            // 在修改Child原型的constructor
            Child.prototype.constructor = Child;
        }

        // 创建父类
        function ParentObj(name, age) {
            this.name = name;
            this.age = age;
        }
        // 给父类原型上定义方法
        ParentObj.prototype.say = function () {
            console.log('加油');
        }
        // 创建子类
        function SonObj (name, age) {
            // 通过对象冒充继承父类
            ParentObj.call(this, name, age);
        } 
        // 调用函数
        inherits(SonObj, ParentObj);

        var obj = new SonObj('yy', 18);
        console.log(obj.name);      // yy
        console.log(obj.age);       // 18

四、闭包

闭包就是能够读取其他函数内部变量的函数(函数里面套函数,内部函数访问外部函数变量),在本质上,闭包是将函数内部和函数外部连接起来的桥梁。
闭包可以把变量长久的存储在内存中,每次闭包都是新的。

  function outer () {
            var a = 10;
            function inner () {
                a++;
                console.log(a);
            }
            return inner;
        }
        var inn = outer();
        console.log(inn);
        inn(); // 11
        inn(); // 12
        var inn1 = outer();
        inn1(); // 11
        inn1(); // 12
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值