js prototype深入理解及应用实例分析


Posted in Javascript onNovember 25, 2019

本文实例讲述了js prototype深入理解及应用。分享给大家供大家参考,具体如下:

上一篇讲了js的prototype概念,在这里回顾一下prototype的定义:

prototype是函数的一个属性,并且是函数的原型对象。引用它的必然是函数,这个应该记住。

但是,很奇怪,各位看官,你有没有看过类似下面这样引用prototype的js代码:

function func(){
  var args = Array.prototype.slice.call(arguments, 1);
  return args;
}

咦???看着上面这行代码,你是不是对prototype只是属于函数产生深深的怀疑呢?

你明白上面那个函数的意思吗?我还是解释一下吧。

call是函数的一个方法,关于这个方法,它也是只有····函数····才能够调用的,它的作用是:调用引用它的函数。

就拿这个Array.prototype.slice.call(arguments,1)来讲,这里面包含太多信息了,我一个个分析一下。

slice(start[,end])是js的一个原生数组函数,作用是获取数组中从start下标开始到end下标结束的元素。举个例子:

var arr1 = [2,3,'l',4,5,'j','i'];
alert(arr1.slice(1));//结束下标省略表示从开始下标截取到末尾
//这里alert的是3,'l',4,5,'j','i',你自己可以试一下

arguments是js函数对象的一个属性,作用是获取函数的实参,返回的是一个以函数实参为属性元素的对象。举个例子:

function args(){
  return this.arguments;//这里的this可以省略,你自己可以试一下
  //我加上是为了说明,调用arguments的只能是对象
}
alert(JSON.stringify(args(1,3,5,6,8)));
//返回的是{"0":"1","1":"3","2":"5","3":"6","4":"8"}

关于函数的对象属性arguments这里就讲这么多了,要详细理解,可以百度。

而Array是js中生成数组的关键字。

这里为什么要用Array.prototype来调用slice函数呢?而不用Array.slice,原因很简单,因为数组的关键字Array不能这样子Array.xx直接调用js的数组函数。但为什么不能直接这样调用呢?不急,下面我们来做实验,你就会很清楚了。

alert(Array.slice());
//Uncaught TypeError: Array.slice is not a function

这里直接给你报错了,说明了什么?呵呵,这说明Array关键字确实不能直接调用数组的函数。

alert(JSON.stringify(Array.prototype));
alert(JSON.stringify(Array.prototype.slice()));

这里返回都是空数组···[]···,说明了什么?说明了Array关键字确实是可以调用prototype函数的属性的,同时也说明js是可以这样子Array.prototype调用js的数组函数的。

说到这里,问题就来了,我上面不是说,prototype是js函数的一个属性,只能被函数调用吗?怎么这里Array关键字可以调用这个属性prototype呢?那么,我这不是坑自己对prototype的定义是错误的吗?我这不是给自己打脸吗?哎,看官,没错,你这里看到的都是正确的。可是,至于Array关键字可以调用函数的prototype属性,我有没有给自己打脸,这里,我们先别急得下结论。

转个弯说,看官是否还记得js生成数组的几种方式?应该有多种,但,我这里就不介绍了。

不过,你是否看过这样生成数组的方式?我们先来看下面的代码:

var arr = new Array();

这个方式生成数组还记得吧?那么,我们js的function是不是也可以像下面这样子生成对象呢?

function func(){
}
var obj = new func();

上面生成数组的方式和下面构造函数生成对象的方式是不是很相似?没错,js中function和Array都是可以通过new来生成对象这样的东西,这说明了什么呢?你看Array()和func()是不是很像?是不是最后面都有一对圆括号?是就对了,呵呵,说了这么多,我只是想揭露一样东西,这个东西就是,假如我猜的的没有错的话,Array()这个东西其实是js一个·····构造数组的内置函数····,不然,可以用new Array()的方式生存数组的方式就说不过去了是吧?

讲到这里,我们再返回来说js可以这样子Array.prototype调用prototype就很明白不过了是吧?Array()是js的一个内置函数,既然Array是一个函数,那么Array肯定拥有prototype这个属性对吧?所以说,Array关键字调用prototype并没有违反prototype是函数的一个属性这个原则,prototype是函数的一个属性依然是一个不变的结论。

关于Array生成数组的方式,类似的我们是否可以这样子new Object()生成对象,或者new String()这样子生成字符串?既然可以这样子构造对象和字符串,那么我们下面的代码也应该是可行的,对吧?

alert(JSON.stringify(String.prototype));
alert(JSON.stringify(Object.prototype));

根据上面的解释,你应该知道这里是可以执行的吧?你应该知道这里的之所以能执行的原理吧?你自己试试。这里就不再解释了。

讲到这里,哎,我既然把行文开始的那个函数给忘了?这里讲解一下本文开始那个func函数的作用:

func函数的作用就是,从第二个实参数开始获取func函数的实参。

我来给你分析一下:

function func(){
var args = Array.prototype.slice.call(arguments, 1);
return args;
}
alert(func(0,1,2,3,4));//给func函数传实参

Array.prototype是一个空数组,

Array.prototype.slice()的意思是一个空数组调用数组的函数slice(),

Array.prototype.slice.call()的意思是call函数调用数组的函数slice(),

这里call()怎么调用slice()呢?

是这样子的,Arguments获取func函数实参列表,生成一个对象传递给call()函数,call函数又把Arguments生成的对象传递给Array.prototype这个空数组,把第二个参数···1···传递给slice函数,然后,call就让引用它的函数slice执行slice(1),所以slice就从1下标开始获取数组的元素了,而这个数组的元素其实就是Arguments的元素,因此,这个函数func的作用就是获取下标为1开始的所有实参。不相信,你自己可以执行一下上面的函数。

下面讲讲prototype的应用:

应用1:

给原型对象增加函数,就是让对象拥有公用的函数。

例子:我给数组原型对象增加一个打乱数组方法:

//给数组原型增加一个打乱数组的函数
Array.prototype.shuffle=function(){
var value = this.valueOf(),len = this.length,temp,key;
while(len--){
//随机生成数组的下标
key = Math.floor(Math.random()*len);
//temp为中间交换变量
temp = value[key];
value[key] = value[len];
value[len] = temp;
}
return value;
}
var arr1 = [0,1,2,3,4,5,6,7,8,9];
var arr2 = ['a','b','c','d','e','f'];  
alert(JSON.stringify(arr1.shuffle()));
alert(JSON.stringify(arr2.shuffle()));

你可以尝试着再增加一个数组arr3看看它能不能调用shuffle函数,因为我这里是给Array的原型对象增加的函数,所以在这个脚本内,所有数组都拥有shuffle这个函数。

应用2:

给原型对象增加属性,也就是给对象增加公用的属性

例子:

function fun(){
}
fun.prototype.name = '小东';
fun.prototype.arr = [1,2,3,4];//这里的属性可以是数组,也可以是对象
var ob1 = new fun();
var ob2 = new fun();
alert(JSON.stringify(ob1.name));
alert(JSON.stringify(ob2.arr));

应用3:

实现原型继承;

function P1(){
}
function P2(){
}
//原型对象增加属性和方法
P2.prototype.name = 'P2"s name';
P2.prototype.get=function(value){
  return value;
}
//实例化P2构造函数的一个对象
var obp2 = new P2();//这个对象应该包含所有原型对象的属性和方法
//给P1的原型对象赋值一个对象,相当于P1继承了obp2的所有属性和方法
P1.prototype = obp2;//这个式子,简单来讲就类似于a = b, b赋值给a这个总该明白吧?
//调用P1从obp2继承过来的get函数
alert(P1.prototype.get('out"s name'));
//展示P1从obp2继承过来的name属性
alert(P1.prototype.name);
//用构造函数P1实例化一个obp1对象
var obp1 = new P1();
//P1的原型对象prototype既然已经继承了obp2的所有属性和函数,那么依据P1所实例化出来的对象也都有obp2的属性和函数了
alert(obp1.get('obp1"s name'));

关于prototype就讲到这里,假如本文有什么错误,还望各位看官指出,我好纠正。

特别指出:

  • Array.prototype是一个数组
  • String.prototype是一个字符串
  • Object.prototype是一个对象

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.3water.com/code/HtmlJsRun测试上述代码运行效果。

希望本文所述对大家JavaScript程序设计有所帮助。

Javascript 相关文章推荐
用正则表达式 动态创建/增加css style script 兼容IE firefox
Mar 10 Javascript
javascript关于open.window子页面执行完成后刷新父页面的问题分析
Apr 27 Javascript
Three.js基础学习之场景对象
Sep 27 Javascript
浅谈vue-cli 3.0.x 初体验
Apr 11 Javascript
Webpack devServer中的 proxy 实现跨域的解决
Jun 15 Javascript
Vue一次性简洁明了引入所有公共组件的方法
Nov 28 Javascript
ES6基础之数组和对象的拓展实例详解
Aug 22 Javascript
Vue列表循环从指定下标开始的多种解决方案
Apr 08 Javascript
JavaScript中作用域链的概念及用途讲解
Aug 06 Javascript
通过JS判断网页是否为手机打开
Oct 28 Javascript
vue3+typeScript穿梭框的实现示例
Dec 29 Vue.js
聊聊JS ES6中的解构
Apr 29 Javascript
KnockoutJS数组比较算法实例详解
Nov 25 #Javascript
js实现简单的日历显示效果函数示例
Nov 25 #Javascript
VUE.CLI4.0配置多页面入口的实现
Nov 25 #Javascript
用Golang运行JavaScript的实现示例
Nov 25 #Javascript
JS插入排序简单理解与实现方法分析
Nov 25 #Javascript
纯 JS 实现放大缩小拖拽功能(完整代码)
Nov 25 #Javascript
python实现迭代法求方程组的根过程解析
Nov 25 #Javascript
You might like
PHP 图片上传实现代码 带详细注释
2010/04/29 PHP
Notice: Undefined index: page in E:\PHP\test.php on line 14
2010/11/02 PHP
php设计模式 Builder(建造者模式)
2011/06/26 PHP
thinkPHP下的widget扩展用法实例分析
2015/12/26 PHP
php实现的rc4加密解密类定义与用法示例
2018/08/16 PHP
浅谈Laravel模板实体转义带来的坑
2019/10/22 PHP
几个比较经典常用的jQuery小技巧
2010/03/01 Javascript
jquery form表单提交插件asp.net后台中文解码
2010/06/12 Javascript
JavaScript实现点击单选按钮改变输入框中文本域内容的方法
2015/08/12 Javascript
用原生js做单页应用
2017/01/17 Javascript
ajax与json 获取数据并在前台使用简单实例
2017/01/19 Javascript
jQuery+pjax简单示例汇总
2017/04/21 jQuery
微信小程序实现列表下拉刷新上拉加载
2020/07/29 Javascript
node使用promise替代回调函数
2018/05/07 Javascript
MVVM 双向绑定的实现代码
2018/06/21 Javascript
JavaScript页面倒计时功能完整示例
2019/05/15 Javascript
Vue项目打包编译优化方案
2020/09/16 Javascript
Python中optparse模块使用浅析
2015/01/01 Python
Python中的filter()函数的用法
2015/04/27 Python
Python 模拟购物车的实例讲解
2017/09/11 Python
基于Pandas读取csv文件Error的总结
2018/06/15 Python
对python当中不在本路径的py文件的引用详解
2018/12/15 Python
PyCharm搭建Spark开发环境的实现步骤
2019/09/05 Python
Python高级编程之继承问题详解(super与mro)
2019/11/19 Python
使用python动态生成波形曲线的实现
2019/12/04 Python
Pytorch 多维数组运算过程的索引处理方式
2019/12/27 Python
在pycharm中为项目导入anacodna环境的操作方法
2020/02/12 Python
Python3+selenium配置常见报错解决方案
2020/08/28 Python
ffmpeg+Python实现B站MP4格式音频与视频的合并示例代码
2020/10/21 Python
Pandas的数据过滤实现
2021/01/15 Python
经贸日语专业个人求职信
2013/12/13 职场文书
毕业生就业自荐书
2013/12/15 职场文书
党支部遵守党的政治纪律情况对照检查材料
2014/09/26 职场文书
总账会计岗位职责
2015/04/02 职场文书
盘点2020年适合农村地区创业的项目
2019/10/16 职场文书
Elasticsearch Recovery 详细介绍
2022/04/19 Java/Android