面向对象

面向对象(ECMAScript)

ECMAScript有两种开发模式:

  • 函数化
  • 面向对象(OOP)
  • ECMAScript没有对象概念
  • 面向对象的三个特征
    • 封装:封装以前写好的方法
    • 继承:继承一个对象的属性或方法
    • 多态
  • 对象是由属性和方法组成的:
    • 属性对应变量
    • 方法对应函数

面向对象的创建方法

字面量创建

适用于单个对象

var obj={
            "name":"王甜甜",
            "age":18,
            "sex":"女",
            "habby":function(){
                console.log('学习!');
            }
        }
        console.log(obj.name);
        obj.habby();

缺点:复用率低,如果要创建多个对象,会代码冗余

实例创建

使用new Object创建一个实例对象

var obj1=new Object();
        obj1.name='朱一龙';
        obj1.sex='男'
        obj1.work=function(){
            console.log(this.name,'是一名普通演员。');//这里面的this代表对象本身
        }
        console.log(obj1.name);
        obj1.work();    

缺点:复用率低,如果要创建多个对象,会代码冗余

工厂模式创建

其实就是函数封装的效果,需要有返回值

 function createObj(name,sex){
            var obj=new Object();
            obj.name=name;
            obj.sex=sex;
            obj.id=function(){
                console.log('姓名:',this.name,'性别:',this.sex);
            }
            //局部变量,需要返回值
            return obj;
        }    
        var obj1=createObj('李峥','男');
        var obj3=createObj('旺财','公');
        console.log(obj1);
        console.log(typeof obj1);//object
        console.log(obj3);
        console.log(typeof obj3);//object

可以看出,工厂模式创建的确解决了重复实例化的问题,但是还有一个问题,就是识别问题,很明显,‘李峥’和‘旺财’并不是同一个类型,一个是人,一个是狗,但是返回的结果都是object

构造函数创建

目的就是解决工厂无法识别的类型

  • 构造函数创建对象,是使用最多的创建对象的方式,也是将所有的操作都封装起来在函数中,但是又和工厂模式创建又有些不同
  • 构造函数的特点(要求)
    • 首字母最好大写
    • 没有明显的创建对象
    • 直接将属性和方法都赋给this对象
    • 必须使用new运算符
<script>
        function Preson(name,sex){
            //这里不用实例创建对象,直接就可以通过this添加属性和方法
            this.name=name;
            this.sex=sex;//这里的this指向的是window
            this.id=function(){
                console.log('姓名:',this.name,'性别:',this.sex);
                //这里面的this指向的就是这个对象,是因为this在这里起了作业
            }
        }
        var obj1=new Preson('朱一龙','男')
        console.log(obj1);   
        console.log(typeof obj1);   
        var obj2=new Preson('狗剩','母')
        console.log(obj2);    
        console.log(typeof obj2);    
    </script>

new在这里面起到了什么作用:

  • 1.隐式创建了对象
  • 2.改变了this的指向
  • 3.隐式返回,不需要返回值

每有一个实例化对象,就要把原型分配一次,然后存储在不同的地方,所以即使他们的值相同,也不是一样的。构造函数的缺点也在这里,就是多个实例化对象,就要多次分配原型,会增加内存

function Stydent(name,sex){
            this.name=name;
            this.sex=sex;
            this.id=function(){
                console.log('确认身份,是学生')
            }
        }
        var stu1=new Stydent('张三','17');
        var stu2=new Stydent('王五','17');
        stu1.id();
        stu2.id();
        console.log(stu1.id()  == stu2.id());//true 两者输出的值是一样的
        console.log(stu1.id == stu2.id);//false 对象不同,存储位置不同,
原型创建

**原型–prototype:**每一个函数都有原型,所有方法都放在原型中

**_ _ proto _ _:**是实例化对象中的一个属性,指向原型对象

<script>
        function Preson(){
            // 使用原型添加属性
            Preson.prototype.name='黄金';
            Preson.prototype.sex='女';
            // 使用原型添加方法
            Preson.prototype.id=function(){
                console.log('123');
            }
        }    
        var per1=new Preson();
        var per2=new Preson();
        console.log(per1.name);
        console.log(per2.name);
        per1.id();
        per2.id();
        console.log(per1.id == per2.id);//true
        //因为通过原型创建的,对象的方法和属性都是公用的
    </script>

通过原型创建的对象,对象的方法和属性都是共用的,只会存储一次,因此可以解决浪费问题

原型也有缺点:原型创建不能传参,属性值都是固定的

混合模式创建

用构造函数+原型混合使用的方式构造对象

<script>
        function Preson(name,sex){
            this.name=name;
            this.sex=sex
        }
        Preson.prototype.id=function(){
            console.log('确认学生身份');
        }
        var per1=new Preson('暑假','nv');
        console.log(per1.name);
        per1.id();
        var per2=new Preson('寒假','nan');
        console.log(per2.sex);
        per2.id();
        console.log(per1.id == per2.id);
        // 混合模式创建就是构造+原型
    </script>

构造函数中放一直变化的属性和方法,原型中存储共享的属性和方法

命名空间

防止命名冲突,匿名函数自执行

  • 匿名函数自执行
(function(){alert('自执行')})();

call&apply

两者的作用都是用来改变this的指向的

**区别:**传参方式不同

<div id="b"></div>
<script>
        var obj1={
            "name":"欧水",
            "fun":function(){
                console.log(this.name);
            }
        }    
        var obj2={
            "name":"欧恩",
            "fun":function(){
                console.log(this.name);
            }
        }    
        obj1.fun();//欧水
        obj2.fun();//欧恩
        obj1.fun.call(obj2);//欧恩
        obj1.fun.apply(obj1);//欧水
        function ff(){
            console.log(this);
        }
        ff();
        ff.call(document.body);
        ff.apply(document.getElementById('b'));
        function ff2(a,b){
            console.log(a,b)
        }
        ff2(2,4);
        ff2.call(document.getElementById('b'),10,20)
        ff2.apply(document.getElementById('b'),[10,20])
</script>

面向对象的继承

  • 继承是指子类继承父类的属性和方法
原型链继承
  • 就是将父亲的实例对象赋值给子类的原型对象
  • 就是子类的原型继承了父类
  • Son.prototype= new Parent(‘张三’,123);
<script>
        // 父类
        function Parent(name,age){
            this.name=name;
            this.age=age;
            this.arr=[1,2,3];
        }
        Parent.prototype.fun=function(){
            console.log(this.name,this.age)
        }
        // 子类
        function Son(){}
        // Son.prototype= new Parent();
        // var son1=new Son('123',123);
        // console.log(son1.name)//undefined
        //子类不可以传参
        Son.prototype= new Parent('张三',123);
        var son1=new Son();
        console.log(son1.name)   
        console.log(son1.arr);
        son1.arr.push(4);
        console.log(son1.arr);
        var son2=new Son();
        console.log(son2.arr);
        son1.fun(); 
    </script>

原型链继承的弊端

  • 子类不能传参
  • 如果继承了引用数据类型的,一改所有的、总的就会改,另一个子类继承父类,引用数据类型的数据就是改过的数据
对象冒充继承
  • 继承属性
  • 继承父类的构造函数
  • 继承不了父类的prototype上的属性和方法
  • 可以传参
  • 继承的引用数据类型,改变他的数据,中的数据不会变,不会影响另一个子类继承
  • Parent.call(this,name,age);
<script>
        // 父类
        function Parent(name, age) {
            this.name = name;
            this.age = age;
            this.arr = [1, 2, 3];
        }
        Parent.prototype.fun = function () {
            console.log(this.name, this.age)
        }
        // 子类
        function Son(name,age) {
            Parent.call(this,name,age);
        }
        var son1=new Son('申卡',123);
        console.log(son1.name);
        console.log(son1.arr);
        son1.arr.push(5,5);
        console.log(son1.arr);
        var son2=new Son();
        console.log(son2.arr);
        // son1.fun()    //报错
    </script>

混合继承
  • 对象冒充+原型链
  • 既可以传参,也会继承父类的prototype的属性和方法
 // 父类
        function Parent(name, age) {
            this.name = name;
            this.age = age;
            this.arr = [1, 2, 3];
        }
        Parent.prototype.fun = function () {
            console.log(this.name, this.age)
        }
        // 子类
        function Son(name, age) {
            Parent.call(this, name, age);
        }
        Son.prototype=new Parent();
        var son1 = new Son('申卡', 123);
        console.log(son1.name);
        console.log(son1.arr);
        son1.arr.push(5, 5);
        console.log(son1.arr);
        var son2 = new Son();
        console.log(son2.arr);
        son1.fun()
    </script>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值