想要学习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属性对象。
再看个例子,解释一下原型链
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:仅供参考,不提供美观)
因此调用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/