javascript中的prototype和__proto__的理解
在工作中有时候会看到prototype和__proto__这两个属性,对这两个属性我一直比较蒙圈,但是我通过查阅相关资料,决定做一下总结加深自己的理解,写得不对的地方还请各位大神指出。
跟__proto__属性相关的两个方法
判断属性是存在实例对象中,还是存在原型对象中的方法
获取或遍历对象中属性的几种方法
1、prototype
每个函数都有一个prototype属性,该属性是一个指针,指向一个对象。 而这个对象的用途是包含由特定类型的所有实例共享的属性和方法。使用这个对象的好处就是可以让所有实例对象共享它所拥有的属性和方法
2、 __proto__
每个实例对象都有一个__proto__属性,用于指向构造函数的原型对象。__proto__属性是在调用构造函数创建实例对象时产生的。
- function Person(name, age, job){
- this.name = name;
- this.age = age;
- this.job = job;
- this.sayName = function(){
- console.log(this.name);
- }; // 与声明函数在逻辑上是等价的
- }
- var person1=new Person("Nicholas",29,"Software Engineer");
- console.log(person1);
- console.log(Person);
- console.log(person1.prototype);//undefined
- console.log(person1.__proto__);
- console.log(Person.prototype);
- console.log(person1.__proto__===Person.prototype);//true
输出结果如下:
总结:
1、调用构造函数创建的实例对象的prototype属性为"undefined",构造函数的prototype是一个对象。
2、__proto__属性是在调用构造函数创建实例对象时产生的。
3、调用构造函数创建的实例对象的__proto__属性指向构造函数的prototype。
4、在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。
下图展示了使用Person构造函数创建实例后各个对象之间的关系
上图展示了 Person 构造函数、 Person 的原型属性以及 Person现有的两个实例之间的关系。
3、 跟__proto__属性相关的两个方法
isPrototypeOf():虽然在所有实现中都无法访问到__proto__,但可以通过 isPrototypeOf()方法来确定对象之间是否存在这种关系。
- alert(Person.prototype.isPrototypeOf(person1)); //true
- alert(Person.prototype.isPrototypeOf(person2)); //true
Object.getPrototypeOf():在所有支持的实现中,这个方法返回__proto__的值。例如:
- alert(Object.getPrototypeOf(person1) == Person.prototype); //true
- alert(Object.getPrototypeOf(person1).name); //"Nicholas"
注意:虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。请看下面的例子:
- function Person(){
- }
- Person.prototype.name = "Nicholas";
- Person.prototype.age = 29;
- Person.prototype.job = "Software Engineer";
- Person.prototype.sayName = function(){
- alert(this.name);
- };
- var person1 = new Person();
- var person2 = new Person();
- person1.name = "Greg";
- alert(person1.name); //"Greg"―― 来自实例
- alert(person2.name); //"Nicholas"―― 来自原型
4、 判断属性是存在实例对象中,还是存在原型对象中,有以下方法
hasOwnProperty():可以检测一个属性是存在于实例中,还是存在于原型中。返回值为true表示该属性存在实例对象中,其他情况都为false。
in 操作符:无论该属性存在于实例中还是原型中。只要存在对象中,都会返回true。但是可以同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。
- var person1 = new Person();
- var person2 = new Person();
- alert(person1.hasOwnProperty("name")); //false
- alert("name" in person1); //true
- person1.name = "Greg";
- alert(person1.name); //"Greg" ―― 来自实例
- alert(person1.hasOwnProperty("name")); //true
- alert("name" in person1); //true
- alert(person2.name); //"Nicholas" ―― 来自原型
- alert(person2.hasOwnProperty("name")); //false
- alert("name" in person2); //true
- delete person1.name;
- alert(person1.name); //"Nicholas" ―― 来自原型
- alert(person1.hasOwnProperty("name")); //false
- alert("name" in person1); //true
5、 获取或遍历对象中属性的几种方法
for-in:通过for-in循环的返回的是能够被访问的、可枚举的属性,不管该属性是在实例中,还是存在原型中。
- function Person(name, age, job) {
- this.name = name;
- this.age = age;
- this.job = job;
- }
- Person.prototype={
- sayName:function(){
- return this.name;
- }
- }
- var p=new Person("李明",30,"诗人");
- for(var prop in p){
- console.log(prop);//name、age、job、sayName
- }
- console.log(Object.keys(p));//["name", "age", "job"]
- console.log(Object.keys(Person.prototype));//["sayName"]
- console.log(Object.getOwnPropertyNames(Person.prototype))
- // ["constructor", "sayName"]
Object.keys():取得实例对象上所有可枚举的属性。 Object.getOwnPropertyNames(): 获取实例对象所有属性,无论它是否可枚举。
注意:使用对象字面量来重写整个原型对象时,本质上完全重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor 属性(指向 Object 构造函数),不再指向 Person。但是可以通过在重写原型对象时指定constructor属性,使之还是指向原来的constructor。此时,尽管 instanceof 操作符还能返回正确的结果,但通过 constructor 已经无法确定对象的类型了。
object instanceof constructor:检测 constructor.prototype 是否存在于参数 object 的原型链上。
- function Person() {}
- var friend2 = new Person();
- Person.prototype = {
- //constructor : Person,
- name: "Nicholas",
- age: 29,
- job: "Software Engineer",
- sayName: function() {
- alert(this.name);
- }
- };
- var friend = new Person();
- console.log(friend2 instanceof Object); //true
- console.log(friend2 instanceof Person); //false,
- console.log(friend2.constructor == Person); //true
- console.log(friend2.constructor == Object); //false
- console.log(friend instanceof Object); //true
- console.log(friend instanceof Person); //true
- console.log(friend.constructor == Person); //false
- console.log(friend.constructor == Object); //true
由于原型的动态性,调用构造函数时会为实例添加一个指向最初原型的Prototype指针,而把原型修改为另外一个对象就等于切断了构造函数与最初原型之间的联系。看下面的例子
- function Person(){
- }
- var friend = new Person();
- Person.prototype = {
- constructor: Person,
- name : "Nicholas",
- age : 29,
- job : "Software Engineer",
- sayName : function () {
- alert(this.name);
- }
- };
- var friend2=new Person();
- friend.sayName(); //Uncaught TypeError: friend.sayName is not a function
- friend2.sayName();//Nicholas
- console.log(friend instanceof Person);//false
- console.log(friend instanceof Object);//true
- console.log(friend2 instanceof Person);//true
结果分析:这是因为friend1的prototype指向的是没重写Person.prototype之前的Person.prototype,也就是构造函数最初的原型对象。而friend2的prototype指向的是重写Person.prototype后的Person.prototype。如下图所示
6、 原型链
基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。最直观的表现就是让原型对象等于另一个类型的实例。
- function SuperType(){
- this.property = true;
- }
- SuperType.prototype.getSuperValue = function(){
- return this.property;
- };
- function SubType(){
- this.subproperty = false;
- }
- //继承了 SuperType
- SubType.prototype = new SuperType();
- SubType.prototype.getSubValue = function (){
- return this.subproperty;
- };
- var instance = new SubType();
- alert(instance.getSuperValue()); //true
SubType.prototype = new SuperType();这句代码使得原来存在于 SuperType 的实例中的所有属性和方法,现在也存在于 SubType.prototype 中。使得instance的constructor指向了SuperType。
- console.log(instance.constructor===SuperType);//true
总结: 访问一个实例属性时,首先会在实例中搜索该属性。如果没有找到该属性,则会继续搜索实例的原型。在通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。在找不到属性或方法的情况下,搜索过程总是要一环一环地前行到原型链末端才会停下来。
就拿上面的例子来说,调用 instance.getSuperValue()会经历4个搜索步骤:
搜索instance实例;
搜索 SubType.prototype;
搜索SuperType的实例;
搜索 SuperType.prototype,最后一步才会找到该方法。
您可能感兴趣的文章:
文章同步发布: https://www.geek-share.com/detail/2769998109.html
javascript中的prototype和__proto__的理解的更多相关文章
- JavaScript中的prototype和__proto__细致解析
最近在学js,体会了一点点它的灵活性.对于初学者的我,总是被它的灵活感到晕头转向,最近发现了一点东西想与大家分享. JavaScript中的prototype和_proto_: 我们先了解一点js中的 ...
- Javascript中的prototype和__proto__的联系区别
转载至http://www.cnblogs.com/sinstone/p/5136871.html 一.联系 prototype和__proto__都指向原型对象,任意一个函数(包括构造函数)都有 ...
- 对于JavaScript对象的prototype和__proto__的理解
一.Object和Function的关系: 刚学JavaScript的时候,看书上说JavaScript中万物皆对象,而javascript中的其他对象都是从Object继承而来,包括内置对象.瞬间觉 ...
- 彻底理解JavaScript中的prototype、__proto__
虽然在JavaScript里一切皆对象,但为了理解原型链系统,我们需要将JavaScript的对象分为对象和函数两大类.在此基础上,JavaScript的原型链逻辑遵从以下通用规则: 对象有__pro ...
- JavaScript 中 的prototype和__proto__
1.prototype是函数的一个属性(每个函数都有一个prototype属性),这个属性是一个指针,指向一个对象.它是显示修改对象的原型的属性. 2.__proto__是一个对象拥有的内置属性(请注 ...
- Javascript中Function,Object,Prototypes,__proto__等概念详解
http://anykoro.sinaapp.com/2012/01/31/javascript%E4%B8%ADfunctionobjectprototypes__proto__%E7%AD%89% ...
- 帮你彻底搞懂JS中的prototype、__proto__与constructor(图解)
作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...
- 原型链继承中的prototype、__proto__和constructor的关系
前不久写了有关原型链中prototype.__proto__和constructor的关系的理解,这篇文章说说在原型链继承中的prototype.__proto__和constructor的关系. 通 ...
- JS中的prototype、__proto__与constructor属性
作为一名前端工程师,必须搞懂JS中的prototype.__proto__与constructor属性,相信很多初学者对这些属性存在许多困惑,容易把它们混淆,本文旨在帮助大家理清它们之间的关系并彻底搞 ...
随机推荐
- mysql死锁(锁与事务)
线上某服务时不时报出如下异常(大约一天二十多次):“Deadlock found when trying to get lock;”. Oh, My God! 是死锁问题.尽管报错不多,对性能目前看来 ...
- centos7 docker swarm加入集群失败
提示的错误为 [root@localhost downloads]# docker swarm join --token SWMTKN-1-2ezr0k5ybds1la4vgi2z7j8ykxkmm0 ...
- 安装TensorFlow后import tensorflow时,出现CXXABI_1.3.11和GLIBCXX_3.4.22 not found
Ubuntu16.04使用Anaconda搭建TensorFlow使用环境但是在安装TensorFlow后,import tensorflow报出如下错误: 该问题的错误原因是由于gcc的动态库较老导 ...
- gdb命名记录
gdb常用命令 显示类 info locals 显示当前局部变量 info args 显示当前函数的参数 info sharedlibrary 显示当前程序依赖的动态库 ptype val 打印变量类 ...
- ireport初接触
我用的版本5.6.0 @官网下载地址 下载安装@参考博客龙凌云端,着重留意:在windows下使用,只下载iReport-5.6.0-windows-installer.exe就行了 安装后配置环境变 ...
- copyProperties 忽略null值字段
在做项目时遇到需要copy两个对象之间的属性值,但是有源对象有null值,在使用BeanUtils来copy时null值会覆盖目标对象的同名字段属性值,然后采用以下方法找到null值字段,然后忽略: ...
- Photoshop如何自定义形状
Photoshop如何自定义形状,自定义形状定义一次,可以随便使用,而且形状无大小,填充后不会有像素问题,普通人可把常用的自定义成形状,很方便.PS中有一些自定义的形状,自己可以随便使用,但是不是很全 ...
- IDEA 2018 搭建 Spring MVC helloworld
转自https://segmentfault.com/a/1190000017248622 网上看了不少idea搭建SpringMVC Helloworld的例子,但是一个个试下来都没有成功.我把他们 ...
- swool教程链接汇总
参考地址: swoole教程第一节:进程管理模块(Process)-上 swoole教程第二节:基础的通讯实现-server篇-1 W3Cschool的swoole的系统教程 csdn网站swoole ...
- Python代码编码规范
目录 1. Introduction 介绍 2. A Foolish Consistency is the Hobgoblin of Little Minds 尽信书,则不如无书 3. Code la ...