最近在学习javaScript,学习到js面向对象中的原型时,感悟颇多。若有不对的地方,希望可以指正。

  js作为一门面向对象的语言,自然也拥有了继承这一概念,但js中没有类的概念,也就没有了类似于java中的extends,所以,我觉得js中的继承主要依赖于js中的原型(链)。

  那么,原型是什么呢?我们知道js中函数亦是一种对象,当我们创建一个函数时,其实这个函数也就默认的拥有了一个属性叫做prototype,这个属型叫做原型属性,他是一个指针,指向了这个函数的原型对象,这个原型对象有一个默认的属性叫做constructor,这个属型指向了拥有protptype属型的函数。

function Person(){}
Person.prototype={
     // constructor:Person;
first_name:"guo",
hair_color:"black",
city:"zhengzhou",
act:function(){alert("eatting");}
};

  以这个为例,我们先创建了一个函数Person,这个函数默认的有一个属性prototype,指向Person.propttype这个对象,这个对象有一个默认的属性constructor(),Person.prototype.constructor--->Person.(其实此处默认的是指向Object,后面会做指正)

  当我们通过构造函数创建了实例后会怎么样呢?

	function Person(){}
Person.prototype={
first_name:"guo",
hair_color:"black",
city:"zhengzhou",
act:function(){alert("eatting");}
};
var boy=new Person();
var girl=new Person();

  在这时,我们要知道,js中的构造函数与函数的区别便是这个new关键字,使用new操作符的函数便是一个构造函数。当我们创建了Person的实例对象把它保存在boy,girl时,这两个实例对象会生成一个默认的属性叫做_proto_(在ECMAScript5中可用[[prototype]]表示),这个属型指向了构造函数的原型对象,也就是boy._proto_--->Person.prototype(与构造函数毫无关系)。此时,boy或者girl可以通过点来调用原型对象中的属型,此时要知道,boy,girl共享了原型对象的属型。我们可以通过isProtptypeOf()或者object.getPrototypeOf()(这个函数的返回值为原型对象,也就是_proto_的值)来验证上述结论。

alert(Person.prototype.isPrototypeOf(boy));  //true
alert(Object.getPrototypeOf(boy).first_name); //"guo"

  此时,我们可以再做进一步验证,若在实例中创建了一个与原型对象属性重名的属性会怎么样呢?

                var boy=new Person();
var girl=new Person();
boy.hair_color="red";
alert(boy.hair_color); //red
alert(girl.hair_color); //black
alert(Object.getPrototypeOf(boy).hair_color); //black

  由此可见,实例中声明的重名属性会屏蔽的原型对象中的属性,但也仅仅时覆盖,不会对原型对象的属型造成影响(Object.getPrototypeOf(boy).hair_color==black),也不会对其他共享原型对象属型的实例对象产生影响(girl.hair_color==black)。与此同时,可以使用delete操作符删除实例对象声明的属性来撤销掉屏蔽效果。我们可以使用hasOwnProperty()来验证一个属型是存在于实例的(true),还是存在于原型对象的(false)。

alert(boy.hasOwnProperty("hair_color"));  //true

  可以使用Object.keys()来枚举属性。

var key=Object.keys(Person.prototype);
alert(key);

  学习了这些,我们会发现,使用上面的写法来声明原型对象会出现一个问题,constructor不再指向Person了,这与我们说的原型对象的constructor属性默认指向含有prototype属性的函数背道而驰,这是因为:每创建一个函数会自动创建一个prototype对象,这个对象会默认创建constructor。所以,此处我们的本质是对默认的prototype进行了重写,因此新的consrtuctor也变成了指向Object函数,不再指向Person函数。若constructor真的很重要,那么需要写上constructor:Person.

  之后,我们需要知道原型的动态性,改变原型对象中的属性会反应到实例中,不管实例的创建在原型对象的属型改变前面或者后面

                function Person(){}
Person.prototype={
first_name:"guo",
hair_color:"black",
city:"zhengzhou",
act:function(){alert("eatting");}
}; var boy=new Person();
Person.prototype.hobby="basketball";
var girl=new Person();
alert(boy.hobby); //basketball

  上面这段代码可见,即使对原型对象属性的修改发生在实例创建的后面,boy实例亦然共享了Person.prototype.hobby.

  但是,这种情况仅仅发生在原型对象属型的修改,当对原型对象属性进行完全重写时,实例的创建必须放在原型对象属性重写的后面,否则会出错。

function Person(){}
var girl=new Person();
Person.prototype={
first_name:"guo",
hair_color:"black",
city:"zhengzhou",
act:function(){alert("eatting");}
}; var boy=new Person();
Person.prototype.hobby="basketball"; alert(boy.hobby); //basketball
alert(girl.first_name); //undefined

  再回到“屏蔽”这一问题上,我们前面了解到了创建实例对象的属性(与原型对象中的某一属性重名)会屏蔽掉原型对象的该属性,但不影响其他实例对象。这里有一个错误,这个情况只适用于基本数据类型,当属性的值引用类型时,会出现一个大问题,看如下代码。

function Person(){}

        Person.prototype={
first_name:"guo",
hair_color:"black",
friends:["Nick","John"],
city:"zhengzhou",
act:function(){alert("eatting");}
}; var boy=new Person();
boy.friends.push("Mike");
var girl=new Person();
alert(boy.friends); //Nick,John,Mike
alert(girl.friends); //Nick,John,MIke

  可见,上面这句话不适用了,原因是friends是存在于原型对象中的,而不是boy中,所以他的修改会影响到这个环境。(我们可以通过boy.frindes=[]来创建一个boy实例的属性)那么,我们就需要引入组合使用构造函数模式与原型模式。

 

function Person(hair_color,city){

			this.hair_color=hair_color;
this.city=city;
this.friends=["John","Nick"];
}
Person.prototype={
constructor:Person,
first_name:"guo",
act:function() { alert("eatting");
}
};
var boy=new Person("black","zhengzhou");
var girl=new Person("red","shenyang");
boy.friends.push("Nick");
alert(girl.friends);
alert(boy.friends);

  该模式是目前ECMAScript中使用最广泛,认同最高的创建自定义类型的方法,甚至可以作为一种默认模式。

  但是对于从事其他面向对象语言的程序员来说,这样的模式显得很怪异,为了将所有的信息都封装到构造函数中,动态原型模式出现了。动态模式主要是通过一个if语句来判断是否需要对原型对象进行初始化,以达到节省资源的目的。

  此外还有稳妥构造模式,是为了适应没有共享属性和不使用this的情况。

    

 

javaScript中的原型的更多相关文章

  1. 【转】JavaScript中的原型和继承

    请在此暂时忘记之前学到的面向对象的一切知识.这里只需要考虑赛车的情况.是的,就是赛车. 最近我正在观看 24 Hours of Le Mans ,这是法国流行的一项赛事.最快的车被称为 Le Mans ...

  2. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  3. javascript中的原型继承

    在Javascript面向对象编程中,原型继承不仅是一个重点也是一个不容易掌握的点.在本文中,我们将对Javascript中的原型继承进行一些探索. 基本形式 我们先来看下面一段代码: <cod ...

  4. 图解JavaScript中的原型链

    转自:http://www.jianshu.com/p/a81692ad5b5d typeof obj 和 obj instanceof Type 在JavaScript中,我们经常用typeof o ...

  5. 前端知识体系:JavaScript基础-原型和原型链-理解原型设计模式以及 JavaScript中的原型规则

    理解原型设计模式以及 JavaScript中的原型规则(原文地址) 1.原型对象:我们创建的每一个函数(JavaScript中函数也是一个对象)都有一个原型属性 prototype,原型属性实质上是一 ...

  6. JavaScript中的原型、原型链、原型模式

    今天,咱来聊聊JavaScript中的原型跟原型链 原型跟原型模式 这一块的知识,主要是设计模式方面的. 首先,我们知道JavaScript是面向对象的.既然是面向对象,那它自然也有相应的类跟对象等概 ...

  7. 深入了解JavaScript中基于原型(prototype)的继承机制

    原型 前言 继承是面向对象编程中相当重要的一个概念,它对帮助代码复用起到了很大的作用. 正文 Brendan Eich在创建JavaScript时,没有选择当时最流行的类继承机制,而是借鉴Self,用 ...

  8. javascript中的原型和继承

    javascript一直是初学者口中的难点,甚至一些有些许工作经验的人也不太明白其中的原理,而我就是那个初学者,前段时间在阮一峰老师的博客上看了一篇文章<javascript继承机制的设计思想& ...

  9. JavaScript中的原型和对象机制

    1.对象相关的一些语言特性 JavaScript里所有的东西都是对象, 对象是属性的集合.要知道,函数也是对象, 能够作为变量的值. 返回值. 参数或者属性的值. 函数对象特殊的地方是能通过" ...

  10. 理解javascript中的原型模式

    一.为什么要用原型模式. 早期采用工厂模式或构造函数模式的缺点:  1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂 ...

随机推荐

  1. Maven解决Missing artifact com.sun:tools:jar:1.5.0错误

    <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> ...

  2. Hadoop学习之--Capaycity Scheduler配置参数说明

    以下列举出来的是capacity关于queue和user资源使用量相关的参数说明: mapred.capacity-scheduler.queue.xxx.capacity: 队列的资源容量百分比,所 ...

  3. HttpComponents 学习的两个重要文档

    httpcore-tutorial-simplified-chinese httpclient-tutorial-simplified-chinese

  4. erlang局域网内节点通信——艰难四步曲 (转)

    http://blog.chinaunix.net/uid-22566367-id-382011.html 在Programming Erlang这本书中,在写到第十章中,主要实现的是不同节点之间的通 ...

  5. 安卓app开发方式之webApp

    1.phonegap: 专注于webapp调用native的功能.2.ionic: 专注于webapp的前端ui技术,需要与phonegap(准确的说是和Cordova配合使用).ionic是一个专注 ...

  6. 微服务架构下分布式Session管理

    转载本文需注明出处:EAII企业架构创新研究院(微信号:eaworld),违者必究.如需加入微信群参与微课堂.架构设计与讨论直播请直接回复此公众号:“加群 姓名 公司 职位 微信号”. 一.应用架构变 ...

  7. jquery easyui的layout

    1.创建一个布局:layout是一个容器,它有5个区域:north(北),south(南),east(东),west(西):center(中)-----------学习中文网地址 <body c ...

  8. BestCoder Round #71 (div.2) (hdu 5620 菲波那切数列变形)

    KK's Steel Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total ...

  9. Linux使用locate命令定位文件

    FIND命令 很多Linux用户喜欢使用find命令来查找文件,例如他们通常喜欢这样做: find / -name 'pattern' 确实find的强大功能不仅仅用来查找文件,它能用来定位更加细节的 ...

  10. Lua学习笔记(二):基本语法

    Lua学习指南:http://www.lua.org/manual/ 首先我们要明确的一点是:在Lua中,除了关键字外一切都是变量. Lua关键字 可以查看这个地址:http://www.lua.or ...