JS第十六节 面向对象3

本文详细介绍了JavaScript中对象属性的设置,包括defineProperty方法的使用,数据属性的配置,以及对象的访问属性get和set。此外,还探讨了Vue的MVVM原理实现,并讲解了JavaScript的继承方式,如原型链继承、构造函数继承、组合继承等,以及它们的优缺点。最后,文章提到了原型式继承、寄生式继承和寄生组合式继承,展示了JavaScript继承的多种实现策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.对象属性设置 -- defineProperty
1.Object.getOwnPropertyDescriptor() 获取对象属性

    var Person={
        name:"zs",
    }
    var des=Object.getOwnPropertyDescriptor(Person,"name")
    console.log(des.value) //zs
    console.log(des.configurable) //true
    console.log(des.writable) //true
    console.log(des.enumerable) //true   在对象里面直接定义都为true

2.****对象的数据属性
    value           属性的属性值
    configurable    能否删除属性的值
    writable        能否修改属性的值
    enumerable      能否遍历(枚举)属性的值

(0)var Person={}
    Object.defineProperty(Person,"name",{value:"zs"})
    var des=Object.getOwnPropertyDescriptor(Person,"name")
    console.log(des.value) //zs
    console.log(des.configurable) //false
    console.log(des.writable) //false
    console.log(des.enumerable) //false    对象为空时都为false

(1)writable  能否修改属性的值
    Object.defineProperty(Person,"name",{value:"zs",writable:false})
    console.log(Person.name) //zs
    Person.name="ls" //修改失败
    console.log(Person.name) //zs

(2)enumerable  能否遍历(枚举)属性的值
    Object.defineProperty(Person,"name",{value:"zs",enumerable:false})
    var v1=Object.keys(Person)
    console.log(v1)

(3)configurable  能否删除属性的值
    Object.defineProperty(Person,"age",{value:"21",configurable:true})
    console.log(Person.age) //21
    delete Person.age
    console.log(Person.age) //undefined

3.对象的访问属性
    get: 在读取属性时调用的函数
    set: 在写入属性时调用的函数

    var Person={"_name":"zs",age:23}
    var v1=""
    Object.defineProperty(Person,"name",
                        {get:function(){
                            // console.log("get...")
                            return this._name
                        },
                        set:function(val){
                            console.log("set...",val)
                            if(val=="ls"){
                                v1="He is "+val
                                this.age=55
                            }
                        }
                    })
    // console.log(Person.name)
    Person.name="ls"
    console.log(v1);
    console.log(Person.age);

4.vue MVVM 原理实现
    <input type="text" id="unamea">
    显示:<span id="show"></span>
    <script>
        var myobj={}
        Object.defineProperty(myobj,'uname',{
            set:function(val){
                document.getElementById("show").innerText=val },
            get:function(){
                // return myobj.uname }
        })
        document.getElementById("unamea").addEventListener("keyup",function(event){
            esrc=event.target
            myobj.uname=esrc.value
        })


二.继承
1.约定
    (1)
    function Person(){
        var name="zs"           //私有的基本属性
        var friends=["ls","ww"] //私有的引用属性
        function f1(){}         //私有的函数
    }
    (2)
    function Person(){
        this.name="zs"           //实例的基本属性
        this.friends=["ls","ww"] //实例有的引用属性
        this.f1=function(){}     //实例的函数
    }
    (3)
    function Person(){}
    Person.prototype.name="zs"          //原型的基本属性
    Person.prototype.friends=["ls","ww"]//原型有的引用属性
    Person.prototype.f1=function(){}    //原型的函数

2.原型链继承

    function Animal(){
        this.name="animal"
        this.frineds=[]
        this.say=function(){console.log("say...");}
    }
    Animal.prototype.eat=function(){console.log("eat...");}
    function Cat(){        //构造函数
        this.name="cat00"
    }
    //继承
    Cat.prototype=new Animal()
    Cat.prototype.name="cat"        //原型
    //实例
    var c1=new Cat()
    c1.name="jfcat"
    console.log(c1.name)
    c1.say()
    c1.frineds.push("jfcat01")
    console.log(c1.frineds);

    var c2=new Cat()
    console.log(c2.name)
    console.log(c2.frineds);
总结:
核心:Cat.prototype=new Animal()拿父类实例充当子类原型对象
原型链的查找顺序:实例-->实例对象的构造函数-->实例对象原型-->父类构造原型-->父类对象原型
优点:简单易于实现
缺点:原型的引用类型属性是所有实例共享的
     创建子实例时无法向父类构造函数传参


3.原型链原理

    function Animal(){}
    Animal.prototype.name="animal"
    Animal.prototype.say=function(){console.log("hello")}
    console.log(Animal);
    console.log(typeof Animal.prototype)
    console.log(Animal.prototype.constructor)

(1)每个函数都有一个显示的"prototype"属性,该属性指向原型对象
(2)原型对象中的"constructor"属性,指向函数本身
    function Cat(){}
    Cat.prototype=new Animal()
    // console.log(Cat)
    // console.log(Cat.prototype)
    // console.log(Cat.__proto__)
    var c1=new Cat()
    var c2=new Cat() 

    console.log(c1.__proto__==Cat.prototype)//true
    console.log(Cat.prototype.__proto__==Animal.prototype);//true
    console.log(Animal.prototype.__proto__==Object.prototype);//true
    console.log(Object.prototype.__proto__==null);//true

(3)new创建的对象,没有prototype属性        
    function Animal(){}
    Animal.prototype.name="animal"
    Animal.prototype.say=function(){console.log("hello")}
    function Cat(){}
    Cat.prototype=new Animal()
    // console.log(Cat)
    // console.log(Cat.prototype)   
    // console.log(Cat._proto_)
    var c1=new Cat()
    var c2=new Cat()
    console.log(c1.__proto__==Cat.prototype );  //true
    Cat.prototype.__proto__==Animal.prototype //true
    Animal.prototype.__proto__==prototype //true
    console.log( c1.__proto__.__proto__==Animal.prototype); //true

    Object.prototype.__proto__==null  //原型链结束  true

(4)每个对象都有一个"__proto__"内部隐藏属性,
    指向它所对应的原型对象(chrome--[[]] fireFox--<>)
(5)原型链利用原型上一个引用类型继承另一个引用类型的方法,
    原型链正是基于"__proto__"才得以形成
(6)console.log(Object.prototype.__proto__==null);//true
    原型链结束 指向空的时候


4.(借用)构造函数继承      Animal.call(this.arg)
    function Animal(val){
        this.name=val
        this.friends=["a","b"]
        this.say=function(){console.log("say...")}
    }
    function Person(arg){
        Animal.call(this.arg) //继承
    }
    var p1=new Person("zs")
    var p2=new Person("ls")
    console.log(p1.name);
    console.log(p2.name);
    p1.friends.push("ww")
    console.log(p1.friends);
    console.log(p2.friends);
    console.log(p1.say==p2.say); //false

总结:
核心:借用父类的构造函数,来增强子类的实例,完全没有使用原型
优点:1.解决了子类实例共享父类引用实例的问题
     2.创建子类时,可以向父类构造函数传参
缺点:无法实现函数的复用,每一个子类实例都有一个新的function函数,消耗内存


5.组合继承(构造函数+原型链)
    function Animal(val){
        this.name=val
        this.friends=["a","b"]
    }
    Animal.prototype.say=function(){console.log("say...")}

    function Person(arg){
        Animal.call(this,arg) //继承父类基本属性和引用属性并保留了传参的优点
    }
    Person.prototype=new Animal()//继承父类函数,实现函数复用

    var p1=new Person("zs")
    console.log(p1.name) //zs
    console.log(p1.friends);
    p1.friends.push=("ww")
    console.log(p1.friends);
    var p2=new Person("ls")
    console.log(p2.name)
    console.log(p2.friends)
    console.log(p1.say==p2.say); //true

总结:
    核心:把实例函数都放在原型对象上,以实现函数复用,并保留构造函数的优点
    优点:1.不存在引用属性共享问题
         2.可以传参
         3.函数可以复用
    缺点:因为父类构造函数被调用了两次,生成了两份,浪费内存


6.原型式继承
    function Beget(obj){ // 生孩子函数
        function F(){}
        F.prototype=obj
        return new F()
    }
    function Animal(){
        this.name="animal"
        this.friends=["ls","ww"]
    }
    var Person=new Animal()
    var p1=Beget(Person)
    // var Person={name:"zs",friends:["ls","ww"]}

    var p1=Beget(Person)
    console.log(p1.name) // animal
    p1.name="zs"
    console.log(p1.name); // zs
    p1.friends.push("sl") 
    console.log(p1.friends) // ['ls', 'ww', 'sl']
    var p2=Beget(Person)
    console.log(p2.name) // animal
    console.log(p2.friends); // ['ls', 'ww', 'sl']

核心:用生孩子函数得到一个"纯洁"的(没有实例属性)的新对象

7.寄生式继承
    function Beget(obj){ // 生孩子函数
        function F(){}
        F.prototype=obj
        return new F()
    }
    function Animal(){
        this.name="animal"
        this.friends=["ls","ww"]
    }
    function getSubObject(obj){
        var clone=Beget(obj)
        clone.age=23
        return clone
    }
    var Person=getSubObject(new Animal())
    console.log(Person.name) // animal
    console.log(Person.age) // 23


8.寄生组合式继承 ---最佳
    function Beget(obj){ // 生孩子函数
        function F(){}
        F.prototype=obj
        return new F()
    }
    function Animal(){
        this.name="animal"
        this.friends=["ls","ww"]
    }
    Animal.prototype.say=function(){console.log("say...")}

    function Person(){
        Animal.call(this)
    }
    var P=Beget(Animal.prototype)
    P.constructor==Person
    Person.prototype=P

    var p1=new Person()
    console.log(p1.name)
    console.log(p1.friends)

优点:完美
缺点:无

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值