函数的本质是对象

三种定义方式

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. Flink与HanLP集成使用

    自然语言处理是机器学习的一个重要分支,在智能翻译.智能问答.舆情监控.ChatOps等都有很好的应用场景,目前比较好的一个开源实现工具是何晗大神的HanLP,主页(http://hanlp.com/) ...

  2. Dapper系列 作者:懒懒的程序员一枚

    Dapper 第一篇简单介绍什么是小巧玲珑?Dapper如何工作安装需求方法参数结果常用类型 Dapper 第二篇 Execute 方法介绍描述存储过程Insert语句Update语句Delete语句 ...

  3. Navicat Premium 12(破解版免安装)

    获取安装包解压至任意位置 切勿更新!!! 切勿更新!!! 切勿更新!!! 扫下方二维码关注公众号回复:navicat12即可获取

  4. Linux访问权限控制及时间同步实践

    1.编写脚本/root/bin/checkip.sh,每5分钟检查一次,如果发现通过ssh登录失败 次数超过10次,自动将此远程IP放入Tcp Wrapper的黑名单中予以禁止防问 方式一:脚本+定时 ...

  5. Spring中的可扩展接口

    1.监听器Listener(点此连接,执行流程带源码分析及demo) 2.bean定义的后置处理器(BeanDefinitionRegistryPostProcessor)和bean工厂的后置处理器( ...

  6. 制作一个docker镜像:mysql-8-x64-linux

    因为个人学习需要,为软件系统的虚拟容器化,以下将mysql制作为docker镜像,并记录下详细步骤. 欢迎大家学习交流和转载,同时写作不易,如果各位觉得不错,请点赞支持. 备注:以下代码和文章,欢迎复 ...

  7. .NET Core之单元测试(三):Mock框架Moq的使用

    编写一个API 新增一个接口 public interface IFoo { bool Ping(string ip); } 接口实现 public class Foo : IFoo { public ...

  8. 解决 webpack-dev-server 不能使用 IP 访问

    webpack 是众所周知很好用的打包工具,在开发 vue 项目时,vue-cli 就集成了 webpack.我们启一个服务:npm run dev然后在浏览器可是使用 http://localhos ...

  9. Nginx下配置Http Basic Auth

       nginx basic auth指令 第一条语句: 语法:     auth_basic string | off;默认值:     auth_basic off;配置段:     http, ...

  10. tensorflow打印可用设备列表

    from tensorflow.python.client import device_libprint(device_lib.list_local_devices())