函数的本质是对象

三种定义方式

1、  字面量=function声明

            function add() {
// body...
}
add();

2、  var赋值表达式

            var add = function (argument) {
// body...
};
add();
var add = function fn(argument) {
// body...
fn();
add();
};
add();
fn();//会报错,只能在函数体内调用

3、  构造函数

    var add = new Function('num1', 'num2', 'return num1 + num2;');
add();

三种定义方式区别:

字面量=function声明:预加载时add=function

    console.log(add());
function add() {
return 1;
}

var赋值表达式:预加载时add=undefined

    console.log(add());
var add = function () {
return 1;
};

构造函数:少用


杂七杂八的知识点:

JS中没有块级作用域,所以不会在if中发生预解析,在外部预解析的时候,if中声明的所有函数都会被提前,所以无法达到按需定义的目的。

内部函数可以访问外部函数的变量(作用域链的机制)


案例:写出一个加法(add)函数,并在其内部定义一个函数(isNumber),用来判断add的参数是否可以转化为数字类型进行相加,

如果可以,就在页面中输出结果;

如果不能就退出add,给出提示“请传入数字类型的参数”

function add(num1,num2){
if(isNaN(num1) || isNaN(num2)){
alert('请传入数字类型的参数');
return;
}else{
return parseInt(num1)+parseInt(num2);
}
}

var num1=prompt('请输入数字1');

var num2=prompt('请输入数字2');

alert(add(num1,num2));

案例:匿名函数也是函数,当它自执行的时候会创建函数作用域,它里面的变量和函数都是局部的,当匿名函数执行完毕后会被销毁。所以我们在外面访问不到add

    function () {
function add(num1,num2){
return num1+num2;
}
}();
document.write(add(1,2));//报错

匿名函数自执行方式:

    var add = function () {
console.log(1);
}(); (function () {
console.log(1);
})(); !+-~function () {
console.log(1);
}();

递归调用:递归调用就是自己调用自己,但切记一定要有终止条件,否则函数将无限递归下去

    function factorial(num) {
if (num <= 1) return 1;
return num * factorial(num - 1);
// return 5 * 4! = 5 * 4 * 3! =... 5 * 4 * 1!
}
console.log(factorial(5));

方法的调用:

    document.onclick = function () {
console.log('你点击了文档!');
};
document.onclick();
    var operation = {
add: function (num1, num2) {
return num1 + num2;
},
subtract: function (num1, num2) {
return num1 - num2;
},
'@': function () {
console.log('@');
},
key: function () {
// body...
}
};
console.log(operation.add(1, 2));
console.log(operation['@'](1, 2)); //@符比较特别
var key = 'add';
console.log(operation[key](1, 2));

链式调用

    var operation = {
add: function (num1, num2) {
console.log(num1 + num2);
return this;
},
subtract: function (num1, num2) {
console.log(num1 - num2);
return this;
},
'@': function () {
console.log('@');
},
key: function () {
// body...
}
};
operation.add(1, 2).subtract(2, 1);

间接调用:

对象没有call和apply方法,只有函数有

call和apply的唯一区别就在它们传参的方式上

apply可以将数组和类数组一次性的传递进函数中,call只能一个一个的传;

    var name = 'xm';
var person = {};
person.name = 'xh';
person.getName = function () {
return this.name;
};
console.log(person.getName()); //this指向person
console.log(person.getName.call(window)); //this指向window
console.log(person.getName.apply(window)); //this指向window function add(num1, num2) {
return num1 + num2;
}
console.log(add(1, 2));
var datas = [1, 2];
console.log(add.call(window, 1, 2));
console.log(add.apply(window, datas)); //apply(ele,[])

输出:'xm', [object Object]

person()就是普通函数的调用,返回值是return后面的内容:'xm' ; new person()是将person作为构造函数调用,返回的永远是对象 ; document.write没法输出对象,它会尝试着将其转换成字符串输出

输出:undefined

call可以改变函数中this的指向,这里在调用方法的时候将其this改为了window,所以this.value就变成了window.value,而window.value没有定义过,所以为undefined


函数的参数:

function add() {
if (arguments.length == 0) return;
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
console.log(add());
console.log(add(1, 2, 3, 4, 5));

arguments

类数组,实质是类

function fn(name) {
arguments[0] = '';
console.log(name);
}
fn('xm');//没有输出

arguments.callee 指代函数本身,多用于递归

计算阶乘方法一:

function factorial(num) {
if (num <= 1) return 1;
return num * factorial(num - 1);
}
console.log(factorial(5));

计算阶乘方法二:

function factorial(num) {
if (num <= 1) return 1;
return num * arguments.callee(num - 1);
}
console.log(jiecheng(5));

计算阶乘方法三:

var jicheng = function fn(num) {
if (num <= 1) return 1;
return num * fn(num - 1);
};
console.log(jicheng(5));

判断传入实参的个数是否与形参相等

arguments.length实参个数

add.length形参个数

function add(num1, num2) {
if (arguments.length != add.length) throw new Error('请传入' + add.length + '个参数!');
return num1 + num2;
}
console.log(add(1, 1));
console.log(add(1));
console.log(add(1, 2, 3));

案例:

输出:1,1,1,1,2,3

1、 count()()这样调用,每次都会创建一个新的局部作用域,num的值会不断地被初始化为1

2、 return num++表示先返回num的值,再将num加1

3、 先将count()赋给fn,此时count()只调用了一次,接下来多次调用fn()的时候,count函数并没有多次调用,num只会在count函数调用的时候被初始化,所以多次调用fn()的时候num不会被多次初始化;由于fn相当于count函数的内层函数(var fn=count();这行代码执行后,就调用了count(),调用count后就将里面的函数赋值给了fn,所以说fn就相当于函数的内层函数了。),可以访问count中的变量num,所以多次调用fn函数,会将num的值累加;

JS函数深入的更多相关文章

  1. 3.3 js函数

    1.函数语法: 函数声明的方式:function 函数名(参数1,参数2-){//函数体;}函数调用:函数名(参数1,参数2-); 函数内不一定都指定返回值. 如果需要指定返回值,可用 return ...

  2. Js函数function基础理解

    正文:我们知道,在js中,函数实际上是一个对象,每个函数都是Function类型的实例,并且都与其他引用类型一样具有属性和方法.因此,函数名实际上是指向函数对象的指针,不与某个函数绑定.在常见的两种定 ...

  3. js函数表达式和函数声明的区别

    我们已经知道,在任意代码片段外部添加包装函数,可以将内部的变量和函数定义"隐 藏"起来,外部作用域无法访问包装函数内部的任何内容. 例如: var a = 2; function ...

  4. 通用js函数集锦<来源于网络> 【二】

    通用js函数集锦<来源于网络> [二] 1.数组方法集2.cookie方法集3.url方法集4.正则表达式方法集5.字符串方法集6.加密方法集7.日期方法集8.浏览器检测方法集9.json ...

  5. 通用js函数集锦<来源于网络/自己> 【一】

    通用js函数集锦<来源于网络/自己>[一] 1.返回一个全地址2.cookie3.验证用户浏览器是否是微信浏览器4.验证用户浏览器是否是微博内置浏览器5.query string6.验证用 ...

  6. 100多个基础常用JS函数和语法集合大全

    网站特效离不开脚本,javascript是最常用的脚本语言,我们归纳一下常用的基础函数和语法: 1.输出语句:document.write(""); 2.JS中的注释为//3.传统 ...

  7. JS函数

    1.document.write(""); 输出语句2.JS中的注释为//3.传统的HTML文档顺序是:document->html->(head,body)4.一个浏 ...

  8. js函数和运算符

    函数是由事件驱动或者它被调用时执行可重复使用的代码块. <script> function myFunction(){ Alert(“hello World!”): } </scri ...

  9. JavaScript学习03 JS函数

    JavaScript学习03 JS函数 函数就是包裹在花括号中的代码块,前面使用了关键词function: function functionName() { 这里是要执行的代码 } 函数参数 函数的 ...

  10. JSF页面中使用js函数回调后台bean方法并获取返回值的方法

    由于primefaces在国内使用的并不是太多,因此,国内对jsf做系统.详细的介绍的资料很少,即使有一些资料,也仅仅是对国外资料的简单翻译或者是仅仅讲表面现象(皮毛而已),它们的语句甚至还是错误的, ...

随机推荐

  1. vs 搭配 Linux 开发

    这是一篇翻译,为什么突然想翻译文章了呢,因为很多大佬们都说英语对程序员还是挺重要的,毕竟互联网的最新技术基本都在歪果仁那边,如果英语不好,不会看国外的文档的话,将会错失接触第一手资料的机会,失去很多先 ...

  2. apache 访问日志access_log 配置和解析 rotatelogs分割日志

    一.解析访问日志        apache 的访问日志记载着大量的信息,学会高效快捷的读出其中关键信息对我们的工作有极大帮助.       如果Apache的安装方式是默认安装,服务器一运行就会有两 ...

  3. VMware 克隆 CentOS 后网卡信息修改

    概述 在我们需要多台 CentOS 虚拟机的时候,对已有虚拟机的系统进行克隆或是复制.但是这样做又有一个问题,克隆出来的虚拟机启动的时候你输入命令:ifconfig,eth0 网卡信息没了,只有一个 ...

  4. LVS服务原理以及搭建

    一.LVS简介 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统,目的在于使用集群技术和Linux操作系统实现一个高性能.高可用的服务器.它 ...

  5. [Redis-CentOS7]Redis事务操作(六)

    事务操作 隔离操作: 事务中所有的命令都会序列化,按顺序执行,不会被其他命令打扰 原子操作: 事务中所有的命令要么全部执行,要么全部不执行 添加事务并执行 127.0.0.1:6379> MUL ...

  6. 论文翻译:Speech Enhancement Based on the General Transfer Function GSC and Postfiltering

    论文地址:基于通用传递函数GSC和后置滤波的语音增强 博客作者:凌逆战 博客地址:https://www.cnblogs.com/LXP-Never/p/12232341.html 摘要 在语音增强应 ...

  7. Arm开发板+Qt学习之路-开发板显示 /bin/sh: ./hello: Permission denied

    将pc上交叉编译完成的可执行文件hello,通过串口传输到开发板上后,执行./hello显示 /bin/sh: ./hello: Permission denied 解决方案:在开发板上执行  chm ...

  8. C语言基础二 练习

    指出正确标识符 命名 l 只能由26个英文字母的大小写.10个阿拉伯数字0~9.下划线_组成 l 严格区分大小写,比如test和Test是2个不同的标识符 l 不能以数字开头 l 不可以使用关键字作为 ...

  9. printf函数中*修饰符的作用,如:%*d

    在printf函数中,我们可以用数字修饰来控制打印的字段宽度和精度,如下(为强调视觉效果,均填充0): #include <stdio.h> int main() { ; float f= ...

  10. Android中实现长按照片弹出右键菜单

    场景 效果 注: 博客: https://blog.csdn.net/badao_liumang_qizhi 关注公众号 霸道的程序猿 获取编程相关电子书.教程推送与免费下载. 实现 将布局改为Lin ...