Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

原型链这么看好像并不难 #11

Open
koala-coding opened this issue Jul 14, 2019 · 1 comment
Open

原型链这么看好像并不难 #11

koala-coding opened this issue Jul 14, 2019 · 1 comment

Comments

@koala-coding
Copy link
Owner

koala-coding commented Jul 14, 2019

对象着手

在谈原型链之前,先了解对象。

  • 所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型)

  • 所有函数拥有prototype属性(显式原型)(仅限函数)

  • 原型对象:拥有prototype属性的对象,在定义函数时就被创建

prototype与__proto__两个概念

  • prototype:此属性只有构造函数才有,它指向的是当前构造函数的原型对象。
  • proto:此属性是任何对象在创建时都会有的一个属性,它指向了产生当前对象的构造函数的原型对象,由于并非标准规定属性,不要随便去更改这个属性的值,以免破坏原型链,但是可以借助这个属性来学习,所谓的原型链就是由__proto__连接而成的链。

原型链详解

在js代码中 通过对象创建(下面一段简单的代码)详细分析原型链 一段简单代码:

function foo(){}
foo.prototype.z=3;

var obj=new foo();
obj.y=2;
obj.x=1;

//调用
obj.x;//1
obj.y;//2

obj.z;//3

typeof obj.toString;//'function'
'z' in obj;//true
obj.hasOwnProperty('z');//false

obj.z=5;
obj.z;//5
'z' in obj;//true
obj.hasOwnProperty('z');//true
foo.prototype.z;//3

代码简单分析

上面一段代码,声明第一个函数foo的时候,它就会带一个foo.prototype的属性,这个属性是一个对象属性,用new foo();构造器的方式构造一个新的对象obj。这时候这个obj的原型会指向foo的prototype属性。 对于这个foo函数的原型也会指向Object.prototype,这个Object.prototype也是有原型的,它的原型指向null。

代码对象原型链图:

原型链分析图原型链分析图

对象访问属性顺序

对象访问属性的顺序,是采用向上查找,如果当前对象没有,它会一直向上原型链中查找,一直找到null,如果还没有会返回undefind。

对象中值修改说明

代码中修改obj.z的值后,再次输出obj.z的时候是5,foo.prototype.z是3,说明我们在修改或添加对象的属性的时候,只是修改了对象本身obj.prototype.z中的值,而原型链中foo.prototype.z的值并不会修改。

in,hasOwnProperty等方法的出现

首先查看整个原型链,会想这两个方法是怎么来的,在foo的的proto指向上一级Object.prototype的时候,就可以访问Object中的一些函数和属性了,其中就包括这两个方法。

第一次调用

'z' in obj;//true  
obj.hasOwnProperty('z');//false

表示的是z并不是obj这个对象上的,而是对象的原型链上的。

 'z' in obj;//true
  obj.hasOwnProperty('z');//true
  foo.prototype.z;//3

第二次修改了obj.z的值,z就是obj这个对象上的了,但是也并没有修改原型链中的z的值。

特殊说明

_proto_是每一个对象都有的属性,它的指向会有一个特殊说明,大多数情况下 _proto_指向了产生当前对象的构造函数的原型对象,也就是那个 prototype。但是会有特殊的情况

  • 特殊情况
 var a={};
 var b=Object.create(a);

object.create是创建了一个空对象,空对象的原型指向a,a也是空对象,这其中不存在prototype;Object.create在继承中也常被使用,创建一个空对象指向()内的对象,这这样实现了b继承a,也不会篡改a中的内容,在这里就不具体说明了。

原理图分析

原理图分析原理图分析

总结

到底什么是原型链?

proto是任何对象都有的属性,在js中会形成一条proto连起来的链条,递归访问proto必须最终到头,并且值是null。

误区

写这篇总结的过程中,发现很多文章都写了“JS中万物皆对象”。难道真的是这样吗? JS世界很大,并不只有对象

@CoderMonkie
Copy link

已阅Mark。

给博主补充一下,关于__proto__属性,
在浏览器环境下虽有这个实现,但非JS语言标准,
(试了下在Nodejs下也是有这个属性的)

function fnc(){}
console.log('prototype: ', fnc.prototype)
console.log('__proto__:', fnc.__proto__)
prototype:  fnc {}
__proto__: [Function]

不过标准的用法应该是:Object.getPrototypeOf(fnc)
而不是直接访问__proto__属性

let obj = {}
obj.__proto__ === Object.getPrototypeOf(obj)  // true

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants