对Javascript中原型的深入理解

  理解原型对象

在Javascript中无论什么时候,只要创建一个新的函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象(这个对象的用途是包含可以有特定类型的所有实例共享的属性和方法)。如果按照字面上的意思来理解,那么原型属性就是通过调用构造函数而创建的那个对象的实例的原型对象。

在默认的情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。如下图

function Person(){
}

上图中创建了一个构造函数Person(function Person()),Person函数中有一个prototype的属性指向Person的原型对象,在原型对象中有一个constructor的属性指向了Person函数,所有可以通过new Person()创建对象。

创建了自定义的构造函数后,其原型对象默认只会取得constructor属性,至于其他的方法,都是从Object继承而来的。其中上图中Person.prototype .constructor指向Person.而通过这个构造函数,我们可以继续为原型对象添加其他的属性和方法。如下图:

上图的js代码就是

Person.prototype={
  name:"Nicholas",
  age:23,
  sayName:function(){
    return this.name;
  }
};

当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。ECMA-262第5版中管这个指针叫[[Prototype]],虽然在脚本中没有标准方式访问,我们可以借由Chrome在每个对象上都支持一个属性_proto_(私有属性不可见),这个链接的存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

var p1=new Person();

当创建一个新的p2之后依然会有一个_proto_属性指向Person的原型(Persion.prototype),换句话说每个实例与构造函数没有直接的关系,虽然这实例都不包含属性和方法,但我们却可以调用p1.name查找对象属性的个过程来实现。此时如果通过p2.name设置属性值后会在对象自己的内存空间中存储name的值,当调用sayName()方法的时候在寻找name时,在自己空间中找到之后就不会去原型对象中查找(注意:原型中的值是不会被替换,仅仅是在查找的时候被覆盖)

var p1=new Person();
 alert(p1.name);//Nicholas
 var p2=new Person();

原型的检测

在所有实现中都无法访问到[[Prototype]],但是我们可以通过isPrototypeOf()方法来确定对象直接是否存在这种关系。从本质上讲,如果[[Prototype]]指向调用isPrototypeOf()方法的对象(Person.prototype)。

ECMAScript5中增加一个新的方法.叫做Object.getPrototypeOf(),这个方法返回[[Prototype]]的值

== 可以检测某个对象的constructor

检测某个属性是否是自己是自己的属性用(不是对象原型中的实现)hasOwnProperty(),可以清楚的知道什么时候访问的自己的属性,什么时候访问的是原型属性了。

delete可以用来删除实例属性(自己的属性)

in操作:有两种方式操作in操作符。单独的使用for-in循环中使用。单独是用时,in

会通过对象能够访问给的属性的返回值,无论属性存在于实例中还是原型中。

//检查某个对象是否是某个函数的原型
  alert(Person.prototype.isPrototypeOf(p1));//true
   ECMAScript5中增加一个新的方法.叫做Object.getPrototypeOf(),在所有支持的实现中,这个方法返回[[Prototype]]的值
   alert(Object.getPrototypeOf(p1)==Person.prototype);
   alert(Object.getPrototypeOf(p1).name);
  //alert(p1.constructor==Person);
  //alert(p2.hasOwnProperty("name"))
  delete p2.name;
  //alert("name" in p1)//来自原型
   p1.id=12;
 // alert("id" in p1);//来自实例
  alert(hasPrototypeProperty(p1,"name"))
 /**
  检查某个属性是否在原型中存在
  */
  function hasPrototypeProperty(obj,prop){
    return ((!obj.hasOwnProperty(prop))&&(prop in obj));
  }

在上面给原型添加的属性中存在着已问题constructor属性不指向Person了。上面写法的本质是完全重写了默认的prototype对象,因此constructor属性也变成了新的对象的constructor属性(指向Object构造函数),不在指向Person函数,尽管instanceof操作还是正确返回结果,但是通过constructor已经无法确定对象的类型了。

为了避免这个问题可是手动指定constructor

alert(p1 instanceofPersion);alert(p1.constructor==Persion)

原型重写存在的问题

由于在原型中查找值得过程是一次搜索,我们对原型对象所做的任何修改都能够立即从实例上反映出来,即使先创建实例后修改原型也是可以的

var p2=new Person();
  Person.prototype.sayHi=function(){
    alert(this.name);
  }
  p2.sayHi();//可以获取值

可以获取值是因为实例与原型之间的松散连接关系,当我们调用p2.saHi()时,首先回去实例中搜索名为sayHi的属性,在没有找到的情况下,会继续搜索原型,因为实例和原型之间只不过是一个指针,而不是副本,因此可以在原型中找到新的sayHi属性并返回保存在哪里的函数。

如果是重写整个原型就不一样了。我们知道调用构造函数是会为实例添加一个指向最初原型的[[Prototype]]指针。把原型修改为另外一个对象就等于切断了构造函数和最初的原型之间的联系。切记:实例中的指针仅指向原型。而不是构造函数。

function Person(){
}

  var p1=new Person();

  //所有的"范围对象"都继承自这个对象  重写原型对象
  Person.prototype.sayHi=function(){
    alert(this.name);
  }
  //所有的"范围对象"都继承自这个对象  重写原型对象
  Person.prototype={
  constructor:Person,//显示的设置构造函数的反向引用
  name:"Nicholas",
  age:23,
  sayName:function(){
    return this.name;
  }
};

  p1.sayHi();//undefined
  alert(p1.sayName());//报错
 var p2=new Person();
 alert(p2.sayName());//Nichola

重写之前与重写之后如图:

原型存在的问题

原型对象中的属性是被很多实例共享的,这个共享对于函数是非常合适的,对于原型中基本值得属性是没有问题的但是,如果属性值包含引用类型值就会有一定的问题了。

function Person(){
}

    Person.prototype={
  constructor:Person,//显示的设置构造函数的反向引用
  name:"Nicholas",
  age:23,
  friends:["Shelby","Cunrt"],
  sayName:function(){
    return this.name;
  }
};
 var p1=new Person();
 var p2=new Person();

 p1.friends.push("Jack");
 alert(p1.friends);//"Shelby","Cunrt","Jack"
 alert(p2.friends);//"Shelby","Cunrt","Jack"
 alert(p1.friends==p2.friends);//true

解决这个为题做好的方法如下:

function Person(name,age,friends){
  this.name=name;
  this.age=age;
  this.friends=friends;
}

    Person.prototype={
  constructor:Person,//显示的设置构造函数的反向引用
  sayName:function(){
    return this.name;
  }
};
 var p1=new Person("Tom",20,"Shelby");
 var p2=new Person("Alisa",20,["Cunrt","Jack"]);
 alert(p1.friends);//"Shelby"
 alert(p2.friends);//"Cunrt","Jack"
 alert(p1.friends==p2.friends);//false

对Javascript中原型的深入理解

时间: 2024-08-09 10:44:19

对Javascript中原型的深入理解的相关文章

第一篇 对Javascript中原型的深入理解

  理解原型对象 在Javascript中不管什么时候,仅仅要创建一个新的函数,就会依据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象(这个对象的用途是包括能够有特定类型的全部实例共享的属性和方法).假设依照字面上的意思来理解.那么原型属性就是通过调用构造函数而创建的那个对象的实例的原型对象. 在默认的情况下,全部的原型对象都会自己主动获得一个constructor(构造函数)属性,这个属性包括一个指向prototype属性所在函数的指针. 例如以下图 func

JavaScript中的伪数组理解

看过jQuery源码的人都知道类数组对象,与我们熟知的arguments对象很像 构造一个类数组必须有两个条件 第一个条件:你必须给对象定义个splice方法,只要他是一个function就可以 第二个条件:就是赋值一个length属性,或者增加push,unshift,shift,pop其中任何一个方法,并且调用了一次. 当这两个条件同时满足那么当前的对象在控制台输出后跟数组的格式一模一样. 一般而言大部分都是这样构造一个类数组对象(jQuery就是这么干的).因为相比而言,这样更简洁,并且更

javascript中原型,构造器,还有E5扩展的默认成员

对象原型所具有的基本特征:1.toString() 2.toLocaleString() 3.valueOf() 4.constructor() 5.propertyIsnumerable() 6.hasOwnProperty() 7.isPrototypeOf()构造器所具有的特殊成员1.call() 2.apply() 3.caller() 4.bind() 5.arguments [object] 6.length [number] 7.prototype [objcet] E5对于Obj

JavaScript中原型对象的彻底理解

一.什么是原型 原型是Javascript中的继承的继承,JavaScript的继承就是基于原型的继承. 1.1 函数的原型对象 ? 在JavaScript中,我们创建一个函数A(就是声明一个函数), 那么浏览器就会在内存中创建一个对象B,而且每个函数都默认会有一个属性 prototype 指向了这个对象( 即:prototype的属性的值是这个对象 ).这个对象B就是函数A的原型对象,简称函数的原型.这个原型对象B 默认会有一个属性 constructor 指向了这个函数A ( 意思就是说:c

javascript中原型(prototype)与原型链

javascript是一门动态语言(动态语言Dynamic Programming Language:动态类型语言,意思就是类型的检查是在运行时做的,也就是常说的“弱类型”语言),没有类的概念,有class保留字,但不能用作变量名 原型:Javascript中的每一个对象都有一个内部私有的连接指向另一个对象,这个对象就是原对象的原型 注意:原型是一个对象,其他对象可以通过他实现属性继承 原型链:这个原型对象也有自己的原型,直到对象的原型为null为止(也就是没有原型),这种一级一级的链结构就称为

javascript中原型链与instanceof 原理

instanceof:用来判断实例是否是属于某个对象,这个判断依据是什么呢? 首先,了解一下javascript中的原型继承的基础知识: javascript中的对象都有一个__proto__属性,这个是对象的隐式原型,指向该对象的原型对象.显式的原型对象使用prototype,但是Object.prototype.__proto__=null; 判断某个对象a是否属于某个类A的实例,可以通过搜索原型链. //继承机制 function A(){ } A.prototype.name='licu

JS中原型链的理解

在谈原型链之前,我们首先要了解自定义函数与 Function 之间是什么关系,而构造函数.原型和实例之间又存在什么千丝万缕的关系呢?其实,所有的函数都是 Function 的实例.在构造函数上都有一个原型属性 prototype,该属性也是一个对象:那么在原型对象上有一个 constructor 属性,该属性指向的就是构造函数:而实例对象上有一个 _proto_  属性,该属性也指向原型对象,并且该属性不是标准属性,不可以用在编程中,该属性用于浏览器内部使用. 1 // _proto_ 2 在函

JavaScript - javascript 中的 "||" 与 "&&" 的理解与灵活运

你肯定见到过这样的代码:a = a||"xxx". 它其实就等价于下面三种形式的代码: a = a || "xxx"; 与: if (!a) { a = "xxx"; } 和: if (a == null || a == "" || a == undefined) { a = "xxx"; } 如何理解三种代码.首先必须理解一个问题: javascript 中的数据类型在与bool类型转换时候发生了什么?

javascript对原型模式的理解

在javascript中每创建一个function,就会自动有一个prototype属性,这个属性是一个指针,指向原型对象,原型对象中的有个默认的constructor,这个constructor又指向了那个function