美文网首页
JavaScript 原型对象

JavaScript 原型对象

作者: 公子无礼 | 来源:发表于2017-06-16 15:36 被阅读0次

    JavaScript是一种基于对象的语言,可以说万物皆对象。
      特别说明:基于对象也好,面向对象也好实际上都是以对象的概念来编写程序,从本质上并无区别。
      JavaScript没有类这个概念,它继承机制是基于原型,产生原型链的模式,而不是其他语言的类。因此要理解JavaScript的继承机制,需要更深入了解原型对象的概念。

    对象
      JavaScript中,对象是有区别的,分为普通对象和函数对象,Object、Function是JS自带的函数对象,function定义方式本质上还是new Function方式。(函数对象都是通过Function来实例化的)

            <script type="text/javascript">
                function f1(){};
                var f2 = function(){};
                var f3 = new Function('str', 'console.log(str)');
                var o3 = new f1();
                var o1 = {};
                var o2 = new Object();
                
                console.log(typeof Object);//function
                console.log(typeof Function);//function
                console.log(typeof o1);//object
                console.log(typeof o2);//object
                console.log(typeof o3);//object
                console.log(typeof f1);//function
                console.log(typeof f2);//function
                console.log(typeof f3);//function
            </script>
    

    在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 new Function()创建的。

    对象继承
      Brendan Eich参考C++和Java,做了简化设计,将new命令引入到JavaScript中,new后面跟对象的构造函数,用来创建对象,缺点:无法共享方法和属性。

    比如,在DOG对象的构造函数中,设置一个实例对象的共有属性species。(函数也是一个对象)
    function DOG(name) {
      this.name = name;
      this.species = '犬科';
    };
    用上面**函数对象**生成两个实例对象
    var dogA = new DOG('大毛');
    var dogB = new DOG('二毛');
    
    这两个对象species属性是独立的,修改其中一个,不会影响到另一个。
    dogA.species = '猫科';
    alert(dogB.species);//犬科
    每个实例对象都有自己的属性和方法的副本,这不仅无法做到资源共享,也极大的资源浪费。
    

    Brendan Eich决定为构造函数设置一个prototype属性。这个属性包含一个对象,所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就在构造函数里面。实例对象一旦创建,将自动引用prototype对象的属性和方法(也就是__proto__)。也就是说,实例对象的属性和方法,分成两种,一种是本地的,另一种是引用的。

    species属性放在prototype对象里,是两个实例对象共享的。只要修改了prototype对象,就会同时影响两个实例对象。
    DOG.prototype.species = '猫科';
    alert(dogA.species);//猫科 (dogA的__proto__指向DOG.prototype)
    alert(dogB.species);//猫科

    由于所有实例对象共享一个prototype对象,那么从外界看起来,prototype对象就好像是实例对象的原型,而实例对象则好像"继承"了prototype对象一样。

    原型prototype
      在JavaScript中,每当定义一个对象(函数)时候,对象都会包含一些预定的属性。其中函数对象的一个属性就是原型对象prototype(原型对象还有constructor属性(指向构造函数对象))。普通对象没有prototype,但是有__proto__属性。(比如实例化、字面量的对象)(指向其原型链)

    原型对象其实就是普通对象(Function.prototype除外,它是函数对象,但它很特殊,他没有prototype属性(前面说道函数对象都有prototype属性))。
    function f1(){};
    console.log(f1.prototype);//f1{}  (f1{}表示普通对象)
    console.log(typeof f1.prototype);//object
    console.log(typeof Function.prototype);//function,这个特殊
    console.log(typeof Object.prototype);//object
    console.log(typeof Function.prototype.prototype);//undefined
    打印关于f1函数对象的相关信息
    

    原型链
      JS在创建对象(不论普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它 的 函数对象的原型对象prototype。
      (ps:函数对象来自Function对象,字面量对象来自Object对象,实例对象来自创建它的函数对象-->等等类似)

    var person = function(name) {
        this.name = name;
    };
    person.prototype.getName = function() {
        return this.name;
    }
    var gz = new person('gongzi');
    gz.getName();//gongzi
    

    以上面的例子为例:

    console.log(gz.__proto__ === person.prototype) //true
    
    同样,person.prototype对象也有__proto__属性,它指向创建它的函数对象(Object)的prototype
    console.log(person.prototype.__proto__ === Object.prototype) //true
    
    继续,Object.prototype对象也有__proto__属性,但它比较特殊,为null
    console.log(Object.prototype.__proto__) //null
    
    我们把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。
    
    如图.png
    function Fruits(name) {
        this.name = name;
    }
    Fruits.prototype.colour = 'red';
    Object.prototype.taste = '甜';
    var fruits = new Fruits('苹果');
    console.log(fruits);//打印实例对象(普通对象)
    
    var Game = {
        name:'王者荣耀'
    };
    Object.prototype.type = '竞技';
    console.log(Game);//打印字面量对象(普通对象)
    
    console.log(Fruits.__proto__);//打印 创建它 的 函数对象 的原型对象,结果function () {}
    console.log(Fruits.constructor);//可以打印出构造函数对象Function//Fruits.__proto__.constructor一样
    Function对象作为一个函数,就会有prototype属性,该属性将对应”function () {}”对象。
    alert(Fruits.__proto__ === Function.prototype);//true
    
    前面有提到,原型对象属于普通对象。Function.prototype是个例外,它是原型对象,却又是函数对象,作为一个函数对象,它又没有prototype属性。
    
    打印实例对象.png 打印字面量对象.png

    constructor属性
      constructor 属性返回对创建此对象的函数的引用
      prototype对象有一个construction属性,默认指向prototype对象所在的构造函数。
      由于construction属性定义在prototype对象上面,意味着可以被所有实例对象继承。
      constructor属性的作用,是分辨原型对象到底属于哪个构造函数。

    总结
    1.原型和原型链是js实现继承的一种模式。
    2.原型链的形成真正的是靠proto而非prototype。

    访问原型对象的方法
    获取实例对象的原型对象,有三种方法:
    1.obj.construction.prototype或者C.prototype用于引用new C()创建的对象的原型对象
    2.Object.getPrototypeOf(obj):是获取obj对象的原型对象的标准方法。
    3.obj.proto:是获取obj对象的原型对象的非标准方法,每个对象都有的属性,可以在不支持Object.getPrototypeOf方法时作为权宜之计,proto是非安全的。
      上面三种方法第一种和第三种都不是很可靠。最新的ES6标准规定,proto属性只有浏览器才需要部署,其他环境可以不部署,obj.construction.prototype在手动改变原型对象时,可能会失效。

    扩展

    1.Object.__proto__ === Function.prototype//true
    2.Function.__proto__ === Function.prototype//true
    3. Function.prototype.__proto__ === Object.prototype//true
    
    1.Object是函数对象,是通过new Funciton()创建,所以Object.__proto__指向Function.prototype。
    
    2.Function也是对象函数,也是通过new Function()创建,所以Function.__proto__指向Function.prototype。
    
    3.Function.prototype是个函数对象,理论上其__proto__应该指向Functuin.prototype,就是它自己,自己指向自己,没有意义。函数对象也是对象,给它设定根指向Object.prototype,Object.prototype.__proto__ === null,保证原型链能够正常结束。
    

    Object.create()
      创建一个具有指定原型且可选择性地包含指定属性的对象。
    Object.create(prototype, descriptors)
      这种创建对象的方式与上面所说略有差异,如果要查找原型链,按照原型对象的类型分析就可以。
      是使用第一个参数作为它们的原型。
    prototype
      必需。要用作原型的对象。可以为 null,不继承任何对象。
    descriptors
      可选。包含一个或多个属性描述符的 JavaScript 对象。
      “数据属性”是可获取且可设置值的属性。 数据属性描述符包含 value 特性,以及 writable、enumerable 和 configurable 特性。
    使用方法可以参考网络上的这两篇,或自己百度,没时间细说了。
    javascript一种新的对象创建方式-Object.create()
    前端开发者进阶之ECMAScript新特性【一】--Object.create

    参考文献:
    Javascript继承机制的设计思想
    JavaScript原型及原型链详解
    JS原型、原型链深入理解

    实在不懂就就就.............这样记住吧
      JS中所有函数的原型都是Function.prototype,所有对象原型链的终点指向Object.prototype

    相关文章

      网友评论

          本文标题:JavaScript 原型对象

          本文链接:https://www.haomeiwen.com/subject/plceqxtx.html