首页 > 代码库 > 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.sub
property = 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原型学习笔记