JS函数

JS函数的定义

函数的定义:

函数是计算机编程中非常重要的一个语法结构。那么什么是函数呢?函数指一组可以随时随地运行的代码集合,当他被调用时可重复的去执行这些代码集合。
类比数学中的函数:
数学中的函数指给定一个数集A,对A施加对应法则f,记作f(A),得到另一数集B,也就是B=f(A).那么这个关系式就叫函数关系式,简称函数。


函数声明

定义函数

JS中创建函数有三种方式:

  1. 函数声明
  2. 函数表达式
  3. 函数对象

1.函数声明

1
2
3
4
5
function foo(){
console.log(123);
}

foo();//调用函数

2.函数表达式

1
2
3
4
5
var foo = function () {
console.log(123);
}

foo();

3.函数对象(了解)

1
2
var foo = new Function();
foo();

关于函数声明及解析

1.函数声明会预解析(仅在当前所在的script块内)

1
2
3
4
5
foo();	//控制台打印123

function foo(){
console.log(123);
}

2.函数表达式不具备预解析功能

3.变量解析要高于函数的预解析

1
2
3
4
5
console.log( a );//控制台打印 f a ( )	{ }
function a(){

}
var a = 10; // 变量预解析要高于函数的预解析

4.函数表达式可直接调用执行

1
2
3
4
5
var foo = function(){  //函数表达式可直接调用执行
console.log(123);
console.log(456);
console.log(789);
}();

但函数声明是不能直接调用的

1
2
3
4
5
function foo(){   //函数声明是不能直接调用的
console.log(123);
console.log(456);
console.log(789);
}();

关于函数变量的区域性

程序寻找参数的时候只能够寻找和它同级或外层的变量,无法向内层找变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function foo(){
var b = 20;
}
function baz(){
console.log( b );
}
foo();
baz();// =>报错,找不到b

var b;
function foo(){
var b = 20;
}
function baz(){
console.log( b );
}
foo();// =>b重新赋值 b = 20;
baz();// =>打印 20

变量提升问题

先甩一道经典变量提升题

1
2
3
4
5
6
var a = 10;
function foo() {
console.log(a); // ??
var a = 20;
}
foo();

问控制台打印的结果是多少?

思考

答案 : undefined
使用var关键字声明的变量在JavaScript中会被提升,并在内存中分配undefined,但初始化却发生在你给变量赋值的地方,另外var声明的变量是函数作用域的,所以上述代码块解析可以看做以下过程

1
2
3
4
5
6
7
8
9
10
var a = 10; // 全局使用域
function foo() {
// var a 的声明将被提升到到函数的顶部。
// 比如:var a

console.log(a); // 打印 undefined

// 实际初始化值20只发生在这里
var a = 20; // local scope
}

上边的代码块理解了下边的代码块理解起来就很方便了

1
2
3
4
5
6
7
8
var a = 18;
f1();
function f1(){
var b=9;
console.log(a);
console.log(b);
var a = '123';
}

答案 : undefined , 9
解析过程直接以代码形式呈现,看起来比较容易理解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//第一步:预解析
var a;
//第三步:当执行函数时,再次进行预解析(局部作用域)
function f1(){
var b;
var a;
//第四步:一行一行执行代码
b=9;
console.log(a);
console.log(b);
a = '123';
}
//第二步:一行一行执行代码
a = 18;
f1();

JS函数参数

1
2
3
4
5
function foo(n){  //形式参数:形参   var n = 123
console.log(n);
}

foo(123); //实际参数:实参 */

实参的个数和形参的个数不一定要一样

1
2
3
4
5
function foo(n1,n2,n3){  
console.log(n3);
}

foo('a','b');

arguments对象:表示实参的集合

arguments.length : 获取集合长度

通过 [] 获取集合数组的下标

1
2
3
4
5
6
7
8
9
10
11
 function foo(){  
console.log(arguments.length);
console.log(arguments[0]);
var result = 0;
for(var i=0;i<arguments.length;i++){
result += arguments[i];
}
console.log( result );
}

foo(1,2,3,4,5);

关于JS中函数的参数

得益于此文的启发

函数的参数属于函数的内部变量,外部无法访问到,即使和外部变量同名,它们也是两个不同的变量

1
2
3
4
5
6
7
8
var a = 100;

function test(a){
a++;      //a(形参)是局部变量
console.log(a);
}
test(a);
console.log(a); //结果是 101 100;

类似于:

1
2
3
4
5
6
7
8
var a = 100;
function test( ){
var a=100; //a是局部变量
a++;
console.log(a);
}
test( );
console.log(a); //结果 101 100;

当函数没有定义参数或者内部没有var变量,内部的变量默认为全局变量

1
2
3
4
5
6
7
var a =100;
function test (){
a++;
console.log(a);
}
test();
console.log(a);//控制台打印 101 101 ,因为a是全局变量

当函数定义了参数,但没有传实参的时候,形参默认为undefined

1
2
3
4
5
6
7
var a = 100;
function test(a){
a++;
console.log( a );
}
test();
console.log( a );//第一个返回undefined 第二个返回100

但是如果通过对象传递参数,函数内部对象属性值发生改变,外部被传递对象的属性值也会改变

1
2
3
4
5
6
7
var a = {x : 100};
function test(a){
a.x++;
console.log( a.x );
}
test(a);
console.log( a.x );//第一个返回101,第二个返回101

总结:
通过值传递参数: 在函数中调用的参数是函数参数(属于局部变量范畴),如果函数修改参数值,将不会改变外部被引用的实参值
通过对象传递参数:对象属性的变量是相当于指针,因此函数修改对象的属性值时,外部的对象属性也会改变。
这也涉及到基本类型和引用类型的值,基本数据类型(undefined、null、boolean、Number)是按值访问的,所以局部变量与全局变量即使名字一样,也是两个不同的变量
总而言之
1.函数参数是被当做变量对待的
2.参数是按值传递的
3.传递参数的时候要确定传递的数据类型

对象属于引用类型,当变量是一个对象时,将这个变量赋给另一个变量时,相当于另一个变量也变为了指针;两个变量都指向同一对象;所以在引用数据类型照片中,变量相当于一个指针^[注:JavaScript高级程序设计第四章 变量、作用域和内存 有详细介绍]


return

返回值return : 表示函数执行完的返回值,当函数没有写return的时候,函数调用完就会变成undefined然后return;
return 类似于跳出操作,所以return后的代码是不执行的

1
2
3
4
5
6
7
8
9
function foo(){

console.log(123);
return 456;
console.log(789);//return后面的代码不执行
}

console.log( foo() );// 控制台打印 123 456


函数作用域和作用域链会单写一篇


函数与事件

JS事件

鼠标、键盘触发的一些功能(一些功能就是自己定义的函数,跟事件关联的函数叫做事件函数)

事件函数

onclick : 点击(不只是鼠标,键盘也可以)
ondbclick : 双击
onmousedown :鼠标按下
onmouseup:鼠标抬起
onmouseover:鼠标移入
onmouseout:鼠标移出
onmousemove:鼠标移动(连续触发)


代码简化

举个栗子,以前我们获取元素的时候,需要下边这么多的代码

1
2
3
4
var elem1 = document.getElementById('elem1');
var elem2 = document.getElementById('elem2');
var elem3 = document.getElementById('elem3');
var elem4 = document.getElementById('elem4');

而如果我们把它封装到一个函数里,每次取元素的时候调用,不是方便多了

1
2
3
4
5
6
7
8
var elem1 = $('elem1');
var elem2 = $('elem2');
var elem3 = $('elem3');
var elem4 = $('elem4');

function $(id){
return document.getElementById(id);
}

常用内置函数

alert()

提示框

1
alert(123);

alert

confirm()

确定对话框

1
confirm('你好');

confirm

prompt();

输入对话框,返回值就是输入的内容

1
2
3
4
5
6
7
var result = prompt('我叫什么' , '请输入名字');
if(result == 'xiaoming'){
console.log('添加好友');
}
else{
console.log('拒绝添加');
}

enter description here

转换数字

这里简述两种方法parseInt()parseFloat()

parseInt()

将字符串转换成整数

1
2
var str = '123px';
console.log( parseInt(str) );//控制台打印 123

parseInt()会从左至右挨个转换直到不能转换为止

parseFloat()

将字符串转换成浮点数

1
2
var str = '123.45';
console.log( parseFloat(str) );

isNaN()

判断是否是NaN,是返回true,不是返回false
但是因为JS历史原因……还是有BUG的

1
console.log( isNaN('hello') );//控制台打印 true 

很显然 hello 类型是字符串,不是NaN,但是为什么会返回true呢
看一眼 w3cschool对isNaN返回值的定义:

如果 x 是特殊的非数字值 NaN(或者能被转换为这样的值),返回的值就是 true。如果 x 是其他值,则返回 false。

也就是说程序内部会首先把hello转换成Number类型,自然就变成了NaN,然后再进行isNaN的判定。
ES6提供了一种更为严谨的判断是否是NaN的方法:Number.isNaN()

现在用这个新方法来判断一下hello是不是NaN

1
console.log( Number.isNaN('hello') );//输出false

isFinite()

判断是否是无限数字,如果是有限数字返回true,如果不是则返回false

Infinity:无限大

-Infinity:无限小


Math对象

Math.min():取最小值
Math.max():取最大值
Math.cell():向上取整
Math.floor():向下取整
Math.pow():平方
Math.sqrt():开平方
Math.abs():取绝对值
Math.PI:π值
Math.random():随机一个 [0,1) 区间的数
Math.round():四舍五入

如果我想要开三次方或者多次方怎么办

1
>Math.pow(8,1/3);//开8的三次方

举一反三

初探this关键字

这里只介绍this最简单的指向,即this会指向当前事件所操作的元素



JS函数
https://moewang0321.github.io/2019/08/07/2019-08-07-JS函数(一)/
作者
Moe Wang
发布于
2019年8月7日
许可协议