本篇文章用来记录下最近研究对象的一些心得,作一个记录与总结,以加深本身的印象,同时,但愿也能给正在学习中的你一点启发。本文适合有必定JavaScript基础的童鞋阅读。原文戳这里javascript
在JavaScript中,万物皆对象。我们写一个JavaScript对象,大多数时候是用构造函数建立一个对象或者用对象字面量建立一个对象。好比:html
//经过构造函数来建立对象 function Person() { //... } var person1 = new Person(); //经过对象字面量建立对象 var person2 = { name: 'jessica', age: 27, job: 'teacher' }
固然还有其余方式建立对象,这里就不列举出来了。那么问题来了,经过不一样的方式建立的对象有什么区别呢?java
咱们知道,每一个JS对象必定对应一个原型对象,并从原型对象继承属性和方法。那么对象是怎么和这个原型对象对应的呢?带着问题慢慢看下面的内容吧~git
__proto__
和prototype
概念区分其实说__proto__
并不许确,确切的说是对象的[[prototype]]
属性,只不过在主流的浏览器中,都用__proto__
来表明[[prototype]]
属性,由于[[prototype]]
只是一个标准,而针对这个标准,不一样的浏览器有不一样的实现方式。在ES5中用Object.getPrototypeOf
函数得到一个对象的[[prototype]]
。ES6中,使用Object.setPrototypeOf
能够直接修改一个对象的[[prototype]]
。为了方便,我下面的文章用__proto__
来表明对象的[[prototype]]
。github
而prototype
属性是只有函数才特有的属性,当你建立一个函数时,js
会自动为这个函数加上prototype
属性,值是一个空对象。因此,函数在js
中是很是特殊的,是所谓的一等公民
。
那么__proto__
和prototype
是怎么联系起来的呢?让咱们来看下下面的代码:浏览器
function Person(name, age) { this.name = name; this.age = age; } var person1 = new Person('jessica', 27);
new Person()
的时候到底发生了什么?new
一个构造函数,至关于实例化一个对象,这期间其实进行了这三个步骤:函数
建立对象,设为o,即: var o = {}
;学习
上文提到了,每一个对象都有__proto__
属性,该属性指向一个对象,这里,将o
对象的__Proto__
指向构造函数Person
的原型对象(Person.prototype
);this
将o
做为this
去调用构造函数Person
,从而设置o
的属性和方法并初始化。spa
当这3步完成,这个o
对象就与构造函数Person
再无联系,这个时候即便构造函数Person
再加任何成员,都再也不影响已经实例化的o
对象了。
此时,o
对象具备了name
和age
属性,同时具备了构造函数Person
的原型对象的全部成员,固然,此时该原型对象是没有成员的。
如今你们都明白了吧,简单的总结下就是:
js在建立对象的时候,都有一个叫作__proto__
的内置属性,用于指向建立它的函数对象的原型对象prototype
那么一个对象的__proto__
属性究竟怎么决定呢?答案显而易见了:是由构造该对象的方法决定的。
下面讲解三种常见的建立对象方法。
好比:
var Person = { name: 'jessica', age: 27 }
这种形式就是对象字面量,经过对象字面量构造出的对象,其__proto__
指向Object.prototype
。
因此,其实Object
是一个函数也不难理解了。Object、Function都是是js自带的函数对象。
能够跑下面的代码看看:
console.log(typeof Object); console.log(typeof Function);
就如我前面讲的,形如:
function Person(){} var person1 = new Person();
这种形式建立对象的方式就是经过构造函数建立对象,这里的构造函数是Person
函数。上面也讲过了,经过构造函数建立的对象,其__proto
指向的是构造函数的prototype
属性指向的对象。
var person1 = { name: 'jessica', age: 27 } var person2 = Object.create(person1);
这种状况下,person2
的__proto__
指向person1
。在没有Object.create
函数的时候,人们大可能是这样作的:
Object.create = function(p) { function f(){}; f.prototype = p; return new f(); }
一看你们就会明白了。
其实仔细思考下上面提到的三种建立对象的方法,追究其本质,不难发现,最根本的仍是利用构造函数再经过new
来建立对象。所谓的对象字面量也只不过是语法糖而已,本质上是var o = new Object(); o.xx = xx;o.yy=yy;
。 因此,函数真不愧是js中的一等公民呀~
既然已经提到了原型,就不得不提一下原型链了,毕竟这是实现继承最关键所在,也是js对象精妙所在。
还记得上文提到的一个总结吗?不记得?不要紧,我贴出来让你们温故而知新,哈哈~
js在建立对象的时候,都有一个叫作__proto__
的内置属性,用于指向建立它的函数对象的原型对象prototype
而原型链的基本思想就是利用原型让一个引用类型继承另外一个引用类型的属性和方法。
让咱们再简单回顾下构造函数、原型和实例的关系:
每一个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针(constructor
),而实例则包含一个指向原型对象的内部指针(__proto__
)。
咱们拿一个例子来说解:
function Person(name, age) { this.name = name; this.age = age; } var person1 = new Person('jessica', 27);
一图胜前言,咱们用画图的形式来说解下上面的例子:
从上图能够看到,其实原型链的顶端是Object.prototype.__proto__
,也即为null
。
函数是js
中的一等公民,js
在建立对象的时候,都有一个叫作__proto__
的内置属性,用于指向建立它的函数对象的原型对象prototype
。只有函数有prototype
, 当你建立一个函数时,js
会自动为这个函数加上prototype
属性,值是一个空对象。