一、函数的定义和参数
函数的定义:
function 函数名(参数列表){函数体}
参数:形式参数(形参);实际参数:实参
形式参数:函数中形式上参与运算的数据。只是一个占位符。
1:函数定义的时候的小括号中的内容:形参列表。
2:形参的作用,用来接收方法的使用者传递的实际的参数。
3:形参的个数没有限制,也不需要添加var关键字。直接写参数的名字即可。
形参的名字和变量的名字的规范一致。形参就是局部变量。只能在方法内使用。
多个形参之间使用逗号分隔。
4:形参的名字要能体现出要接收的实参的数据的内容。
实际参数:函数中实际参与运算的数据。
1:实参的个数通常要和形参的个数一致。
2:实参的个数如果少于形参的个数。多余的形参的值为 undefined。
3:函数调用的时候,是将实参的值按照顺序依次赋值给形式参数。
4:实参可以是任意的有返回值的js的表达式。
5: 实参之间使用逗号分隔。
二、函数调用的传参问题
函数调用的时候。
会进行参数的传递:将实参的值依次赋值给形式参数的过程。
<script>
var num1=10;
var num2=20;
/* var temp = num1;
num1 = num2;
num2 = temp;*/
change (num1, num2);
console.log (`num1 = ${num1}\tnum2 = ${num2}`);
function change(val1, val2) {
console.log (`val1 = ${val1}\tval2 = ${val2}`);
var temp = val1;
val1 = val2;
val2 = temp;
console.log (`val1 = ${val1}\tval2 = ${val2}`);
}
</script>
三、程序中的内存说明
js中的数据占用的内存,主要分为了2部分。
1:栈内存 stack
全局变量、函数内的局部变量。
栈是一种数据结构。
数据结构:具有某种关系的一组数据的集合。类似一个容器,容器中保存了
很多的数据,数据之间存在某种关系。不同的数据结构中的数据的关系是不同的。
不同的关系,导致了访问数据结构中的数据的特点不同。
学习数据结构,要了解数据结构中的数据的关系和特点。
2:堆内存 heap
对象
四、函数的返回值
函数的分类:
按照返回值:有返回值的函数、无返回值的函数。
1:如果希望函数执行完毕之后,函数自身会带有一个结果,那么该函数就需要有返回值。
2:如果希望函数执行完毕之后,不要一个结果,只是实现了某些功能,那么就不需要有返回值。
没有返回值的函数有一个默认的返回值undefined。
如何让一个函数执行完毕之后有一个结果?
要通过一个js关键字实现:return;
如果我们希望一个函数执行完毕之后返回一个结果,那么在函数体内,必须使用关键字 return 后面
跟你需要返回的结果的表达式。
格式:return 结果;
return 的使用方式:
1:在有返回值的函数内,使用return 返回需要返回的值。 return 值;
2: 在不需要返回值的函数内使用,直接使用 return; 用来结束函数的执行的。
3:return 只能在函数中使用,别管后面是否有值,那么一旦使用了return,那么函数立即结束执行。
一般称为 【函数返回】。
<script>
//需求,求任意两个数的最大值。 这个需求的函数应该要有返回值,返回的是两个实参中比较大的那个
function max(num1, num2) {
var max = num1 > num2 ? num1 : num2;
return max;
}
/**
* 检查 指定的数是质数还是合数,打印结果
* @param num 要检查的数
* 如果不是合法的数据,返回 -1,如果是质数返回0,如果是合数返回1.
*/
function checkNumber(num) {
//特殊情况
var str = typeof num;
if (str !== "number") {//不是数值类型
return -1;
} else if (num <= 1) {
return -1;
} else {//大于1 的数。
//小数的情况
var temp = ~~num;
if (temp != num) {//小数
return -1;
} else {
//一般情况
var flag = false;
for (var i = 2; i < num; i++) {
if (num % i === 0) {//合数
flag = true;
break;
}
}
if (flag)
return 1;
else
return 0;
}
}
}
console.log (max (1, 2));
console.log (checkNumber (null));
console.log (checkNumber (1));
console.log (checkNumber (3));
console.log (checkNumber (4));
//求任意数的绝对值
function abs(num) {
if (num < 0)
return -num;
return num;
}
function abs(num) {
return num < 0 ? -num : num;
}
console.log (abs (-1));
console.log (abs (2));
//
/**
* 判断一个数是否是质数
* @param num 被判断的数
* 如果num 值质数,返回true,否则false。
*/
function isPrime(num) {
//特殊情况
var str = typeof num;
if (str !== "number") {//不是数值类型
return false;
}
if (num <= 1) {
return false;
}
//大于1 的数。
//小数的情况
var temp = ~~num;
if (temp != num) {//小数
return false;
}
//一般情况
var flag = false;
for (var i = 2; i < num; i++) {
if (num % i === 0) {//合数
return false;
}
}
return true;
}
console.log (isPrime (null));//false
console.log (isPrime (0));//false
console.log (isPrime (2));//true
console.log (isPrime (11));//true
console.log (isPrime (12));//false
//判断某个一数知否是 true
function isTrue(val) {
return val === true;
}
//实现求四舍五入的函数
function round(num) {
//正数情况
var val = num - ~~(num);
if (val >= 0.5) {
return ~~(num + 1);
}
return ~~num;
}
console.log (round (1.1));//1
console.log (round (1.5));//2
console.log (round (1.51));//2
console.log (round (1.9));//2
</script>
五、函数的使用
有返回值的函数的使用:
1:直接调用。(很少)
2: 用一个变量接收方法的返回值。(最多的)
3: 作为操作数使用。(不多)
4: 作为函数调用的实参使用。(不多)
5: 作为log函数的实参直接打印。(现阶段比较多)
无返回值的函数的使用:
1:直接调用。
<script>
function random(min, max) {
return ~~(Math.random () * (max - min) + min);
}
//1
random (1, 100);
//2
var num = random (1, 299);
//3
num = 1 + random (1, 20);
//4
num = random (random (1, 20), random (30, 80));
//5
console.log (random(1,20));
//1: 无参直接调用。
function log(msg) {
console.log (msg);
}
log(true);
</script>
六、js中不存在函数重载
函数的重载:overload。
1:概念:方法名字相同,形参列表不同的函数,称为函数的重载。
在js中不存在重载这个问题。如果多个方法的名字相同,那么后定义的会覆盖前面的
<script>
//会被覆盖掉
function add(num1, num2) {
return num1 + num2;
}
//这个会覆盖掉上面的
function add(num1, num2, num3) {
return num1 + num2 + num3;
}
console.log (add(1,2));//NaN
console.log (add(1,2,3));//6
</script>
七、函数的定义的几种方式:
js中关于函数定义的几种方式:
1:方法声明方式 使用最多的。
function 方法名(参数列表){方法体}
2:方法的直接赋值方式 使用一般多。
var 变量名 = function(参数列表){方法体}
匿名方法定义的形式。
3: 使用构造函数。 基本不用
var 变量名 = new Function(“参数列表”,“方法体”);
所有的function 实例。函数对象都是通过 构造函数 Function 创建出来的。
三种定义方式的区别:
1:第一种方式,可以在定义之前和之后调用该方法。而且方法是有名字的。
2: 第二种方式,是匿名的函数,是将一个匿名函数赋值给了一个变量。还有该方式,必须先
定义后使用。
3:第三种方式,很繁琐,必须先定义后使用。
<script>
//
test();
//函数定义的直接声明方式
function test() {
console.log ("helloworld!");
}
test();
// sum 是一个对象变量,通过变量名来访问。
sum(1,2);
var sum = function (num1,num2) {
return num1 + num2;
}
console.log (sum(1,2));
var value = 10;
// 使用构造函数
var log = new Function("","{alert('helloworld')}");
log();
</script>
八、定义函数的几点建议
1:能用局部变量实现的就使用局部变量,不使用全局变量。
2:函数内,先处理特殊问题,然后最后处理一般问题。
3:给函数添加适当的注释,文档注释,给参数添加注释。包括返回值的注释。
4:函数实现的功能越单一越好。越容易实现复用。
5:方法体不要过长。一般不建议超过50行。如果方法体过长,需要适当的拆分。
6:方法越短小精悍越好。
7:注意方法的命名,和参数的命名的规范性。
<script>
//A B
function a() {
// ...
}
function b() {
}
a,b
a()b()
// function a(a,b,c) {
// ...
// }
</script>
九、局部变量和全局变量
变量的作用域:
变量可以被访问的范围。
变量的分类
1:全局变量
在方法外定义的,script标签内定义的变量。就是全局变量。
2: 局部变量
在方法内定义的变量就是局部变量。
局部变量和全局变量的不同
1:作用域不同。
a:全局变量的作用域是整个script代码块。包括里面的方法体中.
b:局部变量的作用域就是其所在的方法范围内。
2: 生命周期不同。
a:局部变量的生命周期从方法开始调用开始,从方法结束调用结束。
依赖于所在的方法何时被调用。
b:全局变量的生命周期从script代码块开始加载就开始了。关闭浏览器的时候结束。
3:如果全局变量和局部变量的作用域存在冲突:被访问的优先级不同。
a:局部的高于全局的。
b:如果在冲突的作用域中访问全局的变量,可以通过 window.变量 或者是 this.变量 访问
总结:
1:全局的变量会一直占用内存空间。
2:js中可以重复定义变量,可能会出现多次定义一个全局变量。在函数内没有使用var 定义变量污染了全局数据。
<script>
//全局变量
var num = 0;
var val = 10;
var number = 100;
function fn() {
//局部变量 和 全局变量存在命名的冲突。
var num = 10;
console.log ("局部:"+num);//10
//访问全局变量
console.log (window.num);//0
console.log (this.num);//0
var value = 10;
//访问全局变量
val = 100;
number = 100;
}
fn();
var val = 200;
function a() {d();}
function c() {}
function d() { c();}
function test() {
a();
}
</script>
十、方法练习
1:自定义函数,实现求任意数的,任意次幂的方法。只针对正整数。
2:自定义函数实现求任意正整数的开方的函数。(不用要求精度很高)
小数点后保留3位。
<script>
// console.log (2**3);//8
/**
* 求value 的num 次幂
* @param value
* @param num
* @returns {number}
*/
function power(value,num) {
var result = 1;
for (let i = 0; i <num ; i++) {
result *= value;
}
return result;
}
console.log (power(4,3));//64
console.log (power(3,4));//81
/**
* 求任意数的平方根
* @param num
* @returns {number}
*/
function sqrt(num) {
var result = num;
while(true){
var value = result * result;
if(value > num){
result -= 1/64;
continue;
}else{
return result;
}
}
}
console.log (sqrt(16));
</script>
十一、局部方法定义介绍
局部方法的使用: 了解一下。
<script>
function test() {
fn();
//局部方法。
function fn() {
console.log ("helloworld");
}
fn();
return fn;
}
var fn1 = test();
console.log ("-------------");
fn1();
</script>
十二、let和var的区别
let 关键字:用来定义变量的。let的后期版本推出的新的关键字。
var 关键字:用来定义变量的。
不同点:
1-1:let 定义的变量具有块级作用域。在代码块定义的变量只能在代码块中使用。出了代码块就不能被访问了。
1-2:var 定义的变量不具有块级作用域。在代码块中定义的变量,就是全局的变量。
2-1:使用var声明的全局变量会作为window的属性存在。可以通过 window. 访问全局变量。
2-2: 使用let 定义的全局变量不会作为window的属性存在。
3-1: var 可以重复定义同名变量,后面会覆盖前面的。
3-2: let 不可以重复定义同名变量。
总结:var 定义变量不够严谨,let定义变量更加的严谨。
<script>
let value = 10;
// let value = 10;
var num = 10;
var num = 100;
if (true) {
//把外面定义的变量污染了。
var num = 100;
//不会污染全局的value。
let value = 20;
}
console.log (num);//100
console.log (value);//10
function test() {
console.log ("hello");
}
console.log (window.num);//100
window.test ();//hello
console.log (window.value);//undefined
</script>
十三、方法的执行符
方法的执行符:()
调用方法,必须使用方法名+()
执行符的作用:定义匿名函数,并直接执行。
<script>
function test() {
console.log ("hello");
}
//直接打印方法的名字,输出的是方法的完整的定义的形式。
/*
ƒ test() {
console.log ("hello");
}
*/
console.log (test);
//调用方法
test();
var fn = function () {
console.log ("world");
}
/*
* ƒ () {
console.log ("world");
}
* */
console.log (fn);
fn();
//定义匿名函数,并执行该函数,不要有全局方法名字。
(function () {
console.log ("world11111");
})();
//使用函数作为实参,在方法内执行实参函数。
function fn1(fn) {
fn();
}
console.log ("------------");
fn1(test);
fn1(function () {
console.log ("我是匿名函数")
});
</script>