原型对象随笔

prototype、proto和constructor 三者之间的关系

首先来看三个的各自含义函数

  1. prototype
    构造函数有一个prototype属性,指向实例对象的原型对象。经过同一个构造函数实例化的多个对象具备相同的原型对象
  2. constructor
    原型对象有一个constructor属性,指向该原型对象对应的构造函数
  3. proto
    实例对象有一个proto属性,指向该实例对象对应的原型对象,参照构造函数prototype属性来的。

原型对象

基本理解

不管何时,只要建立函数,就会根据规则为该函数建立一个 prototype属性,这个属性指向函数的原型对象。在默认状况下,全部的原型对象,都会自动得到一个constructor属性。这个属性包含一个指向 prototype 属性所在函数的指针。
在建立了自定义构造函数以后,其原型对象默认只会取得 constructor 属性和从Object继承一些方法。
当调用构造函数建立一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象
例如:prototype

// 定义函数.  会默认为该函数建立prototype属性
function Person(){}
// 建立实例对象, 实例对象会有默认的proto 属性 指向原型对象
var p = new Person()

图示:
指针

实际状况

  1. 原型对象也是实例对象,实际上,任何对象均可以看作是经过Object()构造函数的new操做实例化的对象。
  2. 函数也是对象,只不过是具备特殊功能的对象而已。任何函数均可以看作是经过Function()构造函数的new操做实例化的结果。
  3. Object.prototype的原型对象是null (注意不是Object的原型对象)
  4. 特殊就是Fuction函数了, 全部的函数均可以当作是构造函数Function()的new操做的实例化对象。那么,Function能够当作是调用其自身的new操做的实例化的结果
function foo(){}
f1 = new foo;

图示:
code

注意
原型对象Function.prototype的constructor属性指向构造函数Function();实例对象Object和Foo自己没有constructor属性,须要继承原型对象Function.prototype的constructor属性。对象

function Foo(){};
var f1 = new Foo;
console.log(Function.prototype.constructor === Function);//true
console.log(Foo.constructor === Function);//true
console.log(Foo.hasOwnProperty('constructor'));//false
console.log(Object.constructor === Function);//true
console.log(Object.hasOwnProperty('constructor'));//false

原型链

其实,在对象去查找一个属性的时候,会如今对象自己上查找,若是不存在,则在其原型对象上查找,一直查找到null为止。这种经过原型层层链接起来的就称为成了原型链

注意: 原型对象能够被修改,能够被重写。注意修改和重写的区别:blog

修改原型对象

function Foo(){}
foo.prototype.name = 'fun'
var f1 = new Foo;
alert(f1.name); // fun  能够访问到原型对象上的属性

字面量改变

function Foo(){}
Foo.prototype = {
    name:"foo"
}
var f1 = new Foo;
alert(f1.name); // fun  能够访问到原型对象上的属性

注意当以这种字面量来建立,虽然结果是正确的可是 constructor 并不在指向 Foo 函数了。 而如今咱们彻底重写了prototype 对象了。(就是改变了Foo.prototype的指向一个新建立的对象)所以,constructor属性指向新对象的constructor属性(新对象由Objecct建立出来的,所以指向了Object构造函数)继承

console.log(f1 instanceof Objecct) // true
console.log(f1 instanceof Foo) // true
console.log(f1.constructor == Foo) // false
console.log(f1.constructor == Object) // true

因此一般会在改变prototype时指定constructor属相原型链

unction Foo(){}
Foo.prototype = {
    constructor: Foo,
    name:"foo"
}
var f1 = new Foo;
alert(f1.name); // fun  能够访问到原型对象上的属性

动态改变

其实原型对象和实例对象之间链接就一个指针,而非副本,这样松散的链接关系, 就可以让咱们在原型对象作的任何操做,在实例上当即反应出来。原型

function Foo(){}
f1 = new Foo;
// 这里改变对象自己, 此时 实例对象和构造函数的原型对象是同一地址
Foo.prototype.sayHello = function(){
    console.log("hello")
}
f1.sayHello()  // 'hello'

请记住,实例中的prototype指向原型对象,在建立时就构造函数已经决定了。 不会随着构造函数的原型对象指针的改变而发生改变。io

function Foo(){}
f1 = new Foo;
// 这里改变了指向。 此时 实例对象和构造函数的原型对象不在指向同一地址了
Foo.prototype = {
    constructor: Foo,
    sayHello : function(){
        console.log("hello")
    }
}
f1.sayHello()  // erro

重写原型对象切断了现有原型与任何以前已经存在的对象实例之间的联系,以前任何实例对象它们的引用仍然是最初的原型。而现有构造函数,以及以后建立的实例对象会指向重写以后的原型对象。

相关文章
相关标签/搜索