JavaScript prototype属性详解


Posted in Javascript onOctober 25, 2016

每个函数都有一个prototype属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用new操作符调用)的时候,新创建的对象会从原型对象上继承属性和方法。

私有变量、函数
在具体说prototype前说几个相关的东东,可以更好的理解prototype的设计意图。之前写的一篇JavaScript 命名空间博客提到过JavaScript的函数作用域,在函数内定义的变量和函数如果不对外提供接口,那么外部将无法访问到,也就是变为私有变量和私有函数。

function Obj(){
    var a=0; //私有变量
    var fn=function(){ //私有函数
     
    }
   }

这样在函数对象Obj外部无法访问变量a和函数fn,它们就变成私有的,只能在Obj内部使用,即使是函数Obj的实例仍然无法访问这些变量和函数

var o=new Obj();
   console.log(o.a); //undefined
   console.log(o.fn); //undefined

静态变量、函数

当定义一个函数后通过 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数,用过Java、C#的同学很好理解静态的含义。

function Obj(){
    
   }
   
   Obj.a=0; //静态变量
   
   Obj.fn=function(){ //静态函数
     
   }
   
   console.log(Obj.a); //0
   console.log(typeof Obj.fn); //function
   
   var o=new Obj();
   console.log(o.a); //undefined
   console.log(typeof o.fn); //undefined

实例变量、函数

在面向对象编程中除了一些库函数我们还是希望在对象定义的时候同时定义一些属性和方法,实例化后可以访问,JavaScript也能做到这样

function Obj(){
    this.a=[]; //实例变量
    this.fn=function(){ //实例方法
     
    }
   }
   
   console.log(typeof Obj.a); //undefined
   console.log(typeof Obj.fn); //undefined
   
   var o=new Obj();
   console.log(typeof o.a); //object
   console.log(typeof o.fn); //function

这样可以达到上述目的,然而

function Obj(){
    this.a=[]; //实例变量
    this.fn=function(){ //实例方法
     
    }
   }
   
   var o1=new Obj();
   o1.a.push(1);
   o1.fn={};
   console.log(o1.a); //[1]
   console.log(typeof o1.fn); //object
   var o2=new Obj();
   console.log(o2.a); //[]
   console.log(typeof o2.fn); //function

上面的代码运行结果完全符合预期,但同时也说明一个问题,在o1中修改了a和fn,而在o2中没有改变,由于数组和函数都是对象,是引用类型,这就说明o1中的属性和方法与o2中的属性与方法虽然同名但却不是一个引用,而是对Obj对象定义的属性和方法的一个复制。

这个对属性来说没有什么问题,但是对于方法来说问题就很大了,因为方法都是在做完全一样的功能,但是却又两份复制,如果一个函数对象有上千和实例方法,那么它的每个实例都要保持一份上千个方法的复制,这显然是不科学的,这可肿么办呢,prototype应运而生。

prototype

无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,默认情况下prototype属性会默认获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针,有些绕了啊,写代码、上图!

function Person(){
    
   }

JavaScript prototype属性详解

根据上图可以看出Person对象会自动获得prototyp属性,而prototype也是一个对象,会自动获得一个constructor属性,该属性正是指向Person对象。

当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(很多浏览器这个指针名字为__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。

function Person(name){
    this.name=name;
   }
   
   Person.prototype.printName=function(){
    alert(this.name);
   }
   
   var person1=new Person('Byron');
   var person2=new Person('Frank');

JavaScript prototype属性详解 

Person的实例person1中包含了name属性,同时自动生成一个__proto__属性,该属性指向Person的prototype,可以访问到prototype内定义的printName方法,大概就是这个样子的

JavaScript prototype属性详解

写段程序测试一下看看prototype内属性、方法是能够共享

function Person(name){
    this.name=name;
   }
   
   Person.prototype.share=[];
   
   Person.prototype.printName=function(){
    alert(this.name);
   }
   
   var person1=new Person('Byron');
   var person2=new Person('Frank');
   
   person1.share.push(1);
   person2.share.push(2);
   console.log(person2.share); //[1,2]

果不其然!实际上当代码读取某个对象的某个属性的时候,都会执行一遍搜索,目标是具有给定名字的属性,搜索首先从对象实例开始,如果在实例中找到该属性则返回,如果没有则查找prototype,如果还是没有找到则继续递归prototype的prototype对象,直到找到为止,如果递归到object仍然没有则返回错误。同样道理如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。

function Person(name){
    this.name=name;
   }
   
   Person.prototype.share=[];

   var person=new Person('Byron');
   person.share=0;
   
   console.log(person.share); //0而不是prototype中的[]

构造简单对象

当然prototype不是专门为解决上面问题而定义的,但是却解决了上面问题。了解了这些知识就可以构建一个科学些的、复用率高的对象,如果希望实例对象的属性或函数则定义到prototype中,如果希望每个实例单独拥有的属性或方法则定义到this中,可以通过构造函数传递实例化参数。

function Person(name){
    this.name=name;
   }
   
   Person.prototype.share=[];
   
   Person.prototype.printName=function(){
    alert(this.name);
   }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于JQuery实现CheckBox全选全不选
Jun 27 Javascript
在jquery中combobox多选的不兼容问题总结
Dec 24 Javascript
删除条目时弹出的确认对话框
Jun 05 Javascript
KnockoutJS 3.X API 第四章之数据控制流foreach绑定
Oct 10 Javascript
Bootstrap图片轮播组件Carousel使用方法详解
Oct 20 Javascript
jQuery模拟实现的select点击选择效果【附demo源码下载】
Nov 09 Javascript
轻松理解JavaScript之AJAX
Mar 15 Javascript
JavaScript实现二叉树的先序、中序及后序遍历方法详解
Oct 26 Javascript
关于vue中的ajax请求和axios包问题
Apr 19 Javascript
使用VScode 插件debugger for chrome 调试react源码的方法
Sep 13 Javascript
解决vue.js中settimeout遇到的问题(时间参数短效果不稳定)
Jul 21 Javascript
js实现鼠标拖曳效果
Dec 30 Javascript
对Angular.js Controller如何进行单元测试
Oct 25 #Javascript
jstree创建无限分级树的方法【基于ajax动态创建子节点】
Oct 25 #Javascript
input file上传 图片预览功能实例代码
Oct 25 #Javascript
Node.js开启Https的实践详解
Oct 25 #Javascript
Json对象和字符串互相转换json数据拼接和JSON使用方式详细介绍(小结)
Oct 25 #Javascript
利用yarn实现一个webpack+react种子
Oct 25 #Javascript
Yarn的安装与使用详细介绍
Oct 25 #Javascript
You might like
双料怀旧--SHARP GF515的维护、修理和简单调试
2021/03/02 无线电
php中json_encode UTF-8中文乱码的更好解决方法
2014/09/28 PHP
php修改文件上传限制方法汇总
2015/04/07 PHP
php实现网页缓存的工具类分享
2015/07/14 PHP
PHP+Ajax实现验证码的实时验证
2016/07/20 PHP
php中bind_param()函数用法分析
2017/03/28 PHP
通过 Dom 方法提高 innerHTML 性能
2008/03/26 Javascript
jquery和javascript的区别(常用方法比较)
2013/07/04 Javascript
JavaScript中的值类型详细介绍
2014/12/29 Javascript
Javascript removeChild()删除节点及删除子节点的方法
2015/12/27 Javascript
javascript字符串对象常用api函数小结(连接,替换,分割,转换等)
2016/09/20 Javascript
javascript对浅拷贝和深拷贝的详解
2016/10/14 Javascript
移动端日期插件Mobiscroll.js使用详解
2016/12/19 Javascript
利用jquery禁止外层滚动条的滚动
2017/01/05 Javascript
浅谈JS验证表单文本域输入空格的问题
2017/02/14 Javascript
基于JavaScript实现焦点图轮播效果
2017/03/27 Javascript
Javascript中toFixed计算错误(依赖银行家舍入法的缺陷)解决方法
2017/08/22 Javascript
原生JS实现 MUI导航栏透明渐变效果
2017/11/07 Javascript
jQuery实现table表格信息的展开和缩小功能示例
2018/07/21 jQuery
Vue项目服务器部署之子目录部署方法
2019/05/12 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
JS+CSS实现炫酷光感效果
2020/09/05 Javascript
Vue中inheritAttrs的使用实例详解
2020/12/31 Vue.js
python实现连接mongodb的方法
2015/05/08 Python
Pycharm学习教程(2) 代码风格
2017/05/02 Python
TensorFlow实现随机训练和批量训练的方法
2018/04/28 Python
python安装scipy的方法步骤
2019/06/26 Python
python 中不同包 类 方法 之间的调用详解
2020/03/09 Python
Django DRF认证组件流程实现原理详解
2020/08/17 Python
俄罗斯奢侈品牌衣服、鞋子和配饰的在线商店:INTERMODA
2020/07/17 全球购物
德国苹果商店:MacTrade
2020/05/18 全球购物
小米官方旗舰店:Xiaomi
2020/08/07 全球购物
教师绩效考核方案
2014/01/21 职场文书
归元寺导游词
2015/02/06 职场文书
Mac M1安装mnmp (Mac+Nginx+MySQL+PHP) 开发环境
2021/03/29 PHP
MySQL中使用or、in与union all在查询命令下的效率对比
2021/05/26 MySQL