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

  理解原型对象

在Javascript中不管什么时候,仅仅要创建一个新的函数,就会依据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象(这个对象的用途是包括能够有特定类型的全部实例共享的属性和方法)。假设依照字面上的意思来理解。那么原型属性就是通过调用构造函数而创建的那个对象的实例的原型对象。

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

例如以下图

function Person(){
}

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

创建了自己定义的构造函数后。其原型对象默认仅仅会取得constructor属性,至于其它的方法。都是从Object继承而来的。

当中上图中Person.prototype .constructor指向Person.而通过这个构造函数,我们能够继续为原型对象加入其它的属性和方法。

例如以下图:

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvemxfamF5/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" >

上图的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
时间: 2024-12-23 05:24:52

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

对Javascript中原型的深入理解

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

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中的伪数组理解

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

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

JavaScript中原型对象的彻底理解

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

javascript对原型模式的理解

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

JavaScript中this关键字的理解

this是个什么鬼? this是JavaScript中的一个关键字,代表当前对象. this在那些情况下会指向谁?如下文. 一.调用全局变量(Global Variable) var x="我是全局变量呦"; function obj() { alert(this.x); } obj(); //我是全局变量呦 此时,this指向了全局变量x. 二.将this作为对象的方法来调用. function test() { alert(this.x); } var obj={}; obj.x=

JS中原型链的理解

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