javaScript中的原型解析【推荐】


Posted in Javascript onMay 05, 2016

最近在学习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中的原型解析【推荐】就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
prototype 的说明 js类
Sep 07 Javascript
jQuery checkbox全选/取消全选实现代码
Nov 14 Javascript
JavaScript 学习历程和心得分享
Dec 12 Javascript
JS将所有对象s的属性复制给对象r(原生js+jquery)
Jan 25 Javascript
关于事件mouseover ,mouseout ,mouseenter,mouseleave的区别
Oct 12 Javascript
JavaScript ES6的新特性使用新方法定义Class
Jun 28 Javascript
简单几步实现返回顶部效果
Dec 05 Javascript
微信小程序开发之map地图实现教程
Jun 08 Javascript
基于vue实现可搜索下拉框定制组件
Mar 26 Javascript
VUE在for循环里面根据内容值动态的加入class值的方法
Aug 12 Javascript
Vue.js样式动态绑定实现小结
Jan 24 Javascript
JavaScript判断数组类型的方法
Oct 23 Javascript
实例讲解JavaScript的Backbone.js框架中的View视图
May 05 #Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
May 05 #Javascript
详解Backbone.js框架中的模型Model与其集合collection
May 05 #Javascript
基于jQuery实现动态搜索显示功能
May 05 #Javascript
jQuery插件ajaxfileupload.js实现上传文件
Oct 23 #Javascript
jQuery插件AjaxFileUpload实现ajax文件上传
May 05 #Javascript
js ajaxfileupload.js上传报错的解决方法
May 05 #Javascript
You might like
一个没有MYSQL数据库支持的简易留言本的编写
2006/10/09 PHP
javascript之ESC(第二类混淆)
2007/05/06 Javascript
JavaScript中两个感叹号的作用说明
2011/12/28 Javascript
20个最新的jQuery插件
2012/01/13 Javascript
js实现拖拽 闭包函数详细介绍
2012/11/25 Javascript
js如何获取object类型里的键值
2014/02/18 Javascript
jquery库或JS文件在eclipse下报错问题解决方法
2014/04/17 Javascript
jquery文本框中的事件应用以输入邮箱为例
2014/05/06 Javascript
node.js中的http.createServer方法使用说明
2014/12/14 Javascript
12种JavaScript常用的MVC框架比较分析
2015/11/16 Javascript
JavaScript实现移动端滑动选择日期功能
2016/06/21 Javascript
bootstrap制作jsp页面(根据值让table显示选中)
2017/01/05 Javascript
BootStrap实现带关闭按钮功能
2017/02/15 Javascript
解决在layer.open中使用时间控件laydate失败的问题
2019/09/11 Javascript
[40:05]DOTA2上海特级锦标赛A组小组赛#1 EHOME VS MVP.Phx第一局
2016/02/25 DOTA
[01:19:23]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第二场
2018/04/06 DOTA
python通过post提交数据的方法
2015/05/06 Python
Python编程实现两个文件夹里文件的对比功能示例【包含内容的对比】
2017/06/20 Python
python在文本开头插入一行的实例
2018/05/02 Python
Python学习小技巧总结
2018/06/10 Python
python安装pywin32clipboard的操作方法
2019/01/24 Python
pyqt5移动鼠标显示坐标的方法
2019/06/21 Python
Python几种常见算法汇总
2020/06/02 Python
利用pipenv和pyenv管理多个相互独立的Python虚拟开发环境
2020/11/01 Python
英国著名的化妆品折扣网站:Allbeauty.com
2016/07/21 全球购物
化石印度尼西亚在线商店:Fossil Indonesia
2019/03/11 全球购物
澳大利亚美容产品及化妆品在线:Activeskin
2020/06/03 全球购物
写给女生的道歉信
2014/01/14 职场文书
公司成本主管岗位责任制
2014/02/21 职场文书
《记金华的双龙洞》教学反思
2014/04/19 职场文书
战友聚会策划方案
2014/06/13 职场文书
房产协议书范本2014
2014/09/30 职场文书
上下班时间调整通知
2015/04/23 职场文书
诺贝尔奖获得者名言100句:句句启人心智,值永久收藏
2019/08/09 职场文书
vue中三级导航的菜单权限控制
2021/03/31 Vue.js
高性能跳频抗干扰宽带自组网电台
2022/02/18 无线电