一、什么是原型链
当需要获取一个对象的某个属性或方法时,首先在对象自身查找该属性,找不到的话,会沿着原型链向上查找,直到在某个原型中找到该属性,如果到达原型链顶端依然找不到,则返回undefined.
1 var person = {name : "Peter"}; 2 3 //Peter 4 console.log(person.name); 5 6 //undefined 7 console.log(person.age); 8 9 Object.prototype.age = 100; 10 11 //100 12 console.log(person.age);
二、原型链的作用
- 面向对象时,继承主要就依靠原型链来实现
- 定义构造函数时,使用原型来防止方法的重复定义(静态方法)
- ...发挥你的想象
继承实例:
1 function Father(){ ...} 2 3 function Son(){...} 4 5 var father = new Father(); 6 7 //实现继承,所有的son继承自father对象 8 Son.prototype = father; 9 10 var son = new Son(); 11 12 //true 13 son instanceof Father;
使用原型来防止方法重复定义:
1 //使用这种方法来定义构造函数时,每次new Cat都重新创建了一个bite方法 2 function Cat(){ 3 this.name = "咪咪"; 4 function bite(){...} 5 } 6 7 //这种方式,在new Dog时,所有实例都用的同一个bite方法 8 function Dog(){ 9 this.name = "旺财"; 10 } 11 12 Dog.prototype.bite = function(){...}
三、理解原型链原理
想要理解javascript的原型链机制,首先要有这些概念:
- 除了5种基本类型(number, string, boolean, null, undefined)外,所有东西都是对象,function也不例外
- 每个对象都有自己的构造函数,用字面量定义的对象(var obj = {})的构造函数时Object(),函数的构造函数是Function(). (Function()也是一个函数,它的构造函数是自己)
ps:基本数据类型在执行方法时会被转换为对应的包装对象(Number, String, Boolean)
接下来,就是原型链的核心了,请注意,核心是[[proto]]而不是prototype(笔者学习时老以为prototype才是关键,这是不对的):
- 所有对象都有[[proto]]属性(标准中定义),它指向本对象的原型, 在js中本不能直接被访问,但FF或chrome中提供了__proto__属性来访问该值
- 原型链就是根据[[proto]]属性,来遍历所有原型
- 每定义一个函数时,都会为该函数对象产生一个prototype属性(注意:与[[proto]]不同,只有函数对象才有,笔者刚学习时老弄混),它的默认值是一个名字与函数名相同的对象 , 这个对象有个属性constructor,指向函数自身(func.prototype.constructor === func)
- 所有普通对象(非函数对象)的[[proto]]指向它的构造函数的prototype,字面量对象的构造函数是Object()
- 所有函数对象(包括Function自己)的[[proto]]都指向Function.prototype
- 对于默认的prototype而言,因为它是一个对象,所以它的[[proto]]都指向Object.prototype(当然,你可以修改prototype)
- Object.prototype的[[proto]]的值为null, 它是原型链的顶端
大家结合文字再看网络上流传的图,进一步的理解原型链.