zoukankan      html  css  js  c++  java
  • 构造函数,原型对象,实例对象

    一、构造函数,原型对象,实例对象

    1.1 基本概念

    1、对象:

    • 属性和方法的集合,即变量和函数的封装。
    • 调用构造函数产生的实例对象, 每个对象都有一个__proto__属性,指向这个对象的构造函数的原型对象

    2、构造器函数:

    • 用于创建对象的函数,通过new关键字生成对象。
    • 函数名一般首字母大写的。
    • 每创建一个函数, 该函数都会自动带有一个prototype属性。该属性是一个指针,指向一个对象,该对象称之为原型对象(后期我们可以使用这个原型对象帮助我们在js中实现继承)

    3、原型对象:

    • 默认有一个属性constructor,该属性也是一个指针,指向其相关联的构造函数
    • 原型对象其实就是普通对象(但 Function.prototype 除外,它是函数对象,但它很特殊,它没有prototype属性(前面说到函数对象都有prototype属性))
    function Person(){};
    console.log(Person.prototype) //Person{}
    
    console.log(typeof Person.prototype) //Object
    console.log(typeof Function.prototype) // Function,这个特殊
    console.log(typeof Object.prototype) // Object
    console.log(typeof Function.prototype.prototype) //undefined
    

    1.2 总结

    三者的关系是

    • 每个构造函数都有一个指向原型对象的指针,
    • 原型对象上包含着一个指向构造函数的指针,
    • 而实例都包含着一个指向原型对象的内部指针

    1.3 举例

    function People(){
        this.type='人'
    }
    People.prototype.showType=function(){
        alert(this.type);
    }
    
    var person=new People();
    //调用原型对象上面的方法
    person.showType();//最后结果弹框弹出人
    
    
    • 构造函数People(), People.prototype指向原型对象,其自带属性construtor又指回了People,即People.prototype.constructor==People.
    • 实例对象person由于其内部指针__proto__指向了原型对象,所以可以访问原型对象上的showType方法。

    person1.__proto__ == Person.prototype
    
    Person.prototype.constructor = Person
    
    person1.constructor == Person
    

    二 原型链

    举例1

    在第一部分我们说到,所有的实例都有一个内部指针指向他的原型对象,并且可以访问到原型对象上的所有属性和方法。

    • person实例对象的__proto__属性,指向了People的prototype属性,即原型对象,可以访问People原型对象上的所有属性和方法
    • 如果People原型对象变成了某一个类的实例aaa,这个实例又会指向一个新的原型对象AAA,那么person此时能访问aaa的实例属性和AAA原型对象上的所有属性和方法了。
    • 同理新的原型对象AAA碰巧又是另外一个对象的实例bbb,这个对象实例指向原型对象BBB,那么person就能访问bbb的实例属性和BBB原型上的属性和方法了。

    举例2

    function People(){
        this.type='人'
    }
    People.prototype.showType=function(){
        alert(this.type);
    }
    
    function Woman(){
        this.sex='女';
        this.age=34;
    }
    Woman.prototype = new People();
    
    var w=new Woman();
    console.log('大家好,我的种类是:'+w.type+",我的年龄是:"+w.age+",我的性别是:"+w.sex);
    //输出结果:
    //大家好,我的种类是:人,我的年龄是:34,我的性格是:女
    //w.type是People上面定义的type
    

    解释一下以上代码.

    首先先定义了People构造函数,通过new People()得到实例,会包含一个实例对象type和一个原型属性showType。

    另外定义一个Woman构造函数,然后情况发生变化,本来构造函数Woman的prototype会执行Woman的原型对象,但是我们这里稍有改变,将Woman构造函数的prototype指向了People实例对象覆盖了Woman的原型对象。

    当Woman的实例对象woman去访问type属性时,js首先在woman实例属性中查找,发现没有定义,接着去Woman的原型对象上找,woman的原型对象这里已经被我们改成了People实例,那就是去People实例上去找。先找People的实例属性,发现没有type,最后去People的原型对象上去找,终于找到了。这个查找就是这么一级一级的往上查找。

    举例3

    function People(){
        this.type='人'
    }
    People.prototype.showType=function(){
        alert(this.type);
    }
    function Woman(){
        this.sex='女';
        this.age=34;
        this.type='女生';//如果这里定义了type属性,就不会层级查找,最后在People找到该属性
    }
    Woman.prototype=new People();
    var w=new Woman();
    console.log('大家好,我的种类是:'+w.type+",我的年龄是:"+w.age+",我的性别是:"+w.sex);
    //输出结果:
    //大家好,我的种类是:女生,我的年龄是:34,我的性格是:女
    

    这就说明,我们可以通过原型链的方式,实现 Woman继承 People 的所有属性和方法。

    总结
    就是当重写了Woman.prototype指向的原型对象后,实例的内部指针也发生了改变,指向了新的原型对象,然后就能实现类与类之间的继承了

    练习

    练习1

    构造函数Person 实例对象person1

    // 题目
    1 : person1.__proto__ 是什么?
    2 : Person.__proto__ 是什么?
    3 : Person.prototype.__proto__ 是什么?
    4 : Object.__proto__ 是什么?
    5 : Object.prototype.__proto__ 是什么?
    
    // 答案
    1 : person1.__proto__ === Person.prototype (person1的构造函数Person)
    
    2 : Person.__proto__ === Function.prototpye (Person的构造函数Function)
    
    3 : Person.prototype.__proto__  === Object.prototype (Person.protyotype是一个普通对象,因为一个普通对象的构造函数都是Object)
    
    4 : Object.__proto__ === Function.prototpye (Object的构造函数Function)
    
    5 : Object.prototype.__proto__ === null (Object.prototype 也有__proto__属性,但是它比较特殊,是null,null处于原型链的顶端。)
    

    原型链的形成是真正是靠__proto__ 而非prototype

    练习2

    var FunctionExample = function () {}
    
    Object.prototype.a = function() {}
    
    Function.prototype.b = function() {}
    
    var f = new FunctionExample();
    
    这时候f能否访问到a和b ??
    
    
    // 所有普通对象都源于这个Object.prototype对象,只要是对象,都能通过原型链访问到a
    
    f.__proto__ === FunctionExample.prototype;
    
    FunctionExample.prototype.__proto__ === Object.prototype;
    
    // 取b我们可通过 f.constructor.b就能访问到b,因为 f.constructor == FunctionExample
    
    f.constructor === FunctionExample;
    
    FunctionExample.__proto__ === Function.prototype;
    
    console.log(f) // FunctionExample {}
    console.log(f.constructor)  // [Function: FunctionExample]
    console.log(FunctionExample.prototype) // FunctionExample {}, 其实可以理解成FunctionExample.prototype就是一个实例
    console.log(FunctionExample.prototype.constructor) // [Function: FunctionExample]
    console.log(f.__proto__) // FunctionExample {} , 可以这么理解,实例的proto指向它的构造函数的原型对象,也就是f.__proto__ == FunctionExample.prototype
    console.log(f.constructor.b) // Function,因为f.constructor指向 FunctionExample, 而 FunctionExample.prototype相当是Function的一个实例,所以在Function.prototype上有个b函数,FunctionExample照样可以访问的到
    console.log(f.constructor.prototype.__proto__); // { a: [Function] } 可以访问到a函数,因为f.constructor.prototype其实就是等于FunctionExample {},而每个对象都有个__proto__属性,Function.prototype.__proto__ == Object.prototype,所以也能访问到a方法
    

    练习3

    function SuperType() {
      this.colors = ['red', 'yellow']
    }
    
    function SubType() {
    
    }
    // 继承了SuperType
    SubType.prototype = new SuperType();
    
    var instance1 = new SubType() // intance.constructor = SuperType
    instance1.colors.push('black')
    console.log(instance1.colors) // ['red', 'yellow', 'black']
    
    var instance2 = new SubType()
    console.log(instance2.colors) // ['red', 'yellow', 'black']
    

    理解一下原型和原型链

    // 为什么instance1.constructor = SuperType ?
    // 为什么 SubType.prototype.constructor = SuperType ?
    
    console.log(instance1.constructor) // SuperType
    console.log(SubType.prototype.constructor) // SuperType
    
    console.log(instance1.__proto__ == SubType.prototype) // true
    console.log(SubType.prototype.__proto__ == SuperType.prototype) // true
    
    console.log(SubType.__proto__ == SuperType.prototype) // false
    console.log(SubType.__proto__ == Function.prototype) // true
    
    console.log(SuperType.prototype.constructor == SuperType) // true
    console.log(SuperType.__proto__ == Function.prototype) // true
    console.log(SuperType.prototype.__proto__ == Object.prototype) // true
    

    练习4

    function SuperType() {
      this.colors = ['red', 'yellow']
    }
    
    function SubType() {
      // 继承了SuperType
      SuperType.call(this);
    }
    
    var instance1 = new SubType()
    instance1.colors.push('black')
    console.log(instance1.colors) // ['red', 'yellow', 'black']
    
    var instance2 = new SubType()
    console.log(instance2.colors) // ['red', 'yellow']
    

    思考一哈?

    console.log(instance1.constructor) // SubType
    console.log(SubType.prototype.constructor) // SubType
    console.log(SubType.prototype.__proto__) // {}
    
    console.log(instance1.__proto__ == SubType.prototype) // true
    console.log(SubType.prototype.__proto__ == SuperType.prototype) // false
    console.log(SubType.prototype.__proto__ == Object.prototype) // true
    
    console.log(SubType.__proto__ == SuperType.prototype) // false
    console.log(SubType.__proto__ == Function.prototype) // true
    
    console.log(SuperType.prototype.constructor == SuperType) // true
    console.log(SuperType.__proto__ == Function.prototype) // true
    console.log(SuperType.prototype.__proto__ == Object.prototype) // true
    
  • 相关阅读:
    jdbc连接池中c3p0的配置文件的详解以及在在java中如何使用
    idea导入myeclipes项目、运行项目
    java中身份证号和的银行卡的深度校验
    springBoot的搭建使用记录
    java分模块项目在idea中使用maven打包失败(ps:maven常用到的命令)
    js获取当前页面相关信息
    mybatis使用中的记录
    tomcat服务的启动与隐藏启动(win)
    cmd命令关闭占用程序的端口
    ping端口是否开放(windows,macos,linux)
  • 原文地址:https://www.cnblogs.com/qiqi715/p/10431095.html
Copyright © 2011-2022 走看看