【JavaScript】19_对象的结构,原型对象与修改原型

9、对象的结构

对象中存储属性的区域实际有两个:

  1. 对象自身

    • 直接通过对象所添加的属性,位于对象自身中
    • 在类中通过 x = y 的形式添加的属性,位于对象自身中
  2. 原型对象(prototype)

    • 对象中还有一些内容,会存储到其他的对象里(原型对象)
    • 在对象中会有一个属性用来存储原型对象,这个属性叫做__proto__
    • 原型对象也负责为对象存储属性,
      当我们访问对象中的属性时,会优先访问对象自身的属性,
      对象自身不包含该属性时,才会去原型对象中寻找
    • 会添加到原型对象中的情况:
      1. 在类中通过xxx(){}方式添加的方法,位于原型中
      2. 主动向原型中添加的属性或方法
    <script>
            class Person {
                name = "孙悟空"
                age = 18

                // constructor(){
                //     this.gender = "男"
                // }

                sayHello() {
                    console.log("Hello,我是", this.name)
                }
            }

            const p = new Person()
            // p.address = "花果山"
            // p.sayHello = "hello"

            console.log(p.sayHello)
    </script>

11、原型对象

访问一个对象的原型对象
对象.proto
Object.getPrototypeOf(对象)

原型对象中的数据:

  1. 对象中的数据(属性、方法等)
  2. constructor (对象的构造函数)

注意:
原型对象也有原型,这样就构成了一条原型链,根据对象的复杂程度不同,原型链的长度也不同
p对象的原型链:p对象 --> 原型 --> 原型 --> null
obj对象的原型链:obj对象 --> 原型 --> null

原型链:

  • 读取对象属性时,会优先对象自身属性,
    如果对象中有,则使用,没有则去对象的原型中寻找
    如果原型中有,则使用,没有则去原型的原型中寻找
    直到找到Object对象的原型(Object的原型没有原型(为null))
    如果依然没有找到,则返回undefined

  • 作用域链,是找变量的链,找不到会报错

  • 原型链,是找属性的链,找不到会返回undefined

    <script>
            class Person {
                name = "孙悟空"
                age = 18

                sayHello() {
                    console.log("Hello,我是", this.name)
                }
            }
            const p = new Person()
        const obj = {} // obj.__proto__
    </script>

​ 所有的同类型对象它们的原型对象都是同一个,

​ 也就意味着,同类型对象的原型链是一样的

​ 原型的作用:

​ 原型就相当于是一个公共的区域,可以被所有该类实例访问,

​ 可以将该类实例中,所有的公共属性(方法)统一存储到原型中

​ 这样我们只需要创建一个属性,即可被所有实例访问

​ JS中继承就是通过原型来实现的,

​ 当继承时,子类的原型就是一个父类的实例

​ 在对象中有些值是对象独有的,像属性(name,age,gender)每个对象都应该有自己值,

​ 但是有些值对于每个对象来说都是一样的,像各种方法,对于一样的值没必要重复的创建

​ 尝试:

​ 函数的原型链是什么样子的?

​ Object的原型链是什么样子的?

    <script>
        class Person {
            name = '孙悟空'
            age = 18

            sayHello() {
                console.log('Hello ,我是',this.name)
            }
        }

        class Dog {}

        const p = new Person()
        const p2 = new Person()

        p.sayHello = 'hello'

        const d = new Dog()
        const d2 = new Dog()

        console.log(p)
        console.log(p2)
        console.log(p.__proto__ === p2.__proto__)


        class Animal {

        }

        class Cat extends Animal{

        }

        class TomCat extends Cat {

        }

        // TomCat --> cat --> Animal实例 --> object --> Object原型 --> null

        // cat --> Animal实例 --> object --> Object原型 --> null
        // p对象 --> object --> Object原型 --> null
        const cat = new Cat()

        console.log(cat.__proto__.__proto__.__proto__.__proto__)
    </script>

12、修改原型

大部分情况下,我们是不需要修改原型对象
注意:
千万不要通过类的实例去修改原型

1. 通过一个对象影响所有同类对象,这么做不合适
2. 修改原型先得创建实例,麻烦
3. 危险

处理通过__proto__能访问对象的原型外,
还可以通过类的prototype属性,来访问实例的原型
修改原型时,最好通过通过类去修改
好处:

  1. 一修改就是修改所有实例的原型
  2. 无需创建实例即可完成对类的修改

原则:

  1. 原型尽量不要手动改
  2. 要改也不要通过实例对象去改
  3. 通过 类.prototype 属性去修改
  4. 最好不要直接给prototype去赋值
    <script>
        class Person {
            name = '孙悟空'
            age = 18

            sayHello(){
                console.log('Hello,我是')
            }
        }

        Person.prototype.fly = () => {
            console.log('我在飞!')
        } 

        class Dog {

        }

        const p = new Person ()
        const p2 = new Person ()

        // 通过对象修改原型,向原型中添加方法,修改后所有同类实例都能访问该方法 不要这么做!
        // p.__proto__.run = () => {
        //     console.log('我在跑~')
        // }

        // p.__proto__ = new Dog() // 直接为对象赋值了一个新的原型 不要这么做!


        // console.log(p)
        // console.log(p2)

        // p.run()
        // p2.run()

        // console.log(Person.prototype) // 访问Person实例的原型对象
</script>

13、instanceof和hasOwn

instanceof 用来检查一个对象是否是一个类的实例

  • instanceof检查的是对象的原型链上是否有该类实例

​ 只要原型链上有该类实例,就会返回true

  • dog -> Animal的实例 -> Object实例 -> Object原型

  • Object是所有对象的原型,所以任何和对象和Object进行instanceof运算都会返回true

in

  • 使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true

对象.hasOwnProperty(属性名) (不推荐使用)

  • 用来检查一个对象的自身是否含有某个属性

Object.hasOwn(对象, 属性名)

  • 用来检查一个对象的自身是否含有某个属性
    <script>
        class Animal {}
        class Dog extends Animal {}
        const dog = new Dog()

        // console.log(dog instanceof Dog) // true
        // console.log(dog instanceof Animal) // true
        // console.log(dog instanceof Object) // true

        const obj = new Object()

        // console.log(obj.__proto__)
        // console.log(Object.prototype)

        // dog.__proto__ / Dog.prototype

        class Person {
            name = "孙悟空"
            age = 18

            sayHello() {
                console.log("Hello,我是", this.name)
            }
        }

        const p = new Person()
        // console.log("sayHello" in p)
        // console.log(p.hasOwnProperty("sayHello"))
        // console.log(p.__proto__.__proto__.hasOwnProperty("hasOwnProperty"))

        console.log(Object.hasOwn(p, "sayHello"))
    </script>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

名之以父

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值