1. JS中的函数就是对象
当你发现函数有的时候难以理解时,把它看作一个对象就很好理解了,所以函数可以添加属性和方法。比如函数做参数,函数做返回值。
判断对象是否有该属性:attr in obj
var person = {
age:20;
};
console.log('name' in person); //false
console.log('age' in person); //true
遍历对象属性:
for(var p in cat){
console.log(p);
}
2. JS中的函数定义的三种方法
//function声明,因为它是声明,不用加分号
function add(){
}
//var赋值表达式,因为是赋值,所以要加分号
var add=function(){
};
//构造函数
var add=new Function('num1','num2','return num1+num2;');
三种函数定义方式的区别:
这涉及到预解析的机制。预解析就是:在当前的作用域中,JavaScript代码执行之前,浏览器首先会默认的把所有带var和function声明的变量进行提前的声明或者定义。
为什么是声明或者定义呢?因为var声明的变量和function声明的函数在预解析的时候有区别:var声明的变量在预解析的时候只是提前的声明,并未定义(这就是为什么我们访问没有声明的变量是undefined而不报错的原因);function声明的函数在预解析时会提前声明并且同时定义(所以我们在后面定义的函数,在前面也可以访问)。
由于三种定义函数方式的不同,function声明定义的函数预解析会提前,所以在函数前面访问也能访问到;var赋值表达式定义的函数相当于一个对象赋值给add,这样预解析时add提前声明(add=undefined),此时在它前面访问add没问题,等于undefined,但是调用add()这个函数就会报错,因为预解析时var add=undefined,并没有定义function,只是声明了。
但是,JS中并没有块级作用域的概念(if和for),代码块中的预解析会存在问题,所以尽量不要在for和if代码块中定义变量和函数。
3. JS中函数调用问题
(1)匿名函数自执行
function(){
}();//报错
//JS解析器会将function认为是声明,所以直接调用会出错,解决办法是不让function打头
(function(){
})();
//这样就避免了function打头
(function(){
}());
//这样也避免了function打头
!+-~function(){
}();
//这样也避免了function打头
(2)递归调用
function factorial(num){
if(num<=1) return 1;
return num*factorial(num-1);
}
console.log(factorial(5));
(3)构造函数的调用
var obj=new Person();//构造函数的调用
var ab=person();//普通函数的调用
//Object
new Object();
//Array
new Array();
//构造函数的调用必须new,否则就认为是普通函数的调用,返回值为object对象
(4)函数的间接调用
call和apply是Function的原型对象,它们能够将该函数当作一个方法绑定到指定对象上,并进行调用。也就是说,任何函数可以作为任何对象的方法来调用,哪怕这个函数不是那个对象的方法。
function.call(thisobj,args...)
function.apply(thisobj, [args])
function表示要调用的函数,thisobj表示要将function绑定的指定函数。call和apply方法的区别在于传参的形式不同,call方法可以接受多个参数列表,而apply方法接受一个数组。
var name='xm';
var person={};
person.name='xh';
person.getName=function () {
return this.name;
};
console.log(person.getName());//xh
console.log(person.getName.call(window));//将person的getName方法绑定在window对象上,输出xm
console.log(person.getName.apply(window));//将person的getName方法绑定在window对象上,输出xm
(5)JS函数中的参数
实参>形参的情况:当不确定传入实参数目时,我们可以不写形参,通过arguments类数组(这里叫类数组,是因为它并没有数组的一些方法)获取形参的值和个数,然后进行相应的计算。如进行加法时:
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());//undefined
console.log(add(1));//1
console.log(add(1,2));//3
console.log(add(1,2,3));//6
arguments:类数组,每个函数都有一个arguments,arguments.callee指代函数的本体,它的使用方法如下:
function jiecheng(num){
if(num<1) return 1;
return num*arguments.callee(num-1);//即使函数名修改,内部也不用修改
}
但是,在严格模式( "use strict"; )下,不允许使用arguments.callee,解决方案如下:
var jiecheng=function fn(){
if(num<1) return 1;
return num*fn(num-1);//这样更改了函数名jiecheng,内部也不用改变
}
(6)JS中抛出错误
function add(num1,num2) {
if(arguments.length!=add.length) throw new Error("请传入正确的参数");
return num1+num2;
}
add(1);//错误
add(1,2);//因为上面出错,所以不会执行