zoukankan      html  css  js  c++  java
  • 【前端】JavaScript中prototype和__proto__的区别

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/prototype.html

    经常有小伙伴问我关于prototype和__proto__的问题,觉得有必要写一篇博客总结归纳一下。

    要想弄明白这两个概念,我们先得明白什么是类,什么是对象,什么是实例化

    零、什么是类,什么是对象,什么是实例化

    拥有一点点面向对象思想的小伙伴应该都知道,我们在写代码的时候,是在跟一个一个的对象打交道,我们修改对象的属性,调用对象的方法,以此来让程序为我们服务。

    要创建对象,就需要有一个“类”,在Java等其他很多语言中,都用class关键字来声明类,声明了类,我们才能创建对象。

    我们的对象拥有哪些属性和方法,都是在类中规定的。比如下面这段Java代码(之所以这里用Java做示例是因为Java里类的概念比较强,看不大懂的可以当成伪代码来看,不用太在意语法)

    1 public class Animal{
    2     public String name;
    3     
    4     public void say(){
    5         print("我的名字是" + this.name);
    6     }
    7 }

    它声明了一个“动物”的类,这个类里我们规定了一个属性是这个动物的name,还规定了一个say的方法。然后我们在下面实例化两个动物类的对象

     1 //实例化了一个动物对象
     2 Animal dog = new Animal();
     3 
     4 dog.name = "旺财";
     5 dog.say();
     6 
     7 //又实例化了一个动物对象
     8 Animal cat = new Animal();
     9 
    10 cat.name = "小咪";
    11 cat.say();

    我想小伙伴们应该已经能很清晰地区分什么是类,什么是对象,什么是实例化了。没错,类就是对拥有共同属性和方法的对象的一个抽象。例如我们抽象出了所有动物都有名字,也都会说话这样一个类。然后我们实例化出来的旺财和小咪这两个东东就是这个类的对象。而用类创建对象的过程就称为实例化

    在js中我们也可以很方便的声明类和实例化对象,具体可以看一下我以前的博客 http://www.cnblogs.com/shamoyuu/p/4770235.html

    明白了这些,再解释这两个概念就很容易了。

    一、什么是prototype

    我们先来用js声明一个Animal类,再来实例化一个Animal的对象dog。

     1 function Animal(){
     2     this.name;
     3     
     4     this.say = function(){
     5         alert("我的名字是" + this.name);
     6     }
     7 }
     8 
     9 var dog = new Animal();
    10 dog.name = "旺财";
    11 dog.say();

    Animal虽然是一个类,但它也是一个对象,它具体是谁的对象我们后面再讨论。
    既然它是一个对象,那它是不是会有一些属性或者方法?
    没错,Animal类拥有一个属性,这个属性就是prototype对象,这个对象里有一些跟这个类相关的属性和方法。
    例如,js自带的Array类的prototype属性指向的对象拥有join,push,slice等方法。
    prototype就是类的一个属性,它是一个对象,它里面拥有这个类公用的属性和方法。
    那它有什么用呢?请往下看。

    二、什么是__proto__

    __proto__跟prototype是一模一样的,但区别在于,它不属于类,而属于类的对象

    在实例化一个对象的时候,会自动为这个对象添加一个属性__proto__,它就指向它的创造类的prototype属性

    也就是说

    1 Animal.prototype === dog.__proto__  //true

    这也就是类的prototype属性的作用了,可以为所有它的实例化对象增加属性或方法。是不是特别方便?
    例如我们常用的数组的join,push,slice等方法就是存在于它的创造类的prototype里,也就是在数组对象的__proto__里,这样我们在实例化Array的对象的时候,就会自动获得这些方法。

    这里也有一点需要注意的,prototype和__proto__里存储的都是对象的引用,修改任何一个会影响所有的。例如

     1 function Bird() {
     2     this.fly = function() {
     3         console.info("我会飞");
     4     }
     5 }
     6 
     7 var pigeon = new Bird();
     8 
     9 pigeon.__proto__.eat = function() {
    10     console.info("我会吃");
    11 };
    12 
    13 var pigeon2 = new Bird();
    14 
    15 pigeon.eat(); //我会吃
    16 pigeon2.eat(); //我会吃

    这里我们实例化了一个Bird对象pigeon,给它的__proto__上添加一个方法eat,

    然后基于上面的理论,我们的Bird的prototype当然也被改变了,所以后来创建的pigeon2对象的__proto__属性也变了。

    注意:这里我们改变的只是prototype和__proto__指向对象的属性和方法,并没有改变这个引用的地址。


    好了,关于prototype和__proto__的解释就到此结束,应该是很通俗易懂的。

    三、function Animal(){...}是由谁创造的

    我们在前面讲Java类的时候说到,Java里Animal这个类其实也是Class类的一个对象。
    那么js里Animal类是不是也跟Java里一样,是某个类的一个对象呢?
    答案是肯定的,在js里,所有function都是Function类的一个对象
    Function是一个专门用来创造function对象的类,例如:

    1 function foo(){
    2     alert(123);
    3 }

    这里foo就是一个Function的实例化出来的对象。
    啥?看着不像实例化对象?我们换种写法

    1 var foo = new Function("alert(123);");

    现在是不是用Function类实例化了一个对象?这是js里另外一种实例化Function对象的方法,效果和前面的是一模一样的。

    那么前面说了,类都有prototype属性,所以Function类也有一个prototype属性。但是有一点不同的是,Function的prototype不能被修改
    我们来尝试一下,既然你说不能修改,我偏要改一下试试

    1 Function.prototype.hello = "你好";
    2 var foo = new Function();
    3 alert(foo.hello);  //"你好"

    你这个骗子,我这不是明明修改成功了吗?
    别急,我们来试试替换它

    1 Function.prototype = {
    2     x: 1
    3 };
    4 
    5 var foo = new Function();
    6 
    7 alert(foo.x);  //undefined

    奇怪,这里竟然是undefined,不应该是1吗?那为什么上面的“修改”有效,直接替换无效呢?
    我们打印Function.prototype看看

    1 function () { [native code] }

    打印出来的竟然是一个匿名函数,而不是我们前面一直说的一个对象。

    这就是原因所在,虽然它是一个匿名函数,但它也是一个Function的对象,既然是对象,就可以为它添加属性和方法。这就是我们可以为它添加hello属性的原因。

    但它是无法被修改的,我们不能修改它的指针地址,只可以修改指针指向的对象。

    完结,散花

  • 相关阅读:
    Windows下配置nginx+php(wnmp)
    nginx缓存优先级(缓存问题者必看)
    OpenResty(Nginx)+Lua+GraphicsMagick实现缩略图功能
    M3U8文件简介
    拼车旅游网站 导航
    将jsp页面内容保存到excel(转)
    queryRuner如何获得bean对象,当这个bean对象中包含其他对象的时候
    js的trim方法(转)
    二进制运算误差问题
    myeclipes如何调试web项目
  • 原文地址:https://www.cnblogs.com/shamoyuu/p/prototype.html
Copyright © 2011-2022 走看看