原型:
先了解下原型相关的几个参数:
构造函数创建对象:
function Person() { } var person = new Person(); person.name = 'Kevin'; console.log(person.name) // Kevin
Person 就是一个构造函数,我们使用 new 创建了一个实例对象 person
prototype
每个函数都有一个 prototype 属性
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性和方法。
function Person() { } // 虽然写在注释里,但是你要注意: // prototype是函数才会有的属性 Person.prototype.name = 'Kevin'; Person.prototype.print= function(str){console.log(str)} var person1 = new Person(); var person2 = new Person(); person1.print("打印原型中的方法") //打印原型中的方法 console.log(person1.name) // Kevin console.log(person2.name) // Kevin
proto
每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型.
(问: Person是不是对象?有没有proto?Person.__proto__指向的又是谁?稍后解答)
function Person() { } var person = new Person(); console.log(person.__proto__ === Person.prototype); // true
constructor
每个原型都有一个 constructor 属性指向关联的构造函数 实例原型指向构造函数
function Person() { } console.log(Person === Person.prototype.constructor); // true
function Person() { } var person = new Person(); console.log(person.__proto__ == Person.prototype) // true console.log(Person.prototype.constructor == Person) // true // 顺便学习一个ES5的方法,可以获得对象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
初识Object
Object对象本身是一个函数对象。既然是Object函数,就肯定会有prototype属性,所以可以看到"Object.prototype"的值就是”Object {}”这个原型对象。反过来,当访问”Object.prototype”对象的”constructor”这个属性的时候,就得到了Obejct函数。
另外,当通过”Object.prototype._proto_”获取Object原型的原型的时候,将会得到”null”,也就是说”Object {}”原型对象就是原型链的终点了。
初识Function
如上面例子中的构造函数,JavaScript中函数也是对象,所以就可以通过_proto_查找到构造函数对象的原型。
Function对象作为一个函数,就会有prototype属性,该属性将对应”function () {}”对象。
Function对象作为一个对象,就有__proto__属性,该属性对应”Function.prototype”,也就是说,”Function._proto_ === Function.prototype”。
(所以: Persion也是一个对象,拥有 proto属性, Person.__proto__ === Function.prototype )
原型链
因为每个对象和原型都有原型,对象的原型指向原型对象,而父的原型又指向父的父,这种原型层层连接起来的就构成了原型链。
属性查找
我们创建一个Object对象
var obj = { name: 'obj' }
obj对象我没有给它定义valueOf / toString / constructor方法为什么会有呢?
要探究valueOf / toString / constructor的来源我们需要借助console.dir().
通过上图我们可以看到, Object的大致结构如下图所示
Object:
name:"obj" --->这个是我们赋予的
__proto__:
constructor
toString
alueOf
__proto__
我们发现:
obj 本身有一个属性 name(这是我们给它加的)
obj 还有一个属性叫做 __proto__(它是一个对象)
obj.__proto__ 有很多属性,包括 valueOf、toString、constructor 等
obj.__proto__ 其实也有一个叫做 __proto__ 的属性(console.log 没有显示),值为 null
现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor 这几个属性?
答:
这跟 __proto__ 有关。
当我们「读取」 obj.toString 时,JS 引擎会做下面的事情:
1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
2. 看看 obj.__proto__ 对象有没有 toString 属性,发现 obj.__proto__ 有 toString 属性,于是找到了
所以 obj.toString 实际上就是第 2 步中找到的 obj.__proto__.toString。
可以想象,
3. 如果 obj.__proto__ 没有,那么浏览器会继续查看 obj.__proto__.__proto__
4. 如果 obj.__proto__.__proto__ 也没有,那么浏览器会继续查看 obj.__proto__.__proto__.proto__
5. 直到找到 toString 或者 __proto__ 为 null。
上面的过程,就是读属性的搜索过程。
而这个搜索过程,是连着由 __proto__ 组成的链子一直走的。
这个链子,就叫做原型链。
共享原型链
现在我们有另一个对象
var obj2 = { name: 'obj2' }
那么 obj.toString === obj2.toString , 也就是 obj.__proto__ .toString === obj2.__proto__ .toString
这有什么意义呢?
如果我们改写 obj2.__proto__.toString,那么 obj.toString 其实也会变!
这样 obj 和 obj2 就是具有某些相同行为的对象,这就是意义所在。
那么如何让他们产生差异化呢?
直接赋值就可以了.
bj.toString = function(){ return '新的 toString 方法' }
参考文章:
还没有评论,来说两句吧...