目录
基本概念
函数,一段JS代码,它只定义一次,但可以被执行或调用任意次。
JS函数是参数化的。
- 函数的定义会包括一个名为形参的标识符列表,这些参数在函数体内像局部变量一样工作。
- 函数调用会为形参提供实参的值。
- 函数使用实参的值来计算返回值,成为该函数调用表达式的值。
- 除实参外,每次调用还会拥有另一个值(本次调用的上下文),这就叫this关键字的值。
- 若函数挂载在一个对象上,作为对象的属性,则成为该对象的方法。
- 用于初始化一个新创建的对象的函数称为构造函数。
- 函数即对象,程序可以随意操控。
- 函数可以嵌套在其他函数中定义,从而可以访问它们被定义时所处的作用域中的任何变量。称为闭包。
函数定义
函数定义构成:函数名称标识符,一对圆括号,一对花括号。
function 函数名 ( ) { }
函数定义方式
函数声明语法
function add(num1,num2){
return num1+num2;
}
函数表达式
let sub=function(num1,num2){
return num1-num2;
}
区别:函数声明语法会提升,且可以在函数声明之前调用;而函数表达式只能在声明之后被调用,函数名是可写可不写,且在函数之外无法用函数名调用。
箭头函数(ES6)
let mul =(num1,num2) => num1*num2;
//函数内没有多余语句,即函数内只有return语句,才能省略写法。
let mul =(num1,num2) => {
return num1*num2;
}
//没有参数,不能省略圆括号
let f1 = () => {
console.log("abc");
}
//若只有一个参数,则可以省略圆括号
let f2 = x => x**2;
//立即执行函数,xx值为函数值传进去执行的结果
let xx=((x)=>x**x)(4) //256
Function 构造函数
let sum = new Function(
"num1",
"num2",
"let result=num1+num2;return result;"
);
//接受任意多个字符串参数,最后一个参数始终会被当成函数体,而之前的参数都是新函数的参数。
不推荐使用,会被解释两次,影响性能。
函数命名
函数名称建议使用以动词或以动词为前缀的词组。
通常函数名第一个字符为小写
若函数名包含多个单词时:
- 将单词以下划线分隔
- 驼峰命名法
有一些函数作为内部函数或私有函数,这种函数名通常以一条下划线为前缀。
eg. _ _ proto_ _
函数参数
特征:ECMAScript函数不关心传入参数个数,也不关心传入参数的数据类型。
因为ECMAScript函数的参数在内部表现为一个数组。
arguments对象
一个类数组对象,可以使用中括号访问其中元素。
arguments[0]、arguments[1]
要确定接收到的参数个数,可以访问arguments.length属性。
参数默认值
ES5
function f1(name, age) {
name = name ? name : "User"; //可以简化为 name || "User"
age = age ? age : 0; // age || 0
console.log ( name, age);
}
f1();
f1("Tom");
ES6
function f2(name = "User",age = 0){
console.log (name,age) ;
}
f2( );
f2( "Tom" ) ;
扩展参数
function sum(){ };
let nums=[ ];
//将nums传入sum()
sum.apply(null,nums); //ES5
sum(...nums); //ES6
剩余参数
剩余参数语法允许我们将一个不定数量的参数表示为一个数组。
function sum2(name,...scores){
let r=scores.reduce((x,y)=>x+y,0);
console.log(`${name}总分为:${r}。`);
}
sum2("Tom",80,90,100);
常见问题
- 箭头函数不支持arguments对象。
- 箭头函数支持剩余参数。
- 剩余参数只能位于参数列表的末尾,有且只能有一个。
函数调用
构成函数主体的JavaScript 代码在定义之时并不会执行,只有调用该函数时,它们才会执行。
调用函数的方法:作为函数、作为方法、作为构造函数、通过它们的call( )和apply( )方法间接调用。
作为函数调用
sum( 1,2,3+6,getNum( ) );
对于普通的函数调用,瓯数的返回值成为调用表达式的值。
函数调用上下文(this的值)是全局变量。
作为方法调用
方法调用和函数调用有一个重要的区别,即 调用上下文。
let calculator={
oper1:10,
oper2:20,
add:function(){
this.result=this.oper1+this.oper2;
},
};
calculator.add();
console.log(calculator.result); //30
调用上下文
关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this。
先设置一个变量保存当前this的值,以免下文this再次被使用而改变。
构造函数调用
如果函数或方法调用之前带有关键字new ,它就是构造函数调用。
构造函数通常不使用return关键字,它们通常初始化新对象,当构造函数的函数体执行完毕时,它会显式返回该对象。
间接调用
使用函数对象的call( )和apply( )方法可以间接调用函数。
第一个参数指定调用上下文(函数内部的this ) ,第二个参数给函数传递参数。
let obj1={
x:100,
y:200,
show:function(n=1,m=1){
return `(${this.x*n},${this.y*m})`;
},
concat:function(){
let r=[this.x,this.y];
for(let a of arguments){
r.push(a);
}
return r;
},
};
let obj2={x:111,y:222};
let r1=obj1.show.call(obj2);
let r2=obj1.show.call(obj2,10,100);
console.log(r1,r2);
//(111,222) (1110,22200)
let r3=obj1.concat.call(obj2,11,22,33);
let r4=obj1.concat.apply(obj2,[2,3,4,5]);
console.log(r3,r4);
//[ 111, 222, 11, 22, 33 ] [ 111, 222, 2, 3, 4, 5 ]
回调函数
被作为实参传入另一函数,并在该外部函数内被调用,用以来完成某些任务的函数,称为回调函数。
函数对象
函数属性
length属性
在函数体里,arguments.length 表示传入函数的实参的个数。
而函数本身的length属性是只读的,它代表函数声明的实际参数的数量。
function fn(a,b){
console.log(arguments.length);
console.log(fn.length);
console.log(arguments.callee.length);
};
fn(1,2,3,4,5);
//5
//2
//2
prototype属性
每一个函数都包含一个prototype属性,这个属性是指向一个对象的引用,这个对象称做“原型对象”(prototype object) 。
每一个函数都包含不同的原型对象。当将函数用做构造函数的时候,新创建的对象会从原型对象上继承属性。
自定义属性
函数是一种特殊的对象,可以拥有属性。
function fx(a,b){
if(fx.count) fx.count++;
else fx.count=1;
return a+b;
}
fx(1,2);fx(2,3);fx(3,4);fx(4,5);
console.log(fx.count);
//4
函数方法
call( )和apply( )方法
- 通过调用方法的形式来间接调用函数。
- call( )和apply( )的第一个实参是要调用函数的主体对象,它是调用上下文,在函数体内通过this来获得对它的引用。
bind( )方法
- 将函数绑定至某个对象。
- 当在函数f( )上调用bind( )方法并传入一个对象o作为参数,这个方法将返回一个新的函数。
- (以函数调用的方式)调用新的函数将会把原始的函数f( )当做o的方法来调用。
- 传入新函数的任何实参都将传入原始函数。
- 通过bind( )为函数绑定调用上下文之后,返回的函数不能通过call和apply修改调用上下文对象。
let obj={
x:10,
show:function(y){
let r='';
for(let i=0;i<y;i++){
r+=this.x+'';
}
console.log(r);
},
};
obj.show(4);
let ss=obj.show.bind({x:1000});
ss(3);
//10101010
//100010001000
ss.call({x:2000},3);
//100010001000
let sum=function(x,y){
return x+y;
};
let succ=sum.bind(null,1);
console.log(succ(2));
let obj={};
obj.supAdd=sum.bind(obj,10);
//偏函数,固定一个函数的一个或者多个参数,返回一个新的函数,这个函数用于接受剩余的参数。
console.log(obj.supAdd(20));
//3
//30
偏函数的好处:
- 通过创建一个名称易懂的独立函数,调用是无需每次传入第一个参数,因为第一个参数通过bind提供了固定值。
- 当我们有一个很通用的函数,为了方便提供一个较常用的变体。