理解JavaScript中的面向对象

理解JavaScript中的面向对象

1、工厂模式:用函数来封装,以特定接口创建对象的细节

  1. 解决了创建多个相似对象的问题,
  2. 多用于创建多个含有相同属性,和方法的对象,避免代码的重复编写;
  3. 没有解决对象识别的问题(即怎么知道一个对象的类型)(它的 instanceof 只能是Object)
   function creatPerson(name,age,job) {
        var o = new Object();
        o.name= name;
        o.age= age;
        o.job= job;
        o.sayName = function(){
            alert(this.name);
        };
        return o;
    }
    var p1 = creatPerson("hh",23,"worker");
    var p2 = creatPerson("xx",26,"worker1");
    p1.__proto__===p2.__proto__===Object.prototype;

2、构造函数模式:

缺点:每个方法都在每个实例上重新创建了一例子中p1.sayName!=p2.sayName。

    function Person(name,age,job){
        this.age = age;
        this.name = name;
        this.job = job;
        this.sayName = function(){
            alert(this.name)
        }
        //this.sayName = sayName;   //解决方式
    }
    var p1 = new Person("hh",23,"worker");
    var p2 = new Person("xx",26,"worker1");
        
        //function sayName(){alert(this.name)}  //解决方式


    new的执行:
        {
            var obj ={};
            obj.__proto__ = Person.prototype;
            Person.call(obj);
            return obj
        }
    p1 instanceof Person //true;
    p2 instanceof Person //true;
    p1 instanceof Object //true;
    p2 instanceof Object //true;
    这样是得p1和p2实例有了特定的类型, Person;


3、 原型模式

  1. 优点:他省略了构造函数初始化参数这个环节,原型中所有属性都被很多实例共享,共享对函数非常合适,基本属性也还行
    通过在实例上添加同名属性,可隐藏原型中的对应属性值;
  2. 缺点: 他的共享属性,对于包含引用类型值的属性 如果实例重新赋值没什么影响,和基本类型一样,如果是操作修改 就有些问题了,会使得所有实例获取到的该属性都被修改, 所以也不单独使用
    function Person(){}
    Person.prototype={
        constructor:Person,
        name:"ss",
        friends:["s1","s2"],
        sayName:function(){alert(this.name)}
    }
    var p1= new Person();
    var p2= new Person();
    p1.name = "p1"
    console.log(p1.name) //p1
    console.log(p2.name) //ss
    p1.friends.push("s3");
    console.log(p1.friends) //["s1","s2","s3"]
    console.log(p2.friends) //["s1","s2","s3"]

继承
1、组合继承:(常用继承模式)

  1. 这样可以使得实例分别拥有各自的属性(包括引用类型的,实例间互补影响),又可以使用相同的方法;
  2. 缺陷: 无论什么情况下,都会调用两次父类的构造函数
    function Father(){
        this.name ="ss";
        this.friends=[1,2,3,4]
    }
    function Son(){
        Father.call(this);
    }
    Son.prototype = new Father(); // Son 原型获得Father上的属性,name和friends


    var son1 = new Son(); // 此时调用Son构造函数为son1 实例上添加了属性(name和friends), 这些属性就屏蔽了原型中的同名属性;
    // 调用两次Father构造函数的结果就是有两组属性,一组在实例上,一组在原型上;


2、寄生组合式:(理想的继承实现方式)

  1. 解决组合继承中的缺陷,生成两组属性,只在实例上生成原型;
  2. 通过构造函数来继承属性,通过原型链的混成形式来继承方法(就是给子类原型,指定一个父类的副本即可)
    function inherit(son,father){

        var prototype = object(father.prototype); 
            // 上句话,创建父类原型的副本,prototype.__proto__ = Father.prototype;
            // prototype 继承constructor prototype.constructor 取的是原型链上,原型的Father.prototype.constructor, 为 Father();即:prototype.constructor == prototype.__proto__.constructor  // true
            // prototype.hasOwnPrototyoe("constructor") //false
        

        prototype.constructor = son; // 弥补重写原型造成的默认属性的修改;
            //此时是给prototype 添加了constructor 属性,赋值为son, 屏蔽了原型上的constructor属性
            // prototype.hasOwnPrototype("constructor") // true
            // prototype.constructor = son;
            // prototype.__proto__.constructor = father
        son.prototype  = prototype;
            // 给子类原型赋值为父类原型的副本;
    }

    //使用:
    function Father(){
        this.name="11";
        this.age=12;
    }
    Father.prototype.sayName=function(){
        alert(this.name);
    }
    function Son(){
        Father.call(this);
        this.age=23;
    }
    inherit(Son,Father);
    Son.prototype.sayAge=function(){
        alert(this.age)
    }


参考阅读

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值