【前端】JavaScript中prototype和__proto__的区别
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/prototype.html
经常有小伙伴问我关于prototype和__proto__的问题,觉得有必要写一篇博客总结归纳一下。
要想弄明白这两个概念,我们先得明白什么是类,什么是对象,什么是实例化
零、什么是类,什么是对象,什么是实例化
拥有一点点面向对象思想的小伙伴应该都知道,我们在写代码的时候,是在跟一个一个的对象打交道,我们修改对象的属性,调用对象的方法,以此来让程序为我们服务。
要创建对象,就需要有一个“类”,在Java等其他很多语言中,都用class关键字来声明类,声明了类,我们才能创建对象。
我们的对象拥有哪些属性和方法,都是在类中规定的。比如下面这段Java代码(之所以这里用Java做示例是因为Java里类的概念比较强,看不大懂的可以当成伪代码来看,不用太在意语法)
public class Animal{
public String name;
public void say(){
print("我的名字是" + this.name);
}
}
它声明了一个“动物”的类,这个类里我们规定了一个属性是这个动物的name,还规定了一个say的方法。然后我们在下面实例化两个动物类的对象
//实例化了一个动物对象
Animal dog = new Animal(); dog.name = "旺财";
dog.say(); //又实例化了一个动物对象
Animal cat = new Animal(); cat.name = "小咪";
cat.say();
我想小伙伴们应该已经能很清晰地区分什么是类,什么是对象,什么是实例化了。没错,类就是对拥有共同属性和方法的对象的一个抽象。例如我们抽象出了所有动物都有名字,也都会说话这样一个类。然后我们实例化出来的旺财和小咪这两个东东就是这个类的对象。而用类创建对象的过程就称为实例化。
在js中我们也可以很方便的声明类和实例化对象,具体可以看一下我以前的博客 http://www.cnblogs.com/shamoyuu/p/4770235.html
明白了这些,再解释这两个概念就很容易了。
一、什么是prototype
我们先来用js声明一个Animal类,再来实例化一个Animal的对象dog。
function Animal(){
this.name;
this.say = function(){
alert("我的名字是" + this.name);
}
}
var dog = new Animal();
dog.name = "旺财";
dog.say();
Animal虽然是一个类,但它也是一个对象,它具体是谁的对象我们后面再讨论。
既然它是一个对象,那它是不是会有一些属性或者方法?
没错,Animal类拥有一个属性,这个属性就是prototype对象,这个对象里有一些跟这个类相关的属性和方法。
例如,js自带的Array类的prototype属性指向的对象拥有join,push,slice等方法。
prototype就是类的一个属性,它是一个对象,它里面拥有这个类公用的属性和方法。
那它有什么用呢?请往下看。
二、什么是__proto__
__proto__跟prototype是一模一样的,但区别在于,它不属于类,而属于类的对象。
在实例化一个对象的时候,会自动为这个对象添加一个属性__proto__,它就指向它的创造类的prototype属性。
也就是说
Animal.prototype === dog.__proto__ //true
这也就是类的prototype属性的作用了,可以为所有它的实例化对象增加属性或方法。是不是特别方便?
例如我们常用的数组的join,push,slice等方法就是存在于它的创造类的prototype里,也就是在数组对象的__proto__里,这样我们在实例化Array的对象的时候,就会自动获得这些方法。
这里也有一点需要注意的,prototype和__proto__里存储的都是对象的引用,修改任何一个会影响所有的。例如
function Bird() {
this.fly = function() {
console.info("我会飞");
}
}
var pigeon = new Bird();
pigeon.__proto__.eat = function() {
console.info("我会吃");
};
var pigeon2 = new Bird();
pigeon.eat(); //我会吃
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对象的类,例如:
function foo(){
alert(123);
}
这里foo就是一个Function的实例化出来的对象。
啥?看着不像实例化对象?我们换种写法
var foo = new Function("alert(123);");
现在是不是用Function类实例化了一个对象?这是js里另外一种实例化Function对象的方法,效果和前面的是一模一样的。
那么前面说了,类都有prototype属性,所以Function类也有一个prototype属性。但是有一点不同的是,Function的prototype不能被修改。
我们来尝试一下,既然你说不能修改,我偏要改一下试试
Function.prototype.hello = "你好";
var foo = new Function();
alert(foo.hello); //"你好"
你这个骗子,我这不是明明修改成功了吗?
别急,我们来试试替换它
Function.prototype = {
x: 1
};
var foo = new Function();
alert(foo.x); //undefined
奇怪,这里竟然是undefined,不应该是1吗?那为什么上面的“修改”有效,直接替换无效呢?
我们打印Function.prototype看看
function () { [native code] }
打印出来的竟然是一个匿名函数,而不是我们前面一直说的一个对象。
这就是原因所在,虽然它是一个匿名函数,但它也是一个Function的对象,既然是对象,就可以为它添加属性和方法。这就是我们可以为它添加hello属性的原因。
但它是无法被修改的,我们不能修改它的指针地址,只可以修改指针指向的对象。
完结,散花
【前端】JavaScript中prototype和__proto__的区别的更多相关文章
- 在 JavaScript 中 prototype 和 __proto__ 有什么区别
本文主要讲三个 问题 prototype 和 proto function 和 object new 到底发生了什么 prototype 和 proto 首先我们说下在 JS 中,常常让我们感到困惑的 ...
- javascript中prototype与__proto__
1.prototype:构造函数独有的属性: __proto__:每个对象都有一个名为__proto__的属性: 注意:每个构造函数(自带与自创)都有一个prototype的属性,构造函数的proto ...
- Javascript中prototype属性详解 (存)
Javascript中prototype属性详解 在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不 ...
- (转载)详解Javascript中prototype属性(推荐)
在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...
- JavaScript中:表达式和语句的区别
JavaScript中:表达式和语句的区别 Javascript语言精粹:表达式是由运算符构成,并运算产生结果的语法结构.程序是由语句构成,语句则是由“:(分号)”分隔的句子或命令.如果在表达式后面加 ...
- javascript中prototype、constructor以及__proto__之间的三角关系
三者暧昧关系简单整理 在javascript中,prototype.constructor以及__proto__之间有着“著名”的剪不断理还乱的三角关系,楼主就着自己对它们的浅显认识,来粗略地理理以备 ...
- 彻底理解什么是原型链,prototype和__proto__的区别以及es5中的继承
再讲一遍好了( 参考https://blog.csdn.net/cc18868876837/article/details/81211729 https://blog.csdn.net/lc23742 ...
- js中prototype与__proto__区别
proto(隐式原型)与prototype(显式原型) 显式原型 explicit prototype property:每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数 ...
- 对象中prototype与__proto__与从cinstructor的作用和区别
首先先要知道prototype什么时间才会有 只有在创建函数的时候,每当函数创建的时候才会原型prototype,还有一个constructor,这个不是函数独有的,对象也有 下面就来说说对象prot ...
随机推荐
- python --- mulitprocessing(多进程)模块使用
1. 什么是进程? 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础.在早期面向进程设计的计算机结构中,进程是程序的基本执 ...
- 18_Python列表常用方法总结
''' 1.列表切片索引\截取 2.列表的增删改查 3.列表最大值\列表最小值\排序 4.列表的遍历 5.列表的嵌套 6.列表和字符串的互转 7.判断元素是否在列表中 ''' #列表使用中括号表示 元 ...
- 我的前端故事----关于前端数据&逻辑的思考
最近重构了一个项目,一个基于redux模型的react-native项目,目标是在混乱的代码中梳理出一个清晰的结构来,为了实现这个目标,首先需要对项目的结构做分层处理,将各个逻辑分离出来,这里我是基于 ...
- Django REST framework反向生成url
Django REST framework是一个基于Django的框架,REST framework又是怎么反向生成url的呢?? 在前面的例子中,知道在REST framework中有6种版本控制的 ...
- 在高并发、高负载的情况下,如何给表添加字段并设置DEFAULT值?
在高并发.高负载的情况下,如何给表添加字段并设置DEFAULT值? 在Oracle 12c之前,当Oracle表数据量上亿时,对表执行“ALTER TABLE XXX ADD COLUMN_XX VA ...
- 【视频编解码·学习笔记】7. 熵编码算法:基础知识 & 哈夫曼编码
一.熵编码概念: 熵越大越混乱 信息学中的熵: 用于度量消息的平均信息量,和信息的不确定性 越是随机的.前后不相关的信息,其熵越高 信源编码定理: 说明了香农熵越信源符号概率之间的关系 信息的熵为信源 ...
- 使用IntelliJ IDEA(PHPStorm)和xdebug在firefox、chrome中远程调试PHP
很多PHP程序员都习惯于使用echo.var_dump和exit来中断和调试web应用程序,本文主要介绍结合xdebug.IntelliJ IDEA.Firefox/chrome/IE来远程调试PHP ...
- c语言环境初始化&c语言和汇编混合编程
bootloader通常会分为两个阶段:第一阶段采用汇编语言来编写,主要是一些核心的初始化工作(内存,时钟的初始化),第二阶段使用C语言来编写,主要是它会完成一些板载硬件的初始化(串口,网口)然后其启 ...
- 第三方页面嵌入到web项目的方案 之 使用iframe嵌入
有些项目中可能会遇到这样的需求, 需要在一个项目中嵌入其他的项目的页面或者功能.并且需要这两个页面之间能够进行交互. 本文主要介绍如何实现这种第三方应用的嵌入, 主要有以下几个方向: 1.iframe ...
- 自己制作ssl证书:自己签发免费ssl证书,为nginx生成自签名ssl证书
这里说下Linux 系统怎么通过openssl命令生成 证书. 首先执行如下命令生成一个key openssl genrsa -des3 -out ssl.key 1024 然后他会要求你输入这个ke ...