zoukankan      html  css  js  c++  java
  • JavaScript原型详解

    1,前言

    下面是2008年Github创建以来,各种编程语言的排名情况

    排名其中JavaScript自2015年之后就盘踞第一名,成为github上被使用最多的语言,早期,JS的使用还主要集中于浏览器中,但是随着node.js进军服务器开发和React Native逐渐向移动端渗透,一个属于JS的全栈时代就要来临了。而且JS界还流传一句名言:“所有能用JS开发的应用程序,最终都会用JS来开发”。我就问你怕不怕?

    好了,说了这么多,我并不是想说JS为世界上最好的语言(显然PHP才是,对吧?←_←),也不是觉得JS会替代谁,我只是觉得,JavaScript将会是一个大家(不止web端)都应该了解和学习的语言工具。

    2,面对对象(OOP)

    2.1 实现思路

    面对对象是大家都很熟悉的程序设计思想,是对真实世界的抽象,目前主要OOP语言用来实现面对对象的基础是类,通过类的封装,继承来映射真实世界。包括Java,C#,甚至是python等都通过类的设计来实现面对对象。但是细想起来也会觉得有问题,因为真实世界其实没有类这种概念,只有一个个不同的对象,真实世界中,继承关系发生在对象和对象之间,而不是类。就比如孩子是对象,父母也是对象,孩子(对象)继承自父母(对象)

    JS也是面对对象的编程语言,只不过它实现面对对象的思路是基于原型(prototype),而不是类。这种思路也叫对象关联(Object Link Other Object),即在对象上直接映射那种真实世界的关系(如继承)。

    2.2 原型概念

    相关的概念其实我研究了好几天,除开原型概念本身,与之联系的对象的产生,构造函数,proto,prototype的区别,为什么对象没有prototype这个指向原型的属性,而是使用proto来指向原型?

    好,我们先来谈谈原型这个概念。JS中一切皆对象,而每个对象都有一个原型(Object除外),这个原型,大概就像Java中的父类,所以,基本上你可以认为原型就是这个对象的父对象,即每一个对象(Object除外)内部都保存了它自己的父对象,这个父对象就是原型。一般创建的对象如果没有特别指定原型,那么它的原型就是Object(这就很类似Java中所有的类默认继承自Object类)。

    2.3 对象创建

    在JS中,对象创建的方法有很多种,最常见的如下:

    //第一种,手动创建
    var a={'name':'lala'};   
    
    //第二种,构造函数
    function A(){
        this.name='lala';
    }
    var a=new A();
    
    //第三种,class (ES6标准写法)
    
    class A{
        constructor(){
            super();
            this.name='lala';
        }
    }
    var a=new A()
    //其实后面两种方法本质上是一种写法

    这三种写法创建的对象的原型(父对象)都是Object,需要提到的是,ES6通过引入class ,extends等关键字,以一种语法糖的形式把构造函数包装成类的概念,更便于大家理解。是希望开发者不再花精力去关注原型以及原型链,也充分说明原型的设计意图和类是一样的。

    2.3 查看对象原型

    当对象被创建之后,查看它们的原型的方法不止一种,以前一般使用对象的proto属性,ES6推出后,推荐用Object.getPrototypeOf()方法来获取对象的原型

    function A(){
        this.name='lala';
    }
    var a=new A();
    console.log(a.__proto__)  
    //输出:Object {}
    
    //推荐使用这种方式获取对象的原型
    console.log(Object.getPrototypeOf(a))  
    //输出:Object {}

    无论对象是如何创建的,默认原型都是Object,在这里需要提及的比较特殊的一点就是,通过构造函数来创建对象,函数A本身也是一个对象,而A有两个指向表示原型的属性,分别是proto和prototype,而且两个属性并不相同

    function A(){
        this.name='lala';
    }
    var a=new A();
    console.log(A.prototype)  
    //输出:Object {}
    
    console.log(A.__proto__)  
    //输出:function () {}
    console.log(Object.getPrototypeOf(A))
    //输出:function () {}

    函数的的prototype属性只有在当作构造函数创建的时候,把自身的prototype属性值赋给对象的原型。而实际上,作为函数本身,它的原型应该是function对象,然后function对象的原型才是Object。

    总之,建议使用ES6推荐的查看原型和设置原型的方法。

    2.4 原型的用法

    其实原型和类的继承的用法是一致的:当你想用某个对象的属性时,将当前对象的原型指向该对象,你就拥有了该对象的使用权了。

    function A(){
        this.name='world ';
    }
    function B(){
        this.bb="hello"
        }
    var a=new A();
    var b=new B();
    
    Object.setPrototypeOf(a,b);
    //将b设置为a的原型,此处有一个问题,即a的constructor也指向了B构造函数,可能需要纠正
    a.constructor=A;
    console.log(a.bb)
    //输出 hello

    (增补)

    如果使用ES6来做的话则简单许多,甚至不涉及到prototype这个属性

    class B{
         constructor(){
    
            this.bb='hello'
         }
    }
    class A  extends B{
         constructor(){
            super()
            this.name='world'
         }
    }
    
    var a=new A();
    console.log(a.bb+" "+a.name);
    //输出hello world
    
    
    console.log(typeof(A))
    //输出  "function"

    怎么样?是不是已经完全看不到原型的影子了?活脱脱就是类继承,但是你也看得到实际上类A 的类型是function,所以说,本质上class在JS中是一种语法糖,JS继承的本质依然是原型,不过,ES6引入class,extends 来掩盖原型的概念也是一个很友好的举动,对于长期学习那些类继承为基础的面对对象编程语言的程序员而言。

    我的建议是,尽可能理解原型,尽可能用class这种语法糖。


    2.5 原型链

    这个概念其实也变得比较简单,可以类比类的继承链条,即每个对象的原型往上追溯,一直到Object为止,这组成了一个链条,将其中的对象串联起来,当查找当前对象的属性时,如果没找到,就会沿着这个链条去查找,一直到Object,如果还没发现,就会报undefined。那么也就意味着你的原型链不能太长,否则会出现效率问题。

    3,总结

    • 对于原型概念的理解
      • 类比类的继承,对象的原型可以理解为对象的父对象
    • 原型的运用
      • 尽可能使用ES6的标准,使用class,extends,Object.getPrototype(),Object.setPrototype()等等
    • 需要注意的点
      • 原型继承链条不要太长
      • 指定原型时,注意constructor也会改变。

    4,后记(增补)

    还有人觉得我的分析很抽象,所以,我再总结一下,如果要一句话理解JS中的原型是什么,那就是,对象的原型就指的对象的父对象。每个对象都有父对象,父对象本身也有父对象(爷对象?)。而原型链呢,很像过去家谱的概念,可以从你往上追溯你父亲,到爷爷,到太爷爷一直到头,这就形成了一个链条,如果其中每个人都比作一个对象,那么这个链条就是原型链。

  • 相关阅读:
    「日常训练」Single-use Stones (CFR476D2D)
    「日常训练」Greedy Arkady (CFR476D2C)
    「Haskell 学习」二 类型和函数(上)
    「学习记录」《数值分析》第二章计算实习题(Python语言)
    「日常训练」Alena And The Heater (CFR466D2D)
    Dubbo 消费者
    Dubbo 暴露服务
    Rpc
    git fail to push some refs....
    Spring Cloud (6)config 客户端配置 与GitHub通信
  • 原文地址:https://www.cnblogs.com/libin-1/p/5944740.html
Copyright © 2011-2022 走看看