原型链

引入从Object和Function开始

Object和Function都做为JS的自带函数,Object继承本身,Funtion继承本身,Object和Function互相是继承对方,也就是说Object和Function都既是函数也是对象。函数

1
2
console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true

 

Object 是 Function的实例,而Function是它本身的实例post

1
2
console.log(Function.prototype); // ƒ () { [native code] }
console.log(Object.prototype); // Object

 

普通对象和函数对象

JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object 、Function 是 JS 自带的函数对象。下面举例说明ui

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var o1 = {}; 
var o2 =new Object();
var o3 = new f1();

function f1(){};
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

console.log(typeof Object); //function
console.log(typeof Function); //function

console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function

console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是经过 new Function() 建立的对象都是函数对象,其余的都是普通对象。f1,f2,归根结底都是经过 new Function()的方式进行建立的。Function Object 也都是经过 New Function()建立的。this

函数原型:

在理解原型以前有两句很重要的话:spa

一、每个函数对象都有一个prototype属性,可是普通对象是没有的;
prototype下面又有个construetor,指向这个函数。
二、每一个对象都有一个名为proto的内部属性,指向它所对应的构造函数的原型对象,原型链基于proto;prototype

prototype属性

每一个函数都有prototype属性,默认指向一个Object空对象(称为:原型对象)code

1
2
3
function Foo() {
}
console.log(Foo.prototype) //constructor __proto__

 

函数原型链
这里为何要说是空对象,明明看到有constructor、__proto__两个属性,实际上是这个Object对象中没有咱们所须要的属性,固然能够去向原型中添加咱们须要属性或者方法。对象

尝试给原型对象添加属性(通常都是方法)

1
2
3
4
Foo.prototype.method=function () {
console.log("method()")
}
console.log(Foo.prototype)

此时在原型中能够看到method属性已经添加到Foo()中去了。
函数原型链
如今咱们经过建立实例去访问咱们刚才添加的方法继承

1
2
var fun=new Foo()
fun.method() // 能够看到返回的是method()

 

能够看到构造函数跟原型对象是相互引用的关系。ip

这里须要区分显示原型和隐式原型

每一个函数function都有一个prototype,即显示原型(属性)
每个实例对象都有一个__proto__ 称为隐式原型(属性)
咱们继续以前的构造函数:

1
2
3
4
5
var fun=new Foo() 
console.log(fun.__proto__)
//对象的隐式原型的值为其对应构造函数的显示原型的值
console.log(Foo.prototype===fun.__proto__)//true
fun.method() // 能够看到返回的是method()

 

能够看到对象的__proto__属性在建立对象时是自动添加的,默认值为构造函数的prototype属性值。

constructor(构造函数)

在原型对象中有一个属性constructor,当咱们自定义构造函数以后,其原型对象只会默认取得constructor值,能够经过该属性判断出实例是由哪一个构造函数建立的。

1
console.log(fun.prototype.constructor===Foo) //true

 

那么构造函数的原型对象是由什么来建立的呢?

咱们去构造函数中寻找:

1
Foo.prototype.__proto__.constructor // ƒ Object() { [native code] }

 

这样一来能够看到构造函数原型链的其余方法,原来是从Object 上继承来的。
这里的Object原本就存在,此时咱们能够追溯到它的原型链。

原型链

原型链(本质上就隐式原型链,是用来查找对象的。)
函数原型链
在建立函数以前,已经就有了一个Object函数对象,js在加载引擎的时候首先会把这个内置的函数加载进来,而后在去执行咱们的一些方法,访问一个对象的属性时,先从自身属性中查找,找到返回,若是没有,再沿着__proto__这条链上查找,找到返回,若是最终没找到,返回undefined。

注意事项:

  1. 函数的显示原型指向的对象默认是Object实例对象(可是Object不知足)

    1
    2
    3
    console.log(Fn.prototype instanceof Object) //true
    console.log(Object.prototype instanceof Object) //false
    console.log(Function.prototype instanceof Object) //true
  2. 全部函数都是Function的实例

    1
    console.log(Function.__proto__===Function.prototype) //true
  3. Object的原型对象是原型链的尽头

    1
    console.log(Object.prototype.__proto__) //null
  4. (1)读取对象的属性值时,会自动到原型链中查找
    (2)设置对象的属性时,不会查找原型链,若是当前对象中没有此属性,直击添加属性并设置其值
    (3)方法必定定义在原型中,属性通常经过构造函数定义在对象自己上,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    function Fn() {
    }

    Fn.prototype.a = 'xxx';
    var fn1 = new Fn()
    console.log(fn1.a, fn1)//xxx
    var fn2 = new Fn()
    fn2.a = 'yy'
    console.log(fn2.a, fn2) //yy

原型链属性问题

通常状况下,咱们会将属性直接添加在函数中,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
function Person(name, age) {
this.name = name;
this.age = age
}

Person.prototype.setName=function (name) {
this.name = name
}

var p1 = new Person('tom', 12)
p1.setName('bob')
console.log(p1)


var p2 = new Person('errol', 12)
p2.setName('charlie')
console.log(p2)

 

方法问题

能够看实例对象的隐式原型等于构造函数的显示原型,它们都构造函数都是指向的是Person,因此它们的proto都是相等的。

相关文章
相关标签/搜索