传统的OO语言有类的概念,但js(ES5)却是基于原型实现的面向对象。
原型是?
我们创建的每一个函数都会有一个原型(prototype)属性,这个属性是一个指针,指向函数的原型(prototype)对象。使用原型对象可以让构造函数的实例对象共享原型对象包含的属性和方法,而不会像工厂模式或者构造函数模式那样,方法本应该是可以是通用的,可是每一个创建的对象实例都要各自复制一份。
function People(name){ this.name=name; this.sayName=function(){ console.log("Hi! my name is "+this.name); }; }
var Jerel=new People("Jerel"); var AsenZ=new People("AsenZ"); console.log(Jerel.sayName==AsenZ.sayName); //false
但使用原型模式的话,同一个方法是被不同对象实例所引用的,上面的结果会返回ture。
function People(name){ this.name=name; } People.prototype.sayName=function(){ console.log("Hi! my name is "+this.name); }; var Jerel=new People("Jerel"); var AsenZ=new People("AsenZ"); console.log(Jerel.sayName==AsenZ.sayName); //true
构造函数实例化的过程中发生了什么
构造函数通过new操作符实例化的每一个对象,都会生成一个指向构造函数原型对象的指针,不过在这里不是prototype(构造函数通过prototype指针指向原型对象),而是[[prototype]](或者叫—proto—),同时构造函数内部的this指针会绑定到该对象实例上。
构造函数内部绑定在this指针下的所有属性或者方法会被复制下来,作为实例对象的一部分,但是呢原型中定义的属性和方法仍是属于原型自身的,不归对象实例所有。对象只是引用。对象在调用一个属性或者方法时,如果在构造函数内部没有相应的定义,则会通过[[prototype]]指针去原型对象中寻找。
继承
——借用构造函数
如果需要继承构造函数内部this指针所绑定的所有属性和方法的话,可以在子构造函数中使用call方法,call方法的第一个参数会传入一个对象,这个对象会用来替换调用call方法的方法中的this,所以我们call方法的第一个参数可以传入子构造函数内部的this指针。
但是这种方法却继承不了原型内部的属性和方法。
function People(name){ this.name=name; } People.prototype.sayName=function(){ console.log("Hi! my name is "+this.name); }; function Boy(name){ People.call(this,name); } var Jerel=new Boy("Jerel"); console.log(Jerel.name); //Jerel console.log(Jerel.sayName); //undefined
如果需要继承原型对象的内部属性和方法的话呢?
——组合继承(借用构造函数+原型链)
function People(name){ this.name=name; } People.prototype.sayName=function(){ console.log("Hi! my name is "+this.name); }; function Boy(name){ People.call(this,name); } Boy.prototype=new People(); Boy.prototype.constructor=Boy; var Jerel=new Boy("Jerel"); console.log(Jerel.name); //Jerel Jerel.sayName(); //Hi! my name is Jerel
还有不少其他的实现继承的方法,不过感觉思路差不了多少的,这一篇总结主要是为了加深一下自己对原型的理解。
虽然说有了babel,现在ES6已经可以放开的使用了!class定义类,extends实现继承不能再爽,但是这些新特性也不过是语法糖,底层的原理还是离不开最基本的原型。