首页 > 代码库 > JavaScript原型学习笔记
JavaScript原型学习笔记
JS是一门面向对象的语言,和其它面向对象的语言不一样的是,在JS中没有类的概念。接触过C++、Java的人都清楚,类实现了对象之间的属性和方法共享,而类的继承实现了类的复用。在JS中,通过基于原型的继承实现了以上的功能。
1 构造函数、原型和实例
在JS中,除了5种基本类型,其它都是对象,函数也是对象。而函数是一类特殊的对象,在每个函数对象被创建的时候,都带有一个prototype属性,这个属性指向函数的原型对象。该原型对象只有一个constructor属性,这个属性指向该函数。构造函数其实在结构上与一般的函数没有区别,但是构造函数一般被用来创建一个实例,所以为了与普通函数区分开,构造函数的函数名的第一个字母一般都是大写。
通过new操作符,我们可以用一个构造函数创建一个实例。如果一个函数前面加上new操作符,JS引擎其实进行了如下几步操作:
1.创建一个新对象并将该对象绑定在this上。
2.使该新对象的[[prototype]]属性指向该构造函数的原型。这个[[prototype]]属性是一个内部属性,但很多浏览器都给每一个对象提供__proto__用于找到其[[prototype]]属性指向的对象。
3.执行函数代码。
4.返回新对象的引用。
如果前面没有加new操作符,就会像普通函数一样执行构造函数。所以构造函数前面一定记得加上new。
var a = new A();//构造一个实例并使a指向它
A();//执行该函数
通过给构造函数的原型添加属性和方法,能实现对象之间的属性和方法共享。对于一个实例,如果某个属性或者方法在其内部找不到的话JS引擎将去该实例的原型中查找。而p1和p2共享一个原型,所以相当于共享这个原型里的所有属性和方法。
function Person(name){ this.name = name;}Person.prototype.say=function(){console.log(this.name);}var p1 = new Person("joe");var p2 = new Person("sophia");p1.say();p2.say();
2. 原型链
当一个构造函数的原型对象是另外一个构造函数的实例时,就形成了原型链。
function SuperType(){ this.property = true;}
SuperType.prototype.getSuperValue = http://www.mamicode.com/function(){
return this.property;
}
function SubType(){
this.subproperty = false;
}
//继承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = http://www.mamicode.com/function(){
return this.subproperty;
}
var instance = new SubType();
alert(instance.getSuperValue());//true
以上代码定义了两个类型SuperType和SubType,通过重新赋值给SubType的原型实现了SubType对SuperType的继承。然后给SubType.prototype添加了一个新方法,这样就在继承SuperType.prototype的继承上添加了新方法。这个例子中的构造函数、实例和原型的关系如图:
可以看到的是,当一个构造函数的原型被赋值语句改变值后(实际上是让构造函数的prototype属性指向了另一个对象),它不会再有一个指向该构造函数的constructor属性。而且,由于SubType的原型是SuperType的一个实例,SubType的所有实例都会共享该SuperType实例的属性和方法。原型链的顶端是Object.prototype。Object.prototype的[[prototype]]属性为空。
3.确定原型和实例的关系
有了原型链后,原型和实例的关系变得不那么直接了,有两种方法可以确定原型和实例的关系。
instanceof
alert(instance instanceof Object);//truealert(instance instanceof SuperType);//truealert(instance instanceof SubType);//true
只要是实例原型链上的对象,instanceof操作符都会返回true。
isPrototypeOf()
alert(Object.prototype.isPrototypeOf(instance));//truealert(SuperType.prototype.isPrototypeOf(instance));//truealert(SubType.prototype.isPrototypeOf(instance));//true
4.重新原型方法
虽然,当某些原生原型或第三方JS库定义的原型方法不满足我们的需求时,可以通过SuperType.prototype.xxx = function ooo(){...}的方式重写原型方法,但不建议这么做。可以重写我们自定义的类型SubType的原型方法。养成只修改自己创建的类型的习惯,可以避免一些将来可能会出现的错误。
5.hasOwnProperty
在使用for in语句遍历对象时,它先查找对象的属性,如果没有会沿着原型链查找对象的原型,一直到Object的原型上。这样不可避免地会出现查找效率问题。hasOwnProperty是Object.prototype的一个方法,它能判断一个对象是否包含自定义属性而不是原型链上的属性。但如果一个对象改写了这个属性,就需要使用外部的 hasOwnProperty 函数来获取正确的结果。
参考文章:
1.http://www.nowamagic.net/librarys/veda/detail/1648
2.JS高级程序设计
3.知乎
JavaScript原型学习笔记