前言:无所不能的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 参数对象》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. OPENCV形态学算法-2

    一.漫水填充算法 该算法通过一个指定的种子点,来分析整张图片上的像素,并设置像素差异阈值,在阈值类的点,最后变成相同的颜色.该方法通过上下限和连通方式来达到不同的连通效果. 该方法常用与标记和分离图像 ...

  2. mysql的python api

    我采用的是MySQLdb操作的MYSQL数据库.先来一个简单的例子吧: 1 2 3 4 5 6 7 8 9 10 import MySQLdb   try:     conn=MySQLdb.conn ...

  3. 苹果App Store开发者帐户从申请,验证,到发布应用(1)

    app store为开发者提供四种类型的申请: 个人ios开发者计划$99/年 公司ios开发者计划$99/年 企业ios开发者计划$299/年 高校ios开发者计划免费 在这里主要介绍一下公司ios ...

  4. java线程 — 创建和启动线程

    创建和启动线程,传统有两种方式: 方式1:继承Thread类: 方式2:实现Runnable接口: 线程类(java.lang.Thread):Thread类和Thread的子类才能称之为线程类.阅读 ...

  5. iOS开发网络数据之AFNetworking使用 分类: ios技术 2015-04-03 16:35 105人阅读 评论(0) 收藏

    http网络库是集XML解析,Json解析,网络图片下载,plist解析,数据流请求操作,上传,下载,缓存等网络众多功能于一身的强大的类库.最新版本支持session,xctool单元测试.网络获取数 ...

  6. BZOJ1119[POI2009]SLO && BZOJ1697[Usaco2007 Feb]Cow Sorting牛排序

    Problem J: [POI2009]SLO Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 622  Solved: 302[Submit][Sta ...

  7. Oracle数据库用户权限和管理员权限

    一.如何查看权限 查看用户权限 1. oracle用户查看自己的权限和角色     select * from user_tab_privs;     select * from user_role_ ...

  8. jq动态添加的元素触发绑定事件无效

    <div class='a'> <div class='b'> </div> 其中$('.a')是html页面的元素,$('.b')是jq动态添加的元素.$(&qu ...

  9. 用JS添加文本框案例代码

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. php分页原理教程及简单实例

    <?php //连接数据库 $con = mysql_connect("localhost","root",""); mysql_se ...