深入理解js的prototype以及prototype的一些应

2020-05-20 22:27:11

参考地址 深入理解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是一个对象



  • 2018-12-04 15:30:01

    如何在Mac OS X上安装 Ruby运行环境

    ​ 对于新入门的开发者,如何安装 Ruby和Ruby Gems 的运行环境可能会是个问题,本页主要介绍如何用一条靠谱的路子快速安装 Ruby 开发环境。 此安装方法同样适用于产品环境!

  • 2018-12-04 15:31:15

    iOS--Pod install && Pod update

    许多人在最初接触CocoaPods时认为pod install只是在第一次为项目设置CocoaPods时使用,之后都应该使用pod update.看起来是这样,但也不是(But that's not the case at all.)。 这篇文章的目的就是教你啥时候用pod install,啥时候用pod update

  • 2018-12-04 15:33:19

    CocoaPods安装和使用教程

    当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等。可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而其他类库又用到其他类库,“子子孙孙无穷尽也”,这也许是比较特殊的情况。总之小编的意思就是,手动一个个去下载所需类库十分麻烦。另外一种常见情况是,你项目中用到的类库有更新,你必须得重新下载新版本,重新加入到项目中,十分麻烦。如果能有什么工具能解决这些恼人的问题,那将“善莫大焉”。所以,你需要 CocoaPods。

  • 2018-12-04 23:37:37

    pod install 和 pod update

    当我们新建一个Podfile文件运行后,会自动生成一个Podfile.lock文件,Podfile.lock文件里存储着我们已经安装的依赖库(pods)的版本。 当我们第一次运行Podfile时,如果对依赖库不指定版本的话,cocoapods会安装最新的版本,同时将pods的版本记录在Podfile.lock文件中。这个文件会保持对每个pod已安装版本的跟踪,并且锁定这些版本。

  • 2018-12-04 23:40:26

    pod删除已导入的第三方库和移除项目中的cocoapods

    CocoaPods是一个负责管理iOS项目中第三方开源库的工具。CocoaPods的项目源码在Github上管理。在我们有了CocoaPods这个工具之后,只需要将用到的第三方开源库放到一个名为Podfile的文件中,然后在命令行执行$ pod install命令。CocoaPods就会自动将这些第三方开源库的源码下载下来,并且为我的工程设置好相应的系统依赖和编译参数. 但是如果我们导入的某个第三方不适用,或者我们又不想使用该第三方,那我们又该如何将这些相关的东西从我们的项目中清理出去呢?

  • 2018-12-04 23:41:47

    制作自己的Pod库(公有/私有)

    目的:1.管理自己常用的类;2.组件化开发步骤:1.想一个比较酷的名字,在桌面简历文件夹。2.打开terminal,cd到这个文件夹下面,执行pod lib create  xxx(这里我们以JJCategoryKit为例子,下同)命令,如下图。这个过程会问几个问题,根据实际情况输入回答即可。这里我们选择添加demo,结束的时候会自动Lanuch这个app. 作者:深水日月 链接:https://www.jianshu.com/p/ece0b5721461 來源:简书 简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 2018-12-05 06:08:26

    CocoaPods建立私有仓库 spec repo

    好多项目里都有公共的组件,copy来,copy去很容易出错,而且不容易维护,所以就想到用用cocoapods 建自己的私有库,Carthage用法虽然相对简单,但是它是把公共组件都放在framework里不容易单步调试,所以我还是选择用Cocoapods 来建立私有仓库 参考使用Cocoapods创建私有podspec

  • 2018-12-05 15:11:18

    为什么 Objective-C非常难

    作为一个Objective-C的coder,我总能听到一部 分人在这门语言上抱怨有很多问题。他们总在想快速学习这门语言来写一个App出来,但他们也总是联想到Objective-C看上去实在太难了或者在想这 些语法符号都是神马玩意?不错,他们问得非常好,所以本人也解释一下为什么很多程序员相比较学习Ruby或者Java很容易,但在决定开发iOS或者OS X应用时会那么犹豫。