JavaScript函数学习笔记

学完基础,再学一下函数相关内容

函数定义

JavaScript函数定义

function定义函数,函数可以通过声明定义,也可以是一个表达式

1
2
3
function functionname(parameters){
执行的代码
}

函数表达式可以放在变量里,该变量可以作为函数使用,这样的函数也叫匿名函数(函数没有名字),通过变量名来调用:

1
2
var x = function(a,b){return a*b};
var a = x(1,2);

Function()构造函数

除了用function关键字来定义函数,还可以用内置的JavaScript函数构造器Function()定义函数:

1
2
var myfunction = new Function("a","b","return a*b");
var x = myfunction(1,2);

这个构造函数和上面定义的一样,因为JavaScript要避免用new关键字,所以感觉这个构造函数有点鸡肋

函数提升(Hoisting)

变量和函数的声明会被JavaScript解释器提升到最顶部,所以变量和函数可以在声明前使用:

1
2
3
4
add(1,2);
function add(a,b){
return a+b;
}

匿名函数无法提升

自调用函数

自调用函数会自动调用,不能自调用声明的函数:

1
2
3
(function (){
var x = "hello world";
})()

它实际上是匿名函数的自我调用

函数是对象

typeof判断函数类型会返回”function”,但把函数描述为一个对象更加准确,函数有属性和方法。

arguments.length属性返回函数调用时接收到的参数个数:

1
2
3
function add(a,b){
reutnr arguments.length;
}

toString()方法将函数作为一个字符串返回:

1
2
3
4
function add(a,b){
return a+b;
}
var txt=add.toString();

函数定义作为对象的属性,称之为对象方法。(这个我不太理解,先记住再说

箭头函数

ES6新增了箭头函数,箭头函数的语法更简洁:

1
2
3
4
(参数1, 参数2, …, 参数N) => { 函数声明 }

(参数1, 参数2, …, 参数N) => 表达式(单一)
// 相当于:(参数1, 参数2, …, 参数N) =>{ return 表达式; }

只有一个参数时,圆括号是可选的:

1
2
(单一参数) => {函数声明}
单一参数 => {函数声明}

没有参数的函数应该写成一对圆括号:

1
() => {函数声明}

实例:

1
2
3
4
5
6
// ES5
var x = function(x, y) {
return x * y;
}
// ES6
const x = (x, y) => x * y;

有的箭头函数都没有自己的this。 不适合定义一个对象的方法。

当我们使用箭头函数的时候,箭头函数会默认帮我们绑定外层 this 的值,所以在箭头函数中 this 的值和外层的 this 是一样的。

箭头函数是不能提升的,所以需要在使用之前定义。

使用 const 比使用 var 更安全,因为函数表达式始终是一个常量。

如果函数部分只是一个语句,则可以省略 return 关键字和大括号 {},这样做是一个比较好的习惯:

1
2
3
const x = (x, y) => { return x * y };
//相当于:
const x = (x, y) => x*y;

函数参数

JavaScript函数对参数不做任何检查

参数规则

函数定义时形参不指定数据类型

函数对实参没有类型检测,对实参的个数也没有检测

默认参数

ES5中如果函数调用不给实参,参数默认为undefined

1
2
3
4
5
6
7
8
9
10
function add(a,b){
if(b==undefined) b=0;
return a+b;
}
//或者写成下面这样
function add(a,b){
b=b||0;
return a+b;
}
//如果b有实参,b||0返回b,因为b是true,否则返回0,因为undefined是false

如果函数调用时设置了过多的参数,参数将无法被引用,因为无法找到对应的参数名。 只能使用 arguments 对象来调用。

ES6函数可以设置默认参数,判断undefined或者||操作:

1
2
3
4
5
6
function add(a,b=10){
//b=10 if not passed or undefined
return a+b;
}
add(1,2);//输出3
add(1);//输出11

arguments对象

函数有个内置的arguments对象,包含了函数调用时的参数数组,通过这种方式可以很方便的找到参数里的最大值或者求和:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function findmax(){
var i,max=arguments[0];
if(arguments.length==1) return max;
for(i=1;i<arguments.length;i++){
if(arguments[i]>max) max=arguments[i];
}
return max;
}

function sum(){
var i,sum=0;
for(i=0;i<arguments.length;i++){
sum+=arguments[i];
}
return sum;
}

参数相关

函数调用时如果引用对象的值,那么函数内修改对象的属性会作用于函数外,修改对象属性在函数外是可见的,相当于C语言的引用。

JavaScript函数调用

JavaScript 函数有 4 种调用方式。

每种方式的不同在于 this 的初始化。

this关键字

this指向当前对象

作为函数调用

1
2
3
4
function add(a,b){
return a+b;
}
add(1,2);

这个函数不属于任何对象,但是它是默认的全局对象,在HTML中默认的全局对象是HTML页面,所以函数属于HTML页面,在浏览器中的页面对象是浏览器窗口(window对象),所以它也是window对象的函数,所以可以用window.add(1,2)来调用函数。

函数作为方法调用

JavaScript可以将函数定义为对象的方法

1
2
3
4
5
6
7
8
var myName={
firstName='tian',
lastName='ze',
fullName: function(){
return this.firstName+" "+this.lastName;
}
}
myName.fullName();

对象方法调用函数时,this指向该对象

用构造函数调用函数

函数调用前用new关键字调用构造函数,构造函数的调用会创建一个新的对象,新对象会继承构造函数的属性和方法。

1
2
3
4
5
6
function name(arg1,arg2){
this.firstName=arg1;
this.lastName=arg2;
}
var a=new name("Tian","ze");
x.firstName; //返回"Tian"

函数方法调用函数

函数是对象,对象有属性和方法,call()apply()是预定义的调用函数的两个函数方法,两个方法的第一个参数必须是对象本身。

1
2
3
4
5
var obj1;
function add(a,b){
return a+b;
}
obj1=add.call(obj1,1,2); //返回3
1
2
3
4
5
6
var obj2,myarray;
function add(a,b){
return a+b;
}
myarray=[1,2];
obj2=add.apply(obj2,myarray); //返回3

两个方法第一个参数都是对象本身,第二个参数有区别:apply传入的是一个参数数组,call直接传参。

JavaScript闭包

JavaScript 变量可以是局部变量或全局变量。

私有变量可以用到闭包。

函数内定义的为局部变量,函数外定义的为全局变量,在web页面中全局变量属于window对象,全局变量可以用于页面上的所有脚本。

注:变量声明时如果不用var关键字,即使在函数内定义也是全局变量

计数器困境

使用全局变量计数器,用函数让它递增

1
2
3
4
5
6
var counter=0;
function add(){
return counter++;
}
add();
add(); //计数器为2

问题来了,页面上任何脚本都能改变计数器,如果在函数内声明计数器就无法实现计数的功能了:

1
2
3
4
5
6
function add(){
var counter=0;
return counter++;
}
add();
add(); //本想输出2,但输出是1

内嵌函数可以解决这个问题

JavaScript内嵌函数

JavaScript函数可以访问上一层的作用域,嵌套函数可以访问上一层的函数变量:

1
2
3
4
5
6
7
8
function add(){
var counter=0;
function plus(){
counter++;
}
plus();
return counter;
}

如果能在外部访问plus()函数就可以解决计数器困境,可以利用闭包做到。

JavaScript闭包

1
2
3
4
5
6
var add=(function (){
var counter=0; //只在add赋值时执行一次
return function(){return counter++;}
})();
add();
add(); //计数器为2

变量add指定了函数自我调用的返回值

自我调用函数只执行一次,设置计数器为0

add变量可以当函数来用,它可以访问函数上一层作用域的计数器

这就是闭包,它使函数拥有私有变量变成可能

计数器受匿名函数的作用域保护,只能通过add方法修改

闭包这个点不是很懂,看了下面网友的一些笔记后有点明白了,闭包用于面向对象编程的”封装性”,相当于java类里面的一个公用接口,因为JavaScript没有访问修饰符所以不能创建私有属性,外部可以通过闭包访问私有属性。

此技巧是js为其没有“访问修饰符”而创建出“私有属性”。

以包含面向对象编程语言的基本特征“封装性”的很妙的处理方法。

参考

https://www.runoob.com/js/js-function-definition.html

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2020-2021 Blog of Tianze

请我喝杯咖啡吧~

支付宝
微信