• javascript 面向对象学习(二)——原型与继承


    什么是原型?

    首先我们创建一个简单的空对象,再把它打印出来

    var example = {}
    console.log(example)

    结果如下:

    {
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }

     我们创建的example是个空对象,按理说应该什么属性都没有,却出现了一个__proto__属性,这个属性是从哪里来的呢?实际上,当我们调用 var example = {} 时,相当于调用 var example = new Object(),隐式地继承了 Object.prototype 的属性和方法。Object.prototype 对象是 javascript 的根对象,javascript 的每个对象都是从这个对象来的,下面我们通过构造函数的例子看一下prototype、__proto__到底是什么。

    我们来定义一个构造函数

    function Person() {}
    
    console.log(Person.prototype)

    打印出 Person 的 prototype 属性,结果如下:

    {
        constructor: ƒ Person(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }

    可以看到,这个属性包含了consturcor属性(指向自己)和__proto__属性(指向Object.prototype,即根对象。因为在js里,函数也是对象,继承自根对象)。所有的函数都有这样一个叫做prototype的属性,即原型对象,我们可以在原型对象上定义属性和方法:

    Person.prototype.name = 'Jack'
    Person.prototype.jump = function() {
        console.log(this.name + '-jump')
    }
    console.log(Person.prototype)

    这时打印出的原型对象为

    {
        name: "Jack",
        jump: ƒ (),
        constructor: ƒ doSomething(),
        __proto__: {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf(),
            propertyIsEnumerable: ƒ propertyIsEnumerable(),
            toLocaleString: ƒ toLocaleString(),
            toString: ƒ toString(),
            valueOf: ƒ valueOf()
        }
    }

     name 属性和 jump 方法被加到了这个对象上面。那么,这个原型对象有什么用呢?

    我们再用这个构造函数创建一个实例:

    function Person() {}
    Person.prototype.name = 'Jack'var jack = new Person()
    jack.sex = 'male'
    console.log(jack)

    我们在构造函数原型和实例对象上都加了属性,现在把 jack 打印出来如下:

    {
        sex: "male",
        __proto__: {
            name: "Jack",
            constructor: ƒ doSomething(),
            __proto__: {
                constructor: ƒ Object(),
                hasOwnProperty: ƒ hasOwnProperty(),
                isPrototypeOf: ƒ isPrototypeOf(),
                propertyIsEnumerable: ƒ propertyIsEnumerable(),
                toLocaleString: ƒ toLocaleString(),
                toString: ƒ toString(),
                valueOf: ƒ valueOf()
            }
        }

    可以看到,jack 有个 __proto__ 属性,这个属性跟它的构造函数 Person 的 prototype 属性内容是一样的,我们打印如下内容:

    console.log(jack.name)   // Jack

    得到的结果是 “Jack”,在jack的属性里并没有name这一项,name 是定义在Person 的 prototype 属性上的,然而我们却能从jack中访问到,这就是原型的继承作用。我们访问jack.name时,浏览器首先查找jack有没有name属性,有的话直接获取,没有的话会去jack.__proto__属性里查询,再查不到继续在jack.__proto__.proto__里找……由此形成一条链,即原型链。在这里jack.__proto__.__proto__就是Object.prototype。需要注意的是,原型继承的核心是prototype,而不是__proto__,__proto__是浏览器内部属性,只是用来访问原型对象prototype属性的。下面我们来看一下怎么让两个不相关的对象通过原型链实现继承。

    // 定义父对象
    var father = {
        name: 'Jack'
    }
    // 定义子对象的构造函数
    function Son() {}
    // 令子对象的构造函数的原型指向父对象
    Son.prototype = father
    // 创建子对象实例
    var son = new Son()
    
    console.log(son.name) // Jack

    核心代码就是标红的那句:令子对象的构造函数的原型对象指向父对象。

    总结:在javascript里,每个函数都有叫做原型对象的prototype属性,js的根对象是Object.prototype。通过构造函数创建出的实例能继承构造函数原型对象的属性和方法。

  • 相关阅读:
    获取当前时间并格式化,CTime类
    疑问:VS在调试的过程中,总是会提示正在加载picface.dll的符号,然后卡死在那
    Markup解析XML——文档,说明
    .net Core 获取当前程序路径
    Excel中的细节
    心血来潮尝试一个小项目(WinForm)
    bat文件以管理员运行
    DataGridView一些总结
    常见辅助类、方法
    向txt文件中添加或者追加文字字符串
  • 原文地址:https://www.cnblogs.com/zdd2017/p/13050643.html
Copyright © 2020-2023  润新知