JavaScript 原型链学习(三)原型对象存在的问题 与 组合使用构造函数和原型

原型对象也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节, 结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便, 但还不是原型对象的最大问题。原型对象的最大问题是由其共享的本性所导致的。
原型中所有属性是被很多实例共享的,这种共享对于函数非常合适。对于那些包含基本值的属性倒也说得过去,毕竟(如前面的例子所示),通过在实例上添加个同名属性, 可以隐藏原型中的对应属性。然而,对于包含引用类型值的属性来说,问题就比较突出了。来看下面的例子。

function Person() {}

Person.prototype={
    constructor: Person,
    name : "Nicholas" ,
    age : 29,
    job : "Software Engineer",
    friends : ["Shelby", "Court"] ,
    sayName : function (){
        alert(this.name ) ;
    }
};

var person1 = new Person();
var person2 = new Person();

person1.friends.push("Van");

alert(person1.friends);    //”Shelby, Court, Van"
alert(person2.friends);    //”Shelby, Court, Van"
alert(person1.friends === person2.friends);     //true    

在此,Person.prototype对象有一个名为frends的属性,该属性包含一个字符串数组。然后,创建了Person的两个实例。接着修改了person1.friends引用的数组,向数组中添加了一个字符串。由于friends数组存在于Person.prototype而非person1中,所以刚刚的修改也会通过person2.friends(与person1.friends指向同一个数组)反应出来。假如我们的初衷就是像这样在所有实例中共享一个数组,那就没什么好说的。可是,实例一般都是要有属于自己的全部属性的。而这个问题正是我们很少看到有人单独使用原型的原因。

创建自定义类型的最常见方式,就是组合使用构造函数与原型。构造函数用于定义实例属性,而原型用于定义方法和共享的属性。结果,每个实例都会有自己的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。下面的代码重写了前面的例子。

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ["Shelby","Court"];
}

Person.prototype = {
    constructor : Person,
    sayName : function() {
        alert(this.name);
    }
}

var person1 = new Person("Nicholas", 29,"Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

person1.friends.push ("Van");
alert(person1.friends);    //"Shelby, Count ,Van"
alert(person2.friends);    //"She1 by,Count"
alert(person1.friends === person2.friends);    //false
alert(person1.sayName === person2.sayName);    //true

在这个例子中,实例属性都是在构造函数中定义的,而由所有实例共享的属性constructor和方法sayName()则是在原型中定义的。而修改了person1.friends (向其中添加一个新字符串),并不会影响到person2.friends,因为它们分别引用了不同的数组。
这种构造函数与原型混成的模式,是目前在ECMAScript中使用最广泛、认同度最高的一种创建自定义类型的方法。可以说,这是用来定义引用类型的一种默认模式。

原文地址:https://www.cnblogs.com/weiyalin/p/9416582.html

时间: 2024-11-10 14:06:48

JavaScript 原型链学习(三)原型对象存在的问题 与 组合使用构造函数和原型的相关文章

javascript原型原型链 学习随笔

理解原型和原型链.需从构造函数.__proto__属性(IE11以下这个属性是undefined,请使用chrome调试).prototype属性入手. JS内置的好多函数,这些函数又被叫做构造函数.如:Object---Array---Function---Math---Date---String---Number---Boolean---Symbol---RegExp. JS里,所有的对象,都是其构造函数的实例.如{}是Object的一个实例,[]是Array的一个实例.fn() {}是Fu

nodejs学习三 process对象

rocess对象,我说的是对象.这个对象包含的方法和属性非常的多,它向我们打开了一个通往Node.js的大门,让我们队Node.js有更多的了解. 你知道安装的Node.js的版本吗? 你知道你的Node安装在上面平台下吗? 你知道你的Node可执行文件的绝对路径吗? 你想得到你env环境变量内容吗? 上面输入的信息你可以更具体点,比如console.log(process.env.OS) 你想得到命令行上的参数吗? 好了,下面我们来写一个js.命名process.js 在命令行上运行它: 我们

JavaScript 原型链学习(一)原型对象

在JavaScript中创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有的实例共享的属性和方法.如果按照字面意思来理解,那么prototype就是通过调用构造函数而创建那个实例的原型对象.使用原型对象的好处是可以让所有对象实例共享它所包含的属性和方法.换句话说,不必在构造函数中定义对象实例的信息,而是可以将这些信息直接添加到原型对象中,如下例所示: function Person(){} Person.protot

JavaScript原型与原型链学习笔记

一.什么是原型?原型是一个对象,其他对象可以通过它实现属性继承.简单的说就是任何一个对象都可以成为原型 prototype属性: 我们创建的每个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,而这个对象包含可以有特定类型的所有实例共享的属性和方法.这个对象就是原型对象(也就是某个对象的原型所引用的对象).1.总之只要创建了函数,该函数都有一个prototype属性,指向函数的原型对象. 如上图,Person是一个函数,右侧的方框就是它的原型. 2.默认情况下所有原型对象都会

JavaScript原型链学习

function foo(){} foo.prototype.z = 3; var obj = new foo(); obj.y = 2; obj.x = 1; obj.x; //1 obj.y; //2 obj.z; //3 typeof obj.toString; //'function' 'z' in obj; //true obj.hasOwnProperty('z'); //false 首先,我们通过function foo()去定义一个函数对象..那么,foo()对象自动带有prot

JavaScript之面向对象学习五(JS原生引用类型Array、Object、String等等)的原型对象介绍

1.原型模式的重要性不仅仅体现在创建自定义类型方面,就连所有的原生的引用类型(Obejct.Array.String等等)都在构造函数的原型上定义方法和属性.如下代码可以证明: alert(typeof Array.prototype.sort); //输出:function alert(typeof String.prototype.substring); //输出:function 通过原生对象的原型,不仅可以取得所有默认方法的引用,而且可以定义新的方法.可以想修改自己定义对象的原型一样修改

原型原型链学习记录

这是一篇学习笔记. 个人心得: 关于原型和原型链这一块,很难,但是,一旦理解,就通了. 对于这一块,我之前不懂的时候,非要去弄明白,特别痛苦,之后,看到了王福朋老师的闭包原型系列,真的是茅塞顿开!看完之后,我就拿起JavaScript高程3,高程3第6章节,耐心跟着看也就明白了.之后,再去做一些图解,如果能够根据继承画出所有的关系,没有矛盾的点,那就基本没问题了.再到网上找差不多的文章看,如果没有冲突点,那这一块就没问题了. 参考的内容: http://www.cnblogs.com/wangf

原型与原型链(三)

七. 函数对象 (复习一下前面的知识点) 所有函数对象的proto都指向Function.prototype,它是一个空函数(Empty function) Number.__proto__ === Function.prototype // true Number.constructor == Function //true Boolean.__proto__ === Function.prototype // true Boolean.constructor == Function //tr

方法链、作用域链和原型链(三)——原型链

每一个javascript对象(null除外)都有一个prototype属性,这个属性引用了一个对象,即原型对象,都从原型继承属性. 所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过javascript代码Object.prototype获得对原型对象的引用.通过关键字new和构造函数调用创建的对象的原型就是构造函数的prototype属性的值.因此,使用{}和通过new Object()创建的对象,都继承自Object.prototype. 没有原型的对象不多,Object.pro