JavaScript之原型与原型链

我的博客原文地址git

万物皆对象

在JavaScript中除值类型以外,其余的都是对象,为了说明这点,咱们举几个例子
咱们可使用typeof来作类型判断github

typeof a;             // undefined
typeof 1;             // number
typeof 'wclimb';      // string
typeof true;          // boolean

typeof function(){};  // function
typeof [];            // object
typeof null;          // object
typeof {};            // object

除了undefinednumberstringboolean属于值类型以外,其余都是对象。你可能要问了,不是还有一个是function吗?要校验他是否是应该对象能够这样作:函数

var fn = function(){}
fn instanceof Object // true

由上面的例子所示,函数确实是对象,为何呢?咱们看一下下面的例子this

function Person(name){
    this.name = name; 
}
var person = new Person('wclimb');
console.log(person) // Person {name: "wclimb"}

由此咱们能够得知,对象都是经过函数建立的,这么说你可能又会说不对,你看下面的就不是函数建立的spa

var person = {name:'wclimb'}

你咋就这么飘呢?我竟无言以对,没错,这是个意外、意外、意外。可是归根结底他仍是经过函数建立的prototype

var person = new Object()
    person.name = 'wclimb'

so,如今你只要知道对象是经过函数建立的就能够了,来跟着我读:
第一遍 对象都是经过函数建立的
第二遍 对象都是经过函数建立的
第三遍 对象都是经过函数建立的code

构造函数(constructor)

function Person(name){
    this.name = name
}
var person1 = new Person('wclimb 1')
var person2 = new Person('wclimb 2')

上面Person就是一个构造函数,咱们经过new的方式建立了一个实例对象person
咱们来看看person1和person2的constructor(构造函数)是否是指向Person的对象

person1.constructor === Person // true
person2.constructor === Person // true

原型(prototype)

在JavaScript中,每定义一个函数都会产生一个prototype(原型)属性,这个属性指向函数的原型对象blog

function Person(){}
Person.prototype.name = 'wclimb'
Person.prototype.age = '24'
Person.prototype.sayAge = function(){
    console.log(this.age)
}
var person = new Person()
person.sayAge(); //  24

那么这个prototype究竟是什么呢?跟构造函数有关系吗?ip

image

上图就能够反映出他们之间的关系

其实函数的prototype指向函数的原型对象,每一个对象都会关联另一个对象,也就是原型,上面的例子改为:

Person.prototype = {
    name: 'wclimb',
    age: 24,
    satAge: function(){
        console.log(this.age)
    }
}

隐式原型(__proto__)

上面咱们说到每定义一个函数都会产生一个原型,每一个函数它不止有原型,还有一个__proto__(隐式原型)
每一个对象都有一个__proto__属性,指向建立该对象函数的prototype,咱们能够来试试,仍是上面的例子:

function Person(){}
var person = new Person()
person.__proto__ === Person.prototype // true

如今他们的关系图以下

image

由上图咱们能够知道:

Person.prototype.constructor = Person
person.__proto__ = Person.prototype
person.constructor = Person

咱们能够看到person.__proto__指向构造函数的原型,那么构造函数的原型即Person__proto__指向哪里呢?
咱们知道构造函数其实就是由Function来建立的,由此得出:

Person.__proto__ === Function.prototype

那么构造函数的原型即Person.prototype__proto__指向哪里呢?
原型对象实际上是经过Object生成的,天然而然的得出:

Person.prototype.__proto__ === Object.prototype

那么Object.prototype__proto__指向哪里呢?答案是null,最终获得下面的图

image

抛开这张图,来看看下面几道题

  1. person.__proto__
  2. Person.__proto__
  3. Person.prototype.__proto__
  4. Object.__proto__
  5. Object.prototype.__proto__

解:

  1. 每一个对象都有一个__proto__属性,指向建立该对象函数的prototype,由于Person是person的构造函数

Person === person.constructortrue,因此:person.__proto__ === Person.prototype

  1. Person构造函数是由Function建立的,因此能够得出Person.__proto__ === Fucntion.prototype
  2. 咱们上面说过Person.prototype实际上是一个对象,而对象是由Object建立的,因此 Person.prototype.__proto__ === Object.prototype
  3. Object对象都是函数建立的,因此Object.__proto__ === Function.prototype
  4. 虽然Object.prototype是一个对象可是他的__proto__null

实例和原型

当咱们要取一个值的时候,会先从实例中取,若是实例中存在,则取实例的值,若是实例不存在,则会顺着原型里找,直到找到

function Person(){}
Person.prototype.name = '我来自原型'

var person = new Person()
person.name = '我来自实例'
console.log(person.name); // 我来自实例
delete person.name
console.log(person.name)); // 我来自原型

首先person实例中有这个属性,返回我来自实例,而后将它删除以后,会从原型中招,也就是person.__proto__,由于Person.prototype === person.__proto__,因此获得我来自原型

总结

原型和原型链基本已经讲解完,不过还有待完善,若有错误,还望指正

GitHub:wclimb

相关文章
相关标签/搜索