理解javascript原型与原型链

时间:2021-05-01 14:34:49

想要学习javascript中的面向对象编程(oop),首先就要了解原型及原型链。

 

先来个例子,了解原型

1 function Foo(y){ 
2 this.y = y; 
3 } 
4 Foo.prototype.x = 10; 
5 Foo.prototype.calculate = function(z){ 
6 return this.x+this.y+z; 
7 }; 
8 var b = new Foo(20); 
9 alert(b.calculate(30)); 

js中除了基本数据类型,一切皆对象。那么,对象又是什么意思呢?在我眼里就是键值对的集合。js中几乎所有的对象都有原型(除个别特例)。

来看上面的例子,构造函数Foo有一个prototype的属性对象,其中prototype属性对象中会包括__proto__,constructor(构造函数)指向构造函数,还有一些添加的属性。

创建构造函数的实例对象b,b会有__proto__属性(创建一个空函数function a(){}也会包含__proto__属性)指向其原型Foo.prototype。

Foo.prototype也是一个对象,也存在__proto__属性指向其原型是Object.prototype。

构造函数Foo也是存在__proto__属性指向它的原型是Function.prototype。

那么,原型是什么呢?

我的理解是,原型是构造函数的实例对象的__proto__属性指向的构造函数的prototype属性对象。

 

理解javascript原型与原型链

 

再看个例子,解释一下原型链

 1 function Person(name, age) {
 2     this.name = name;
 3     this.age = age;
 4 }
 5 Person.prototype.hi = function(){
 6     console.log("name" + this.name + '年龄' + this.age);
 7 };
 8 Person.prototype.walk = function() {
 9     console.log(this.name + 'is walking');
10 };
11 function Student(name, age, classroom) {
12     Person.call(this, name, age);
13     this.classroom = classroom;
14 }
15 Student.prototype = Object.create(Person.prototype); 
16 Student.prototype.constructor = Student;
17 Student.prototype.hi = function() {
18     console.log("name" + this.name + '年龄' + this.age + '班级' + this.classroom);
19 };
20 var one = new Student('nalixue', '23', '3');
21 one.walk();
22 one.hi();

上面例子中

创建Person函数,并在Person的原型对象上创建hi和walk函数

创建Student函数,Student原型对象继承Person的原型对象Student.prototype = Object.create(Person.prototype);并在Student原型对象上覆盖Person的原型对象上的hi

函数。

那么,我们创建Student的实例对象one,在调用函数hi()时会在实例本身进行查找,若没有找到,再查找上一级原型,一层一层向上找直到找到为止。

当找到__proto__属性为null时,证明不存在此方法或属性。这样一层一层查找实例上的原型上的属性就构成一条原型链。

 

下面是我画的“十分简易”的原型链:(ps:仅供参考,不提供美观)

理解javascript原型与原型链

因此调用hi()是Student.prototype上的。

调用walk()时,实例本身不存在,根据原型链找到Student.prototype也不存在,就继续查找Person.prototype,找到后调用方法。

 

如何判断原型呢?

总共有3种方法

 

1 var a = {};
2 console.log(Object.getPrototypeOf(a));
3 console.log(a.__proto__);
4 console.log(a.constructor.prototype);

 

以上三种方法皆会输出Object {},可见都可以判断对象上的原型。只不过Object.getPrototypeOf()方法是ECMAScript5新加的,主流浏览才可以用。

 

注意:文章最开始提到了js中几乎所有的对象都有原型(除个别特例),那么这个特例是什么呢?

1 var obj = Object.create(null);
2 console.log(obj.__proto__);   //undefined

Object.create()用来创建空对象,此时对象上不存在__pro__属性的。

PS:顺便说一下,不是所有的函数对象都有prototype属性的

1 var obj = function() {};
2 var bind = obj.bind(null);
3 console.log(bind.prototype);  //undefined

bind()用来指定运行时的this对象,当为空时,函数对象上就不存在prototype属性。

 

不对的地方请多指教~~~~

 

参考:

http://dmitrysoshnikov.com/ecmascript/javascript-the-core/