当前位置: 移动技术网 > IT编程>开发语言>JavaScript > JS函数深入

JS函数深入

2020年01月03日  | 移动技术网IT编程  | 我要评论

函数的本质是对象

三种定义方式

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的值累加;

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网