本文实例讲述了 JavaScript 原型对象, 构造函数和实例对象功能与用法. 分享给大家供大家参考, 具体如下:
大家都知道, javascript 中其实并没有类的概念. 但是, 用构造函数跟原型对象却可以模拟类的实现. 在这里, 就先很不严谨的使用类这个词, 以方便说明.
下面整理了一些关于 javascript 的构造函数, 原型对象以及实例对象的笔记, 有错误的地方, 望指正.
先用一张图简单的概括下这几者之间的关系, 再细化:
构造函数和实例对象
构造函数是类的外在表现, 构造函数的名字通常用作类名.
其实构造函数也就是一个函数, 只不过它于普通的函数又有点不同:
没有显示的创建对象;
直接将属性和方法赋给 this;
没有 return 语句;
构造函数是用来构造新对象的. 之前的笔记中有提到过, 可以是用 new 关键词来调用构造函数, 以创建特定类型的新对象. 如, 创建一个 Object 类型的对象实例:
var o=new Object();
为了区别构造函数和普通函数, 通常规定构造函数的命名首字母大写, 而普通函数的命名首字母小写. 当然, 这不是必须的, 却是一个很好的习惯.
通过用构造函数创建并初始化的属性是实例属性. 所谓的实例属性就是指, 通过该构造函数创建的每个对象, 都将拥有一份实例属性的单独拷贝. 这些属性都是通过实例来访问的, 值根据每个实例所定义的为准, 若实例中没有定义, 则为构造函数初始化时的默认值. 来看一个例子:
- function Person(name,age){
- this.name=name;
- this.age=age;
- this.friends=["Tom","Boo"];
- }
- var p1=new Person("Lily",20);
- var p2=new Person("Sam",30);
- alert(p1.name); //Lily
- alert(p2.name); //Sam
- p1.friends.push("Susan");
- alert(p1.friends); //Tom,Boo,Susan
- alert(p2.friends); //Tom,Boo
上面的例子定义了一个 Person 构造函数, 并初始化了 name,age 和 friends 三个属性. 接着创建了两个实例对象, 分别为 p1 和 p2. 观察这个例子, 每个属性都是为各自所拥有的, 并不会相互影响. 这就是因为每个实例对象都拥有一份属性的副本.
每个实例对象都有一个属性指向它的构造函数, 这属性就是 constructor:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- var p1=new Person("Lily",20);
- var p2=new Person("Sam",30);
- alert(p1.constructor==Person); //true
- alert(p2.constructor==Person); //true
构造函数有一个 prototype 属性, 指向原型对象.
原型对象和实例对象
在 javascript 中, 每个对象都有一个与之相关联的对象, 那就是它的原型对象. 类的所有实例对象都从它的原型对象上继承属性.
原型对象是类的唯一标识: 当且仅当两个对象继承自同一个原型对象时, 它们才是属于同一个类的实例.
前面有提到, 构造函数拥有一个 prototype 属性, 指向原型. 换句话来说, 一个对象的原型就是它的构造函数的 prototype 属性的值. 当一个函数被定义的时候, 它会自动创建和初始化 prototype 值, 它是一个对象, 这时这个对象只有一个属性, 那就是 constructor, 它指回和原型相关联的那个构造函数. 看个例子:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- alert(Person.prototype); //[object Object]
- alert(Person.prototype.constructor==Person); //true
也可以通过原型来创建属性和方法. 通过原型创建的属性和方法是被所有实例所共享的. 即, 在一个实例中修改了该属性或方法的值, 那么所有其他实例的属性或方法值都会受到影响:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- Person.prototype.friends=["Tom","Sam"];
- var p1=new Person("Lily",24);
- var p2=new Person("Susan",20);
- alert(p1.friends); //Tom,Sam
- alert(p2.friends); //Tom,Sam
- p1.friends.push("Bill");
- alert(p1.friends); //Tom,Sam,Bill
- alert(p2.friends); //Tom,Sam,Bill
由上面的例子可以看出, 用原型定义的属性是被所有实例共享的. 为 p1 添加了一个朋友, 导致 p2 也添加了这个朋友.
其实, 很多情况下, 这种现象并不是我们想看到的. 那么什么时候应该用构造函数初始化属性和方法, 哪些时候又该由原型对象来定义呢?
通常建议在构造函数内定义一般成员, 即它的值在每个实例中都将不同, 尤其是对象或数组形式的值; 而在原型对象中则定义一些所有实例所共享的属性, 即在所有实例中, 它的值可以是相同的属性.
当用构造函数创建一个实例时, 实例的内部也包含了一个指针, 指向构造函数的原型对象. 一些浏览器中, 支持一个属性__proto__来表示这个内部指针:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- Person.prototype.sayName=function(){
- alert(this.name);
- }
- var p1=new Person("Lily",24);
- alert(p1.__proto__.sayName); //function (){alert(this.name);}
- alert(p1.__proto__.constructor==Person); //true
在 ECMAscript5 中新增了一个方法,
Object.getPrototypeOf()
, 可以返回前面提到的实例对象内部的指向其原型的指针的值:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- var p1=new Person("Lily",24);
- alert(Object.getPrototypeOf(p1)==Person.prototype); //true
isPrototypeOf()方法也可用于确定实例对象和其原型之间的这种关系:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- var p1=new Person("Lily",24);
- alert(Person.prototype.isPrototypeOf(p1)); //true
原型语法
从前面介绍原型对象于实例对象及构造函数的关系中, 我们已经知道, 给原型对象添加属性和方法只要像这样定义即可:
- Person.prototype=name
- .
那么是否每定义一个 Person 的属性, 就要敲一遍 Person.prototype 呢? 答案是否定的, 我们也可以像用对象字面量创建对象那样来创建原型对象:
- function Person(){
- }
- Person.prototype={
- name:"Tom",
- age:29
- }
- var p1=new Person();
- alert(p1.name); //Tom
- alert(p1.age); //29
有一点要注意, 这个方法相当于重写了整个原型对象, 因此切断了它与构造函数的关系, 此时
Person.prototype.constructor
不再指向 Person:
- function Person(){
- }
- Person.prototype={
- name:"Tom",
- age:29
- }
- var p1=new Person();
- alert(Person.prototype.constructor==Person); //false
- alert(Person.prototype.constructor==Object); //true
因此, 如果想要让它重新指向 Person, 可以显示的进行赋值:
- function Person(){
- }
- Person.prototype={
- constructor:Person,
- name:"Tom",
- age:29
- }
- var p1=new Person();
- alert(Person.prototype.constructor==Person); //true
- alert(Person.prototype.constructor==Object); //false
总结
最后, 我们拿一个例子, 再来理理构造函数, 原型对象以及实例对象之间的关系:
- function Person(name,age){
- this.name=name;
- this.age=age;
- }
- Person.prototype.sayName=function(){
- alert(this.name);
- }
- var p1=new Person("Tom",20);
- alert(Person.prototype); //object
- alert(Person.prototype.constructor==Person); //true
- alert(p1.constructor==Person); //true
- alert(p1.__proto__==Person.prototype); //true
- alert(p1.__proto__.__proto__==Object.prototype); //true
- alert(p1.__proto__.__proto__.constructor==Object); //true
- alert(Person.constructor==Function); //true
- alert(Object.prototype.constructor==Object);
上图说明了这个例子中原型, 构造函数和实例属性的关系.
更多关于 JavaScript 相关内容感兴趣的读者可查看本站专题:javascript 面向对象入门教程,JavaScript 常用函数技巧汇总,JavaScript 错误与调试技巧总结,JavaScript 数据结构与算法技巧总结,JavaScript 遍历算法与技巧总结及JavaScript 数学运算用法总结
来源: http://www.jb51.net/article/145062.htm