JavaScript 原型和原型链的理解

引言

  • 原型和原型链是js中比较重要但也是比较难的内容;
  • 正是因为有了原型链的概念,js中的继承才成为可能;
  • 本文结合js内置的数据类型,说说我对js原型和原型链的理解;

Javascript和Java语言设计思想的区别

  • java
    • java是完全OOP的语言,对Java的认知是从类与对象开始的;
    • class是一类具有共同特点的物体的抽象,object(对象)是某个class下具体的一个实现,Object类是所有类的顶层父类;
  • js
    • javascript是基于原型(而不是基于类的,尽管ES6新增了class关键字)的面向对象的语言,没有类的概念(ES6新增的类是语法糖);
    • javascript中的class本质上是一个函数对象,和java中的类的概念有本质区别;
    • javascript存在类似面相对象的特性,这就是原型和原型链,从而派生出了类似于父类子类和继承的概念;
  • 本图来自这里

java-js-diff

对象和数据类型

  • js中的数据类型:
    • 数据类型:string、number、boolean、object(数组、对象、null)、undefined、function;
    • 数组、对象、null是不精确的数据类型,在用typeof判断时均返回object;
    • typeof关键字只能返回非精确的数据类型;
    • 用Object.prototype.toString判断精确的数据类型;

type1

type2

  • 首字母大小写的区别:
    • 小写(string、number、boolean、object、null、undefined、function)表示数据类型;
    • 大写(String、Number、Boolean、Object、Array)表示js的内置对象(全部是function类型);

typeof

  • js中对象的含义:
    • 广义的对象(js一切皆为对象、包括window和document对象、也包括String、Number、Boolean、Object、Array、Math、Date等内置对象);
    • 狭义的数据类型(数组、对象、null类型均为object,即被typeof关键字判断为object类型);
    • “对象”这种数据类型(请参考我的另一篇博客);

原型链概述

  • JavaScript中的每个对象都有一个内部的链接指向另一个对象,这个对象就是原对象的原型,这个原型对象也有自己的原型,直到对象的原型为 null 为止(也就是没有原型);
  • 这种一级一级的链结构就称为原型链(prototype chain);
  • 每个对象都有一个隐形的属性proto(两边都是双下划线),这个属性的值为一个地址,指向这个属性的原型对象,原型对象是每个对象都有指向的隐形对象;
  • new出来的普通对象没有构造器,就没有prototype属性;
  • proto属性也可用someObject.[[Prototype]] 表示;
  • 如果一个对象是object类型,它的proto属性总是指向Object.prototype;
  • 如果一个对象是function类型,它的proto属性总是指向Function.prototype;
  • 继承属性:JavaScritp引擎在访问对象的属性时,如果在对象本身中没有找到,则会去原型链中查找,如果找到,直接返回值,如果整个链都遍历且没有找到属性,则返回undefined;

各种对象原型链的图示

  • String对象的原型链

string

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var s = "sss";
var s1 = new String();

console.log(typeof String); //function
console.log(typeof String.prototype); //object
console.log(typeof String.prototype.constructor); //function
console.log(typeof String.prototype.__proto__); //object
console.log(typeof String.__proto__); //function
console.log(typeof s1); //object
console.log(typeof s); //string
console.log(typeof s1.__proto__); //object
console.log(typeof s.__proto__); //object
console.log(String.prototype.constructor); // function String(){...}
console.log(String.prototype.__proto__); //Object {}
console.log(String.__proto__); //function(){}
console.log(String.__proto__ == Function.prototype); //true
console.log(String.prototype.constructor.__proto__ == Function.prototype); //true
console.log(String.prototype.__proto__ == Object.prototype); //true
console.log(s1); //String {}
console.log(s1.__proto__); //String {...}
console.log(s); //sss
console.log(s.__proto__); //String {...}
  • Number对象的原型链

number

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var n = 1;
var n1 = new Number();

console.log(typeof Number); //function
console.log(typeof Number.prototype); //object
console.log(typeof Number.prototype.constructor); //function
console.log(typeof Number.prototype.__proto__); //object
console.log(typeof Number.__proto__); //function
console.log(typeof n1); //object
console.log(typeof n); //number
console.log(typeof n1.__proto__); //object
console.log(typeof n.__proto__); //object
console.log(Number.prototype.constructor); // function Number(){...}
console.log(Number.prototype.__proto__); //Object {}
console.log(Number.__proto__); //function(){}
console.log(Number.__proto__ == Function.prototype); //true
console.log(Number.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Number.prototype.__proto__ == Object.prototype); //true
console.log(n1); //Number {}
console.log(n1.__proto__); //Number {...}
console.log(n); //1
console.log(n.__proto__); //Number {...}
  • Boolean对象的原型链

boolean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var b = true;
var b1 = new Boolean();

console.log(typeof Boolean); //function
console.log(typeof Boolean.prototype); //object
console.log(typeof Boolean.prototype.constructor); //function
console.log(typeof Boolean.prototype.__proto__); //object
console.log(typeof Boolean.__proto__); //function
console.log(typeof b1); //object
console.log(typeof b); //boolean
console.log(typeof b1.__proto__); //object
console.log(typeof b.__proto__); //object
console.log(Boolean.prototype.constructor); // function Boolean(){...}
console.log(Boolean.prototype.__proto__); //Object {}
console.log(Boolean.__proto__); //function(){}
console.log(Boolean.__proto__ == Function.prototype); //true
console.log(Boolean.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Boolean.prototype.__proto__ == Object.prototype); //true
console.log(b1); //Boolean {}
console.log(b1.__proto__); //Boolean {...}
console.log(b); //true
console.log(b.__proto__); //Boolean {...}
  • Array对象的原型链

array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var a =[1,2,3];
var a1 = new Array();

console.log(typeof Array); //function
console.log(typeof Array.prototype); //object
console.log(typeof Array.prototype.constructor); //function
console.log(typeof Array.prototype.__proto__); //object
console.log(typeof Array.__proto__); //function
console.log(typeof a1); //object
console.log(typeof a); //object
console.log(typeof a1.__proto__); //object
console.log(typeof a.__proto__); //object
console.log(Array.prototype.constructor); // function Array(){...}
console.log(Array.prototype.__proto__); //Object {}
console.log(Array.__proto__); //function(){}
console.log(Array.__proto__ == Function.prototype); //true
console.log(Array.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Array.prototype.__proto__ == Object.prototype); //true
console.log(a1); //[]
console.log(a1.__proto__); //包含Array的各种方法
console.log(a); //[1,2,3]
console.log(a.__proto__); //包含Array的各种方法
  • Function对象的原型链

function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var f = function(){};
var f1 = new Function();

console.log(typeof Function); //function
console.log(typeof Function.prototype); //function
console.log(typeof Function.prototype.constructor); //function
console.log(typeof Function.prototype.__proto__); //object
console.log(typeof Function.__proto__); //function
console.log(typeof f1); //function
console.log(typeof f); //function
console.log(typeof f1.__proto__); //function
console.log(typeof f.__proto__); //function
console.log(Function.prototype.constructor); // function Function(){...}
console.log(Function.prototype.__proto__); //Object {}
console.log(Function.__proto__); //function(){}
console.log(Function.__proto__ == Function.prototype); //true
console.log(Function.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Function.prototype.__proto__ == Object.prototype); //true
console.log(f1); //function anonymous(){}
console.log(f1.__proto__); //function(){}
console.log(f); //function(){}
console.log(f.__proto__); //function(){}
  • Object对象的原型链

object

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
   var o = {};
var o1 = new Object();

console.log(typeof Object); //function
console.log(typeof Object.prototype); //object
console.log(typeof Object.prototype.constructor); //function
console.log(typeof Object.prototype.__proto__); //object
console.log(typeof Object.__proto__); //function
console.log(typeof o1); //object
console.log(typeof o); //object
console.log(typeof o1.__proto__); //object
console.log(typeof o.__proto__); //object
console.log(Object.prototype.constructor); // function Object(){...}
console.log(Object.prototype.__proto__); //null
console.log(Object.__proto__); //function(){}
console.log(Object.__proto__ == Function.prototype); //true
console.log(Object.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Object.prototype.__proto__ == null); //true
console.log(o1); //Object{}
console.log(o1.__proto__); //Object{...}
console.log(o); //Object{}
console.log(o.__proto__); //Object{...}
  • 自定义对象的原型链

myobject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   function Person(name,age){
this.name = name;
this.age = age;
}

var p1 = new Person("Jack",22);
var p = {"Jack":22};

console.log(typeof Person); //function
console.log(typeof Person.prototype); //object
console.log(typeof Person.prototype.constructor); //function
console.log(typeof Person.prototype.__proto__); //object
console.log(typeof Person.__proto__); //function
console.log(typeof p1); //object
console.log(typeof p); //object
console.log(typeof p1.__proto__); //object
console.log(typeof p.__proto__); //object
console.log(Person.prototype.constructor); // function Person(){...}
console.log(Person.prototype.__proto__); //Object {}
console.log(Person.__proto__); //function(){}
console.log(Person.__proto__ == Function.prototype); //true
console.log(Person.prototype.constructor.__proto__ == Function.prototype); //true
console.log(Person.prototype.__proto__ == Object.prototype); //true
console.log(p1); //Person {name: "Jack", age: 22}
console.log(p1.__proto__); //Person{...}
console.log(p); //Object {Jack: 22}
console.log(p.__proto__); //Object{...}
  • 最后附上一张知乎上面大神画的图,清楚地表示了Object和Function的继承关系

prototype

您的支持是对我最大的鼓励!