当程序在调用某个函数时,做了以下的工作:准备执行环境,初始函数作用域链和arguments参数对象。

函数的声明语句

function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传 入函数的参数。函数体放在大括号里面。

  1. function hello(a){
  2. console.log(a);
  3. }
  4. // 调用:
  5. hello('hello world');
函数表达式

采用变量赋值的写法:将一个匿名函数赋值给变量。这时,这个匿名函数又称函数表达式。

  1. var hello = function(a){
  2. console.log(a);
  3. }
  4. // 将一个具名函数赋值给变量。
  5. var hello = function fn(a){
  6. console.log(a);
  7. console.log(fn); // fn();
  8. console.log(fn === hello); // true;
  9. }
  10. console.log(fn); // ReferenceError: fn is not defined;
  11. // 说明,具名函数fn和hello是同一个函数,但是作用范围不一致,fn只能在函数体内使用,相当于函数的一个局部变量,hello可在函数内部,外部调用。
Function构造函数
  1. var add = new Function(
  2. 'x',
  3. 'y',
  4. 'return x + y'
  5. );
  6. //等同于
  7. function add(x,y){
  8. return x + y;
  9. }
  10. // 可以传递任意数量的参数给Function构造函数,只有最后一个参数会被当做函数体,如果只有一个参数,该参数就是函数体。
  11. // Function构造函数可以不使用new命令,返回结果完全一样。
函数的返回值return

return只能出现在函数体内。

​一个函数中可以有多个return语句。

​return;(表达式的值为undefined)代表直接提出函数执行,return之后除了在finally{}中的代码,都不会再执行。

​return 可以返回任何数据类型的数据。

​如果函数调用时在前面加上了new前缀,且返回值不是一个对象或者没有返回值,则返回this(该新对象)

函数调用

函数调用模式

  1. function add(x,y){
  2. return x+y;
  3. }
  4. var sum = add(3,4);
  5. console.log(sum)//7
  6. // 使用函数调用模式调用函数时,非严格模式下,this被绑定到全局对象;在严格模式(use strict;)下,this是undefined

​ 方法调用模式

​ 当一个函数被保存在对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象。如果 调用表达式包含一个提取属性的动作,那么它就是被当做一个方法来调用。

  1. var p = {
  2. a: 1,
  3. fn: function(){
  4. this.a = 2;
  5. }
  6. }
  7. console.log(p.a);// 1
  8. p.fn();
  9. console.log(p.a);// 2

​ 构造器调用模式

​ 如果函数或者方法调用之前带有关键字new,它就构成构造函数调用。

如果构造函数调用在圆括号内包含一组实参列表,先计算这些实参表达式,然后传入函数内。

如果构造函数没有形参,javascript构造函数调用的语法是允许省略实参列表和圆括号的。凡是没有形参的构造函数调 用都可以省略圆括号。(var o = new Object() 等价于 var o = new Object)

​ 间接调用模式

​ javascript中函数也是对象,函数对象也可以包含方法。call()和apply()方法可以用来间接地调用函数

​ 这两个方法都允许显式指定调用所需的this值,也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不 是那个对象的方法。两个方法都可以指定调用的实参。call()方法使用它自有的实参列表作为函数的实参,apply()方法则 要求以数组的形式传入参数。

  1. var obj = {};
  2. function sum(x,y){
  3. return x+y;
  4. }
  5. console.log(sum.call(obj,1,2));//3
  6. console.log(sum.apply(obj,[1,2]));//3

函数参数

JS是弱类型语言,函数定义时未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查。实际上, javascript函数调用甚至不检查传入形参的个数。

参数个数

1.当实参(函数被调用时掺入的实际参数值)比函数声明指定的形参(函数定义时的参数列表)个数要少,剩下的形参都将设置为undefined值。

  1. function add(x,y){
  2.  return x + y; // x:1, y: undefined
  3. }
  4. add(1);

2.当实参比形参个数要多时,剩下的实参没有办法直接获得,需要使用arguments对象来获取。

  1. function add(x,y){
  2.  console.log(arguments);
  3.  console.log(arguments.length);
  4.  return x + y;
  5. }
  6. add(1,2,3,4,5);
  7. // 控制台:
  8. // Arguments(5) [1, 2, 3, 4, 5, callee: ƒ, Symbol(Symbol.iterator): ƒ]
  9. // arguments是个类数组,有数组的部分属性,如length,可以通过索引去获取对应的参数列表。

3.函数定义时也可以不给形参,到时直接通过arguments[索引]去获取实参。

同名形参

在非严格模式下,函数中可以出现同名形参,且只能访问最后出现的该名称的形参。

  1. function add (x,x,x){
  2. return x;
  3. }
  4. console.log(add(1,2,3));// 3
  5. // 严格模式编译报错。
函数重载

在java语言中,函数的重载是这样定义的:方法名相同,参数的个数或者类型必须不同。

javascript函数不能像Java上那样实现重载。只能通过检查传入函数中参数的类型和数量并作出不同的反应,来模仿方法的重载。

  1. function doAdd(){
  2.   if(arguments.length == 1){
  3.     alert(arguments[0] + 10);
  4.   }else if(arguments.length == 2){
  5.     alert(arguments[0] + arguments[1]);
  6.   }
  7. }
参数传递

值传递:对于基本数据类型的参数传递。比如String,Number,Boolean等。在向参数传递基本类型的值时,被传递的值会被复制到一个局部变量(命名参数或arguments对象的一个元素)。

  1. function addTen(num){
  2.   num += 10;
  3.   return num;
  4. }
  5. var count = 20;
  6. var result = addTen(count);
  7. console.log(count);//20,没有变化
  8. console.log(result);//30

引用传递:参数为引用类型的数据时(Object, Array),传递过去的是引用数据的内存地址。会把这个地址复制给一个局部变量,因此这个局部变量的变化会直接改变指向该内存地址的引用数据。

  1. function setName(obj){
  2.   //obj 在函数内部是一个局部变量
  3.   obj.name = 'test';
  4. }
  5. var person = new Object();
  6. setName(person);
  7. console.log(person.name);//'test'

函数属性和方法

函数是javascript中特殊的对象,可以拥有属性和方法,就像普通的对象拥有属性和方法一样。甚至可以用Function()构造函数来创建新的函数对象。

属性

length属性:arguments对象的length属性表示实参个数,而参数的length属性则表示形参个数。

prototype属性:每一个函数都有一个prototype属性,这个属性指向了一个对象的引用,这个对象叫做原型对象(prototype object)。每一个函数都包含不同的原型对象。将函数用作构造函数时,新创建的对象会从原型对象上继承属性。

  1. function fn(){};
  2. var obj = new fn;
  3. fn.prototype.a = 1;
  4. console.log(obj.a);//1

name属性:函数定义了一个非标准的name属性,通过这个属性可以访问到给定函数指定的名字,这个属性的值永远等于跟在function关键字后面的标识符,匿名函数的name属性为空。

方法

每一个函数都包含两个非继承而来的方法:apply()和call()方法。这两个方法的用途都是在特定的作用域中调用函数。

call()&apply() 要想以对象o的方法来调用函数f(),可以使用call()和apply()。

  1. f.call(o);
  2. f.apply(o);
  3. // 比如:
  4. window.color = "red";
  5. var o = {color: "blue"};
  6. function sayColor(){
  7.   console.log(this.color);
  8. }
  9. sayColor();      //red
  10. sayColor.call(this);  //red
  11. sayColor.call(window); //red
  12. sayColor.call(o);   //blue
  13. sayColor.call(o)等价于:
  14. o.sayColor = sayColor;
  15. o.sayColor();  //blue
  16. delete o.sayColor;
  17. // 调用方式:
  18. func.apply(作用域对象, []);
  19. func.call(作用域对象, a,b,c);
  20. // 在非严格模式下,使用函数的call()或apply()方法时,null或undefined值会被转换为全局对象。而在严格模式下,函数的this值始终是指定的值

应用:

找出数组中最大元素。

  1. var a = [10, 2, 4, 15, 9];
  2. Math.max.apply(null, a);//15

将类数组转成真正的数组。

  1. var add = function(x,y){
  2. console.log(Array.prototype.slice.apply(arguments));
  3. };
  4. add(1,2);
  5. 控制台:
  6. (2) [1, 2]

将一个数组的值push到另一个数组中。

  1. var a = [];
  2. Array.prototype.push.apply(a,[1,2,3]);
  3. console.log(a);//[1,2,3]
  4. Array.prototype.push.apply(a,[2,3,4]);
  5. console.log(a);//[1,2,3,2,3,4]

bind()

bind()是es5新增的方法,这个方法的主要作用就是将函数绑定到某个对象。

当在函数f()上调用bind()方法并传入一个对象o作为参数,这个方法将返回一个新的函数。以函数调用的方式调用新的函数将会把原始的函数f()当做o的方法来调用,传入新函数的任何实参都讲传入原始函数。

 bind()方法不仅是将函数绑定到一个对象,它还附带一些其他应用:除了第一个实参之外,传入bind()的实参也会绑定到this,这个附带的应用是一种常见的函数式编程技术,有时也被称为’柯里化’(currying)。

  1. function getConfig(colors,size,otherOptions){
  2.   console.log(colors,size,otherOptions);
  3. }
  4. var defaultConfig = getConfig.bind(null,'#c00','1024*768');
  5. defaultConfig('123');//'#c00 1024*768 123'
  6. defaultConfig('456');//'#c00 1024*768 456'

JavaScript—深入理解函数的更多相关文章

  1. 深入理解javascript:揭秘命名函数表达式

    这是一篇转自汤姆大叔的文章:http://www.cnblogs.com/TomXu/archive/2011/12/15/2288411.html 前言 网上还没用发现有人对命名函数表达式进去重复深 ...

  2. 【JavaScript】理解与使用Javascript中的回调函数

    在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...

  3. javascript的isPrototypeOf函数的理解

    JavaScript中isPrototypeOf函数方法是返回一个布尔值,指出对象是否存在于另一个对象的原型链中.使用方法: object1.isPrototypeOf(object2)~~~原型链理 ...

  4. 深入理解 JavaScript 中的函数

    JavaScript函数也具有这些特性,但它们不仅仅是常规函数.JavaScript函数是对象.你可以查看我曾经写的关于JavaScript对象的文章,里面我提到几乎JavaScript中的所有一切都 ...

  5. JavaScript的进阶之路(六)理解函数

    函数:定义一次,多次调用:用于对象的属性则称为对象的方法:在JavaScript中,函数即对象:嵌套的函数形成闭包: 定义函数和简单调用函数: //函数定义 function f1(){ //没有参数 ...

  6. 如何理解JavaScript中的函数

    转: 如何理解JavaScript中的函数 JS中的函数简介 JS中的函数是一种通过调用来完成具体业务的一段代码块.最核心的目的是将可重复执行的操作进行封装,然后供调用方无限制的调用. JS中的函数的 ...

  7. 深入理解JavaScript中的函数操作——《JavaScript忍者秘籍》总结

    匿名函数 对于什么是匿名函数,这里就不做过多介绍了.我们需要知道的是,对于JavaScript而言,匿名函数是一个很重要且具有逻辑性的特性.通常,匿名函数的使用情况是:创建一个供以后使用的函数.简单的 ...

  8. 《JavaScript高级程序设计》读书笔记(三)基本概念第六小节理解函数

    内容---语法---数据类型---流程控制语句 上一小节---理解函数 本小节 函数--使用function关键字声明,后跟一组参数以及函数体 function functionName(arg0, ...

  9. JavaScript权威指南 - 函数

    函数本身就是一段JavaScript代码,定义一次但可能被调用任意次.如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法.用于初始化一个新创建的对象的函数被称作构造函数. 相对 ...

随机推荐

  1. ORCHARD WOODEN GATE

    狗: 代码小盒子 爆零秘籍 备忘录 任务计划 核心算法: 搜索/枚举/贪心 dp 分治 数据结构: 并查集 ST表 堆 线段树 树状数组 分块 树套树 平衡树 LCT 莫队 字符串: 哈希 Trie ...

  2. 四、Zookeeper伪集群搭建

    伪集群模式 Zookeeper不但可以在单机上运行单机模式 Zookeeper,而且可以在单机模拟集群模式 Zookeeper的运 行,也就是将不同实例运行在同一台机器,用端口进行区分,伪集群模式为我 ...

  3. git 常用命令--超实用

    git命令行常用操作 1.配置ssh key git config --global user.name 'git用户名' git config --global user.email '邮箱地址' ...

  4. PDF格式分析

    系列文章是csdn作者'秋风之刀'写的,我只是把目录列出来而已,感谢作者辛苦付出. PDF格式分析(一)简介 PDF格式分析(二)语法之对象 PDF格式分析(三)语法之Filter PDF格式分析(四 ...

  5. Linux下keepalived配置

    1.背景 节点1:192.168.12.35 节点2:192.168.12.36 2.keepalived安装 使用yum仓库安装keepalived [root@node01 ~]# yum ins ...

  6. react第十单元(children的深入用法-React.Children对象上的方法)

    第十单元(children的深入用法-React.Children对象上的方法) #课程目标 理解什么是children 掌握React.Children对象上的方法 #知识点 什么是children ...

  7. 教你用python爬取抖音app视频

    记录一下如何用python爬取app数据,本文以爬取抖音视频app为例. 编程工具:pycharm app抓包工具:mitmproxy app自动化工具:appium 运行环境:windows10 思 ...

  8. 自动测试LeetCode用例方法

    自动合并测试LeetCode解题方法 在leetcode.com上答题,Run Code或者Sumbmit通常要Spending一会,如果提交一次就Accepted那还好,如果反复Wrong Answ ...

  9. 论文阅读: A Review of Robot Learning for Manipulation: Challenges, Representations, and Algorithms

    机器人学习操纵综述:挑战,表示形式和算法 1.介绍 因此,研究人员专注于机器人应如何学习操纵周围世界的问题. 这项研究的范围很广,从学习个人操作技巧到人类演示,再到学习适用于高级计划的操作任务的抽象描 ...

  10. 服务器安装PVE6.1.2

    1     去官网下载PVE的镜像文件 https://www.proxmox.com/en/downloads 2     制作成U盘启动 准备一个U盘用来制作启动盘(记得将U盘里原来的资料备份然后 ...