js 中的 原型链 prototype _proto_

原型链

这是第三次修改这个篇文章了

我想我需要将自己的思路说出来

下面的1-4只是为了告诉明确两件件事情。(原型链是会配合着属性的查找使用的。要不然我们一般也用不到原型链。),第二 原型链的查找,仅仅只会沿着_proto_去查找

我们需要知道的基础

我们建立出来三个Object,看下初始化会是什么样子,带那些属性

var apple = function () {};//我们建立了一个函数 我们看下 这个函数有哪些属性

 apple(初始化自带属性)
______________
|  protoType |
|  _proto_   |
--------------

var obj = {};//onject 属性

obj (初始化自带属性)
______________
|            |
|  _proto_   |
--------------

var apple_1 = new apple();//new 实例

apple_1 (初始化自带属性)
______________
|            |
|  _proto_   |
--------------

1,只有function(函数)才具有 protoType +_proto_   属性

2,除了函数之外的object只有 _proto_   

3,new 出来的实例 只有_proto_ (虽然他是函数,但是只有_proto_)-------我跟你一样,想知道为什么。继续往下看。

_proto_中属性的查找

要说到原型链,我们前面提到了,会伴随的属性的查找。

看下面的代码

var apple = function () {};//我们建立了一个函数 我们看下 这个函数有哪些属性

 apple(初始化自带属性)
______________
|  protoType |
|  _proto_   |
--------------

apple.prototype.price = 10;
apple.__proto__.price = 20 ;

此时我们打印一下 apple.price你可以猜测一下。是undefind , null ,10 ,20 ,中的哪一个

最后 js 给出的答案是20,也就是虽然函数 apple() 有 prototype 与 _proto_的属性。但是查找属性只会去_proto_ 里面去查找。

过程是:编译器先去 apple第一层去查找有没有price 结果他查出来的是没有price(因为只有 prototype 与 _proto_属性);

 apple(初始化自带属性)
______________
|  protoType |
|  _proto_   |
--------------

然后他会越过protoType(<1>)直接去 _proto_  里面查找,发现有price,就给你,没有的话,继续找_protop_里面找找看看有没有_proto_ 属性。没有的话就返回undefind,有的话再去找这一层级中的_proto_上有没有price属性。接下来就是(<1>)。

为什么会跳过去protoType (或者说不去查找protoType中有没有prices属性),看下面的代码

var orange = function(){};

 orange (初始化自带属性)
______________
|  protoType |
|  _proto_   |
--------------

orange.protoType.price = 10;

console.log(orange.price);

可以猜测一下 orange.price 打印出来的是什么

返回来的是 undefind,---在寻找Object的属性的时候,编译器,只去_proto_上去寻找属性,其他的一概不理。只认_proto_

所以我们知道了,原型链就是又_proto_组成的,让并沿着只_proto_寻找下去。找不到就返回undefind。

哪什么是protoType

我还只建议你去看这一片的文章 https://www.jianshu.com/p/686b61c4a43d。不要看我下面关于 _proto_ 与 protoType了

protoType 就是_proto_ 指向的地方,也就是 这两个的内容是一模一样的。

我们有些东西需要作为开胃菜!

因为在js(ES6之前,后来才出现class,但是这个也是个语法唐)中一开始没有calss的概念。到那时c# java中是有的。有了calss更有利于面向对象编程。就是编写出来的代码更容易维护。

js中没有calss那可怎么面向对象编程,我们使用 new ,js给了我们这样的一个方式去面向对象编程,其实你用的Function Object,你可以理解为都是 new 出来的,只不过我们编译器让我们写的更加方便。看下面的代码

var Obj_a = new Object();
var Obj_b = {};

console.log( typeof obj_a) 
console.log( typeof obj_b)

再来一个代码

var fun = new Function();
var fun_1 = function(){}

console,log(typeof fun);
console,log(typeof fun_1);

然后我们再来一个代码

var apple = function(){};

var apple_a = new apple();

对比上面的你有没有很熟悉的感觉,你是不是也常常这样使用。

然后 apple_a 与 apple 之间是什么关系。

apple_a 是apple的构造函数, apple是apple_a的构造函数。由apple实例化出来了一个apple_a的对象。

既然由上面这一层关系,这跟prototype由又有什么关系

我们检查了一个 apple_a._proto_ 与 apple.protoType 之间的关系。结果显示他们是相等关系。

还记得前面我们说过什么吗 ----  protoType 就是_proto_ 指向的地方,也就是 这两个的内容是一模一样的。

而Objct需要寻找一个属性,它就会层层的寻找 _proto_ 这个属性。也只认_proto_ ,包括protoType都不认。

我们打印一下 apple.prototype,它里面也有一个_proto_

这样你大概清楚了吧。他们之间是什么关系。给你看下面的图

var animal = function() {};
var dog = function() {};

animal.prototype.price = 20;
animal.price = 1000;

dog.prototype = animal;

var cat = new animal();
var tidy = new dog();
// 下面两行分别输出什么?
console.log(cat.price);
console.log(tidy.price);

prototype的指向规则是什么(更新中)

看到这里就好了。下面的内容是我之前写的

那就是。原型链就是   _proto_  这个属性串起来的。只会在_proto_上去查找你需要的属性。(如果你并不清楚就记住这一点) 而 protoType 是 _proto_ 所指向的内容 。

  

1> 是骡子是马拉出来走两步。

我们知道js分为8中类型 分别是 undefinednull、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。smbol

我们分别在js走一下,看看有什么不同(可以按下F12然后点开控制台(Console)输入下面的代码,会看到一样的结果)

number :

string:

bool:

Object:(有个箭头,然后我们打开箭头)

smybol:

underfind:

null

通过上面的打印,我感觉你应该看到了有什么不同,就是 Object 与其他的打印出来的不同,不同的地方在于Object打印出来的竟然可以打开。里面有个_proto_东西。然后我们接着打开我们会看到下面这幅图

为什么Object类型会这样。可以打开,下面还有这个这么多东西。

看到了这个东西。我们就离原型链更近了一步。

2>呀哈,怪妖艳的哈。一串一串的

看到上面一串一串的。为什么会这样挂的一串一串的。

我们呢,再来试试

我先创建一个Object

我们给这个 a 添加一个值 a(stirng 字符串),然后再打印一下,显示出来。这个 a 添加了一个参数后,会变成何方神圣

看到这里,我想你大概能看出来。难道是a(Object)自己身的属相都会挂在上面。

我们再来加多一些

确实是这样,原来Object被打印出来之后,他里面的属性都会这样的形式显示出来。(那上面的变量我们都可以调用 a.b   a.c  a.d   a.e  a.f 给他打印出来。)

3>原来js8中基本类型中 只有Object类型的才有 _proto_

我们上面做的实验发现只有Object才能打开,并且属性都会挂在上面,而且这些属性可以被调用。

我们还发现有一个 _proto_ ,这是个什么东西,按照方才的推理,Object的属相都会被挂在身上,并且可以调用。那么这个_ptoro_ 也可以调用.。 我们来试试 看看能不能,像调取属相的方法样调取这个 _proto_。

我擦嘞,打印出来。那就是说 _proto_,就是Object类型的一个属性,不过是系统在我们创建Object类型的时候帮助我们默认的添加了折磨一个属性。

4> _proto_ 里面又挂了一串东西

我们看到上面的图片看到了,当我们打开_proto_之后,又是一串的东西。按照刚刚的推理。这里面是_proto_的属性,自然也就是Object的属性。我们应该可以通过Object调取这里面的属性。

我们单独给_proto_增加一个属性  我们输入   a.__proto__.g = 1   看看能不能给_proto_一个属性g

成功了。我们再打印一下,看到了上面这幅图,g的属性被放在_proto_这个属性之下了。

那我们就打印一下 g ,使用两种方式去调用。我们发现了一个问题,都可以使用,并且打印数是一个东西。

所以实验出来的是,当Object,第一级属性中,找不到相关参数的时候,他会去_proto_里面去找。找到了就打印出来。

但是找不到呢?我们实验一下。

js编译器给我们反馈是----undefind。

所以通过上面我们可以的出来一个结论。

当Object类型的变量,在查找一个属性的时候。挡在第一级的属性里面找不到,就回去_proto_里面去寻找。不管下面会有多少个_proto_他都会去寻找。直到没有_proto_的时候。它就不会再去寻找了,返回给你undefind。告诉你,嘿,我爬山涉水呀翻山越岭啊,我能翻的都翻过了,我实在是找不到。

上面这样图 ,我们发现打开第一个_proto_里面就没有了。它就会返回undefind。

结论来了 这个寻找需要的属性的过程,所以依赖的串串就是原型链。

懂了这个你就有了 js 中的继承是怎么实现的基础了

  1. 当调取一个对象的属性时,会先在本身查找,若无,就根据 proto 找到构造原型,若无,继续往上找。最后会到达顶层Object prototype,它的 proto 指向null,均无结果则返回undefined,结束。
  2. 由 proto 串起的路径就是『原型链』

官方一点的话语

所有的JS对象都有一个prototype属性,指向它的原型对象。当试图访问一个对象的属性时,如果没有在该对象上找到,它还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。

看到这里或许你会有疑问,什么是prototype什么是原型对象。不急 这是我们下面需要处理的问题

下面的内容是我之前写的,但是写了一些,我感觉还是写的不好,所以我打算换一种方式。下面的先保留

参照了三个文章 

一篇文章看懂_proto_和prototype的关系及区别

原型链的理解

js 构造函数(construction)与原型(prototype)

之前我也不太懂 原型链 似懂非懂的样子 其中的prototype  proto   constructor  原型链之间到底是什么关系!

今天就帮你了解上面的这些概念是什么  以及与原型链之间的关系

prototype里面有个constructor(指向构造函数 构造函数与实例(实例对象)相对应)

proto      里面有个constructor(指向构造函数 构造函数与实例(实例对象)相对应)

  构造函数与实例(实例对象)

function A (){};//大家都默认 构造函数 第一个字母,大写开头  当然你写成小写也没有问题
 
var b = new A();

其中函数 A() 我们叫构造函数  

通过 new A() ,而得到的变量 b 。就是实例(实例对象) 。

 A 作为模板 new出来一个b的实例。所以b是A的实例,A是b的构造函数。

为什么通过 new ,我们就能得到一个 实例对象 b

目的: 为了解决从原型对象生成实例的问题,Javascript提供了一个构造函数(Constructor)模式。

所谓"构造函数",事实上就是一个普通函数,可是内部使用了this变量。对构造函数使用new运算符,就能生成实例。而且this变量会绑定在实例对象上。

话外:上面中A()函数中的 this 指向的是 window ,而b中的this指向的是指向的是 b (如果你对作用域并不太清除的话,记住一句话,并不是函数在哪里创建就决定了作用域指向哪里,而是函数在哪里被调用才决定作用域指向哪里)

然后我们看一张图

function Position(){
    var name = 'jiang'
    var say = function () {
        console.log('你们好,我的名字叫:',name)
    }
};

var postion1 = new Position();
var postion2 = new Position();

 我们首先把 positon1 与 position2打印一下

prototype 

第一我们需要知道   

prototype 都存在哪些地方:只有一个地方 那就是 function 函数  但是 new 出来的实例并没有

proto(_proto) 都存在哪些地方:Objcet  (Objcet  类型 arry,function,null ,{} )

 

出现的目的 : 为了实现数据共享和抽象出通用的属性,加了一个原型prototype

发布了65 篇原创文章 · 获赞 18 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/huhudeni/article/details/99981520