《无所不能的JavaScript编程系列:arguments 参数对象》
前言:无所不能的JavaScript
JavaScript起源于Netscape公司的LiveScript语言,这是一种基于对象和事件驱动的客户端脚本语言,最初的设计是为了检验HTML表单输入的正确性,只是用于网页开发的一个弱类型脚本语言。随着Html5在PC和移动端越来越流行,JavaScript变得更加重要了,各种层出不穷的框架使得JavaScript的开发更加简捷,V8的性能带来了Node.js,将JavaScript 推向了服务器端,同时还被用在桌面应用、游戏、AR等各种场景,JavaScript已经变成了全能型选手。时至今日,JavaScript可算是世界上最流行的编程语言之一,这个被大量的开发者与设计师随手拈来增强他们的Web前端的脚本语言,越来越被重视。,
JavaScript成功在于它的无所不为。从一个小脚本到前、后端通吃,这足以证明了它的强大之处。
JavaScript一度被认为是一种玩具编程语言,它有很多缺陷,所以不被大多数后端开发人员所重视。很多人认为,相较Java、Ruby、Python、.Net等语言来说,写JavaScript代码很简单,并且JavaScript只是为了在网页上添加一点交互和动画效果,认为只需要会使用jQuery 做一些页面以及前后端交互就可以在简历写上熟悉JavaScript。
但这是完全错误的理解。JavaScript确实很容易上手,学习性价比高,稍微掌握一点JS基础知识,外加HTML和CSS,就可以做一个简单网页或者拿来应聘一份可以糊口的工作。但其精髓却不为大多数开发人员所熟知,如果想精通JS,使用JS进行随心所欲地编程,编写高质量的JavaScript代码更是难上加难。一个合格的开发人员应该精通JavaScript和其他编程语言。如果你已经掌握了其他编程语言,或者你还什么都不会,请立刻开始学习JavaScript,不要被Web时代所淘汰。
函数的实参和形参
在Java 编程中,函数的形参(parameter)和实参(argument)概念屡见不鲜,但是对JavaScript而言,这两个概念通常被弱化了。但其实在JS编程中,还是需要明确理解一下这两个概念。
弱类型脚本语言JS,它的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查,对传入参数个数也不检查。
一句话来说,JavaScript 的实参和形参可以不一致。
JavaScript 的arguments 参数对象
严格来说,我们应该称arguments 为“实参对象”,因为arguments 对象的长度是由实参个数而不是形参个数决定的。形参是函数内部重新开辟内存空间存储的变量,但是其与arguments对象内存空间并不重叠。对于arguments和值都存在的情况下,两者值是同步的,但是针对其中一个无值的情况下,对于此无值的情形值不会得以同步。
如下代码可以得以验证:
function test(arg1, arg2, arg3){
console.log(arguments.length); // result: "2"
arg1 = 100;
console.log(arguments[0]); // result: "100"
arguments[0] = "200";
console.log(arg1); // result: "200" console.log(arg3); // result: "undefined"
arg3 = true;
console.log(arguments[2]); // result: "undefined"
console.log(arg3) // result: true
}
test(1, 2);
根据代码我们可以得到JS实参对象的一些规则:
规则1:当传入的实参比形参个数少的时候,剩下的形参都将设置为undefined;
规则2:利用arguments.length可以获取调用函数的参数个数,它的值取决于调用处(实参),不一定等于形参个数;
规则3:需要使用可选实参的时候,需要将可选实参放在实参列表的最后,但应对这些可选形参加以控制,代码如下:
function getName(param1, /* optional */ param2) {
if(param2 === undefined) param2 = ""; // 严格相等,防止null;不需要判断空的话,param2 = param2 || ""
dosomething(); }
arguments.callee 与函数形参
说了半天的实参,那么形参在哪里?先看arguments 对象的callee 属性,callee 属性是 arguments 对象的一个成员,它表示对函数对象本身的引用,这有利于匿名,该属性仅当相关函数正在执行时才可用。
arguments.callee 得到函数本身,arguments.callee() 是调用自己,arguments.callee.length 是获取形参个数(PS:当然,函数名.length 亦可)。
好,有了这些知识,我们能做什么?
形参的作用无非就是在JS组件编程中,配合实参做一些校验处理和程序分支处理。arguments.callee 的作用就大了,利用它可以在函数内部进行递归逻辑。
代码如下:
function test(n){
if(n>0){
arguments.callee(n - 1);
alert(n);
}
}
var n = 5;
test(n);
如果知道结果是多少,那就OK了。
注:callee在严格模式下被禁用。
arguments 与类数组对象
arguments 对象是比较特别的一个对象,实际上是当前函数的一个内置属性。arguments 非常类似Array,但实际上又不是一个Array实例。
我们称呼这类对象为类数组对象。《JS权威指南》中提到过这一概念。
JS数组的一些特性是其他对象所没有的:
1.当有新的元素加进来的时候,自动更新length属性;
2.设置length为一个较小值将截断数组;
3.从Array.prototype中继承一些有用的方法;
4.其类属性为”Array“;
这些属性让数组和常规对象有所区别,称为”特殊的对象“。当然,这不是我们这边要关心的,上面这些属性并不是数组的本质特性。
一种完全合理的看法是:"把拥有一个数值length属性和对应非负整数属性的对象看做一种类型的数组,即类数组对象"。
这些类数组对象(参数对象arguments),并不能调用数组的方法或者期望length属性有什么特殊的行为,但是仍然可以类似数组那样遍历它们,并且可以使用call来操作数组的方法。
上一段代码,验证一下:
function ArgTest(a, b)
var numargs = arguments.length;
alert(numargs); //获取实际传递参数长度 var expargs = ArgTest.length;
alert(expargs); // 获取应该传递参数长度,使用 arguments.callee.length 可以获得同样的效果 alert(arguments.callee); //可以打印函数本身 Array.prototype.selfvalue = 1;
alert(new Array().selfvalue);
}
function testAguments(){
alert(arguments.selfvalue);
}
运行代码你会发现第一个alert显示1,这表示数组对象拥有selfvalue属性,值为1,而当你调用函数testAguments时,你会发现显示的是“undefined”,说明了不是arguments的属性,即arguments并不是一个数组对象。
因此,直接调用arguments.slice() 将返回一个"Object doesn't support this property or method"错误,因为arguments不是一个真正的数组。
使用Array.prototype.slice.apply(arguments)能将函数的参数对象转化为一个真正的数组。
JavaScript 的函数重载
对于arguments 参数说了这么多,最后再扯一下函数重载吧。本人是Java 程序猿出身,对于面向对象的三大特性(封装、继承、多态)是根深蒂固,JavaScript的封装和继承在后续文章中会介绍到,那么多态和重载,JavaScript是如何处理的呢?
很遗憾,由于JavaScript中函数的声明和调用特性,可以看出JavaScript中函数是不能重载的。
根据其他语言中重载的依据:"函数返回值不同或形参个数不同",我们可以得出上述结论:
第一:Javascript函数的声明是没有返回值类型这一说法的;
第二:JavaScript中形参的个数严格意义上来讲只是为了方便在函数中的变量操作,实际上实参已经存储在arguments对象中了。
另外,从JavaScript函数本身深入理解为什么JavaScript中函数是不能重载的:在JavaScript中,函数其实也是对象,函数名是关于函数的引用,或者说函数名本身就是变量。对于如下所示的函数声明与函数表达式,其实含以上是一样的(在不考虑函数声明与函数表达式区别的前提下),非常有利于我们理解JavaScript中函数是不能重载的这一特性。
编后语
那么问题来了,为什么我们要学JavaScript?尤其是当你已经掌握了某些其他编程语言如Java、C++的情况下。
简单粗暴的回答就是:因为你没有选择。在Web世界里,只有JavaScript能跨平台、跨浏览器驱动网页,与用户交互。
本人工作从事后端开发,属于一个“半吊子”的前端攻城狮,不会切图,不会设计,CSS和HTML会一些,但这些丝毫不能影响我对JavaScript 热爱。
JavaScript 和nodejs 的大前端时代即将来临,不管你学不学,它就在那里!
《无所不能的JavaScript编程系列:arguments 参数对象》的更多相关文章
- 简单物联网:外网访问内网路由器下树莓派Flask服务器
最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...
- 利用ssh反向代理以及autossh实现从外网连接内网服务器
前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...
- 外网访问内网Docker容器
外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...
- 外网访问内网SpringBoot
外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...
- 外网访问内网Elasticsearch WEB
外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...
- 怎样从外网访问内网Rails
外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...
- 怎样从外网访问内网Memcached数据库
外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...
- 怎样从外网访问内网CouchDB数据库
外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...
- 怎样从外网访问内网DB2数据库
外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...
- 怎样从外网访问内网OpenLDAP数据库
外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...
随机推荐
- 从内存中加载DLL Delphi版(转)
源:从内存中加载DLL DELPHI版 原文 : http://www.2ccc.com/article.asp?articleid=5784 MemLibrary.pas //从内存中加载DLL D ...
- 8、手把手教你Extjs5(八)自定义菜单2
这一节来定义另外三种类型的菜单类.首先定义菜单按钮类.文件放于app/view/main/region目录下面,文件名为ButtonMainMenu.js. /** * 显示在顶部的按钮菜单,可以切换 ...
- linux之scp
传输文件夹 scp -r -P 目标端口号 文件夹名 目标用户名@目标服务器地址:目标存放地址 传输文件夹 scp -P 目标端口号 文件名 目标用户名@目标服务器地址:目标存放地址
- elya:给移动APP创业者的工具集(一)
作为移动APP的创业者,往往遇到的困扰是,人家都开发过的功能了,劳资还得辛辛苦苦开发一遍,比如说什么积分系统啊,什么IM组件啊,什么滤镜啊,而且发一个版本官网就得改一次,做一次微信营销就要开发个H5页 ...
- 设计模式笔记之二:Android开发中的MVP架构(转)
写在前面,本博客来源于公众号文章:http://mp.weixin.qq.com/s?__biz=MzA3MDMyMjkzNg==&mid=402435540&idx=1&sn ...
- WebService 使用wsdl.exe生成代理类
利用wsdl.exe生成webservice代理类: 根据提供的wsdl生成webservice代理类 1.开始->程序->Visual Studio 2005 命令提示 2.输入如下红色 ...
- UWP_小说在线阅读器:功能要求与技术要求
学了WP开发也有一年了,也没做过什么软件的.17年进发UWP,锻炼自己一下.做一个开源的小说阅读器吧. 既然开发一个软件.所以要设计一下吧. 功能要求: 可能要用到的技术,这个吗,这就是遇到问题在解决 ...
- vs2015编译mysql c++ connector
目前MySQL Connector/C++的binary版本最高只支持VS2008,VS2015需要下载源码自行编译. 1.CMAKE 到官网下载最新的稳定版本 把bin目录添加到环境变量PATH中 ...
- iOS 程序测试、程序优化、提交前检测
1. 数据显示如果是数值要考虑到0的情况 2. 数据变化对前一个页面及相关页面的影响,也即数据同步问题.如果是有其它设备改变数据,那数据请求就应该在willappear(视图将要显示事件)进行请求,以 ...
- 【拓扑排序】【线段树】Gym - 101102K - Topological Sort
Consider a directed graph G of N nodes and all edges (u→v) such that u < v. It is clear that this ...