第四天笔记(函数)
函数概述
函数相当于一个代码空间,他里面可以存储一些代码片段,就是利用函数来减少冗余代码的出现,形成对应的复用。一般我们会将一些功能性代码抽取放入到函数内,这样的操作就是封装。函数的核心就是利用函数来减少冗余代码的出现,形成对应的复用。
函数的分类
-
系统函数 属于系统的函数(属于global对象的函数的 alert() console.log() isNaN()...)
-
内置函数 属于对应的内置对象的函数 (Math.pow()...)
-
自定义函数 自己定义的函数(自己封装抽取的代码)
函数的定义
使用function关键字来定义
定义的方式有三种
匿名函数(没有名字的函数 无法被调用)
// 自执行函数 自己执行 准备工作的执行(框架的封装)
// 前面的()表示他是一个整体 后面的()是调用
(function(){
console.log('匿名函数')
})()
具名函数(有名字的函数 有复用性 推荐)
function sayhi(){
console.log('hi')
}
sayhi()// 调用
// 结合匿名函数来声明具名函数
var a=function saysb(){
console.log('sb')
}
使用对象构建(new 关键字来构建 不推荐)
var fn=new Function("console.log('你好')")
函数的执行过程
预编译过程
var 关键字修饰的变量会预编译
console.log(a)// undefined
var a=10
console.log(a)// 10
function 也会发生预编译
fn()// 也执行 输出哈哈 fn会被执行
function fu(){
console.log('哈哈')
}
fn1()// 报错 (is not a function) var 关键字预编译不会读取赋值操作
var fn1=function(){
console.log('test')
}
执行过程
-
函数声明会发生预编译 调用的时候会发生什么操作
-
他回去寻找对应堆空间的函数引用然后再将他推入执行栈中 进行执行
-
在执行栈中会打开对应的函数内的代码进行执行 当他执行完毕以后 那么gc就会见他回收(可达性)
可达性:目标是描述达到期望目标集的初始条件集。在有控制输入的情况下,控制综合涉及到控制器的设计,使得从给定初始条件开始的状态轨迹达到期望的集。
回收流程
gc是一个垃圾回收机制 (用于回收当前没有使用的内存)
回收器
主回收器 Major gc (常用的 回收大的对象)
副回收器 Minor gc (回收碎片 使用较频繁)
回收机制
标记清楚 (设置true false 标记)
引用计数 (引用操作进行++)
函数的参数
没有实际的参数叫形参 用于定义
有实际的参数叫实参 用于传递
示例:
function sum(a,b){// 形参
console.log(a+b)
}
sum(1,2)// 实参
注意事项
js 允许少传参 必须这个参数没有被使用到 否则报错
function sum(a,b){// 形参 b就是 undefined
console.log(a+b)// 输出NaN
}
sum(1)// 实参
练习
传递一个数 判断是否回文
function a(b) {
// 判断参数是不是数值
// if (typeof b == 'number') {
// console.error('输入出错');// 错误提示
// } else {
if (typeof b != 'number') {
throw new Error('输入出错');// 抛出错误
}
var x = b //接受数值
var y = 0 //接受反转的内容
// 各位数是0的不可能是回文数
if (b % 10 == 0 && b != 0) {
console.log('这个数不是回文数');
} else {
if (x < 10 && x >= 0) { //如果当前的数是小于10的整数
console.log('该数是回文数')
}
while (x > y) { //反转条件 x>y
y = y * 10 + x % 10
x = parseInt(x / 10)
}
if (x == y) {
console.log('该数是回文数')
} else if (parseInt(y / 10) == x) { //奇数位
console.log('该数是回文数')
} else {
console.log('该数不是回文数')
}
}
// }
}
a('ac')
传递一个数 判断是否是水仙花数
function b(z) {
if(typeof z !='number'){
throw new Error('输入错误')
}
var b = parseInt(z / 100);
var c = parseInt(z % 100 / 10);
var d = parseInt(z % 10);
if (b ** 3 + c ** 3 + d ** 3 == z && 100 <= z && z <= 999) {
alert(z+'是水仙花数')
} else {
alert(z+'不是水仙花数')
}
}
b(153)
函数考虑其复用性的同时,必须要考虑多种情况的产生
return关键字
return 是用于在函数中返回对应的结果的,默认情况下函数return undefined.当return完那么对应的函数执行就结束了
练习
输入两个数返回他们最小公倍数和最大公约数的和
function a(f, l) {
if(typeof f!='number' || typeof f!='number' || f<=0 || l<=0){
// 输入有问题就抛出错误
throw new Error('输入出错');
}
var max = Math.max(f, l);
var min = Math.min(f, l);
var sum=0;
for(var i=max;;i++){
if(i%min==0&&i%max==0){// 最小公倍数
sum=i+i/min; // 最小公倍数等于 最大公约数*min
return sum;
}
}
// for(var i=min;;i--){
// if(min%i==0&&max%i==0){
// return sum+=i;
// }
// }
}
console.log(a(9,6));
总结
break 跳出循环(switch)不会结束 function
continue 只能用于循环
return 结束整个函数,返回对应的数据(一般放在最后)
throw new Error 结束整个程序
arguments
arguments 是参数列表,参数列表是一个伪数组 (伪装的数组,有数组的特性,但不是数组(不具备数组的方法)),它可以用于获取所有的参数(传递的参数)
function fn(a,b,c){
console.log(arguments)
// arguments 有length属性
console.log(arguments.callee);// callee 指向的是当前方法
console.log(arguments[0])// 获取第一个参数
console.log(arguments[1])// 获取第二个参数
}
fn(1,2) //打印[1,2]
arguments 的属性及方法
-
length 属性 用来获取对应的传入参数个数
-
callee 方法 指向当前的函数
-
arguments 访问对应的参数使用下标访问
-
下标从0开始 到length-1结束
-
0表示第一个参数
-
省略对应的形参 直接传入实参 在函数中使用arguments 来接收的对应的实参
示例
function sum(){// 通过arguments 来对实参进行操作 省略形参
result=0
for(var i=0;i<arguments.length;i++){// 用length 属性决定循环次数
// 通过arguments 来对实参进行操作
result+=arguments[i]
}
console.log(arguments.callee);// callee 指向的是当前方法
return result
}
console.log(sum(3,4,8))
作用域及作用域链
作用域概述
一个变量的作用范围称为作用域,作用域主要划分为全局作用域(全局可用)和局部作用域(函数作用域,局部可用)
示例
var a=10 // 全局作用域
function b(){
var a=20;// 局部作用域 外部访问不到
console.log(a)// 20 在局部中当前局部作用域的变量权重大于全局
}
console.log(a)// 10
console.log(c)// 报错 b is not defind
在全局中不能访问局部作用域的变量
console.log(a);// undefined
var a=10
function fn(){
a=20 // 这里赋值给局部的变量 a 就近原则
console.log(a)
var a=30
}
function fn1(){
a=40 // 赋值给全局作用域的a
var b=30
console.log(a+b)
}
function fn2(){
console.log(a);
var a=50
}
fn1()// 70
console.log(a);// 40
fn()// 20
console.log(a);//40
fn2()// undefined
console.log(a);// 40
var 关键字会进行变量提升
只要说函数中使用了var 关键字声明那么这个变量就是局部变量 那么这个里面使用到所有这个变量都是指向这个局部变量
如果在函数中没有使用var 关键字声明那么这个变量就是全局变量
作用域链
作用域链就是逐层向上查找对应的作用域(变量声明) 形成的链子,如果没有找到那么就会报错 就近原则
事件驱动
事件驱动就是通过触发一个行为执行对应的函数,这个被称为事件驱动
简单的一个dom操作
获取对应的dom元素
var 变量 = document.getElementById('对应的标签的id属性')
给对应的变量添加点击事件
变量名.onclick = 处理函数
递归
递归是一个算法,算法就是固定的套路,递归算法是为了降低时间复杂度提高效率所设计的算法,它可以完成所有循环能干的事
递归的用途
(可以在不知道层级的情况下走到底)
-
文件目录遍历
-
DFS 查找
-
多级对象分析合并
-
深拷贝
-
······
递归的流程 (Ologn)
-
初始值(不变的值)
-
规律
-
自己调自己
示例
function 函数名(参数){
if(条件){
初始值赋值
}else{
规律值赋值操作 自己调自己
}
}
求1+···+100的和
function fn(n){// n为次数 1次值为1 2次值为3
if(n==1){
return 1;
}else{
return n+fn(n-1)
}
}
console.log(fn(100))// 5050
求1-100之间的偶数和
function fn(n){
if(n==1){
return 2;
}else{
return fn(n-1)+2*n
}
}
console.log(fn(50));
练习
1 1 2 3 5 8 13 21 第20位是什么
function fn(n){
if(n==1){
return 1
}else if(n==2){
return 1
}else{
return fn(n-2)+fn(n-1)
}
}
console.log(fn(20));
1 3 6 10 15 第10位是什么
function fn1(n){
if(n==1){
return 1
}else{
return fn1(n-1)+n
}
}
console.log(fn1(10));
1 1 2 3 6 11 20 第20位是什么
function fn2(n){
if(n==1){
return 1
}else if(n==2){
return 1
}else if(n==3){
return 2
}else if(n==4){
return 3
}else{
return fn2(n-1)+fn2(n-2)+fn2(n-3)
}
}
console.log(fn2(20));
1 5 11 19 29 41 第15位是什么
function fn3(n){标签:function,console,log,笔记,第四天,var,return,函数 From: https://www.cnblogs.com/balloontrue/p/17106997.html
if(n==1){
return 1
}else{
return fn3(n-1)+2*n
}
}
console.log(fn3(15));