js函数

95 阅读4分钟

js函数

概述

函数是抽取的公共代码块,主要是为了复用。函数相当于一个工具需要的时候就可以调用,当我们没有这个工具就需要自己封装。

函数的分类

  • 系统函数 (console.log、 toString 等 )
  • 内置函数 (Math.pow等)
  • 自定义函数 (自己定义的函数)

函数的定义

使用function关键词声明定义 (推荐)
匿名函数的定义 (没有函数名的函数)
function(){
	代码块
}

示例

//自执行函数 不需要调用 自动执行(早期的源码设计)
(function () {
    console.log('hello world!!')
})()
//使用变量接收匿名函数的函数对象 相当于接收的变量名为函数名(具名函数的第二种写法)
var fn = function () {
    console.log('我是匿名函数')
}
//调用 函数名()
fn()
具名函数的定义 (有函数名的函数 复用)
function 函数名(){
	代码块
}

示例

function logFn(){
	console.log('我是具名函数')
}
//函数调用
logFn()
使用new 关键构建函数对象(不推荐)
var 函数名 = new Function('执行的代码')

示例

//new关键词构建函数对象
var fn = new Function('console.log("hello!!!")')
//函数调用
fn()

预编译机制

概述

预编译指的是js引擎预先编译,它主要针对的是俩个一个使用var关键修饰的变量会进行预编译,使用function修饰的函数会进行预编译。

注意事项
  • var关键词不包含赋值过程
  • 函数的预编译会比var关键词慢 如果var关键词修饰的变量和函数名同名,那么在预编译的时候函数会覆盖var。
//预编译 就是预先编译 就是指你没执行倒对应的步骤 可以使用预编译的东西
console.log(1)
console.log(2)
console.log(a) //undefined
fn() //可以调用
//var关键词会进行预编译的操作 预编译不包含赋值
var a = 10
//函数也会进行预编译
function fn() {
    console.log('123')
}
//函数的预编译慢于var 函数的内容会覆盖var的内容
var fn = 20
console.log(fn) //20
//关键问题
// 具名函数的变量赋值写法
console.log(fn1) //undefined
var fn1 = function () {
    console.log('我是匿名函数')
}
console.log(logFn)//函数
// 具名函数的标准声明写法
function logFn() {
    console.log('我是具名函数')
}

函数支持传入参数

关键词
  • 形参 (形容的参数)
  • 实参 (实际的参数 (实际的值))
函数的参数定义
function 函数名(形参1,形参2,形参3....){
	代码块
}
示例

求和函数

//a b 为形参
function sum(a, b) {
    console.log(a + b)
}
//调用需要传入实参 按照顺序一一对应
sum(1, 2)
练习

封装一个判断是否为回文数的方法

function isPalindrome(number) {
    //如果类型不是数值
    if(typeof number != 'number'){
        //抛出一个错误 直接终止程序 后面的内容也不再执行
        throw new Error('参数类型错误')
    }
    if (number % 10 == 0 && number != 0 || number < 0) {
        console.log('当前数不是回文数')
    } else if (number >= 0 && number < 10) {
        console.log('当前数是回文数')
    } else {
        var x = number
        var y = 0
        //反转操作
        while (x > y) {
            y = y * 10 + x % 10
            x = parseInt(x / 10)
        }
        if (x == y) {
            console.log('当前数为回文数')
        } else if (y > x) {
            //判断当前的y/10是否等于x
            if (parseInt(y / 10) == x) {
                console.log('当前数为回文数')
            } else {
                console.log('当前数不是回文数')
            }
        }
    }
}

封装一个函数判断当前传入的数值是否为水仙花数

function isPPDI(n) {
    if (typeof n != 'number') {
        throw new Error('参数类型错误')
    }
    if(!(n>=100 && n<1000)){
        throw new Error('参数范围错误')
    }
    //水仙花的特点 个位的三次方+十位的三次方+百位的三次方为本身
    if (Math.pow(n % 10, 3) + Math.pow(parseInt(n / 10) % 10, 3) + Math.pow(parseInt(n / 100),3) == n) {
        console.log('当前是水仙花数')
    } else {
        console.log('当前不是水仙花数')
    }
}

在定义函数的时候,需要考虑特殊情况

函数传入的实参可变
// 函数的实参个数可变 (多传 少传)
function fn(a, b, c) {
console.log(a, b, c)
}
//多传实参 (避免的)
fn(1,2,3,4)
//少传实参 默认没传的参数的值为undefined
fn(1)

return 关键词

return关键词是用于返回值的,默认没有return的情况下返回的值为undefined

function fn() {
    console.log(1)
}
//调用返回的值为undefined
console.log(fn()) //undefined
//返回对应的内容 使用return关键词
function fn1(){
    return 10
}
console.log(fn1()) //10
//return关键词 它会直接退出当前的function
function fn2(){
    return 20 //一般放在函数的结束位置
    console.log('hello') //不会打印
}
console.log(fn2()) //20
注意事项
  • return关键词用于返回对应的function的值,默认没有return返回undefined

  • return会退出当前的function执行,function内的后续代码不再执行

  • return 结束当前function ,throw new error是结束当前的执行程序

    //return 和 throw new Error的区别
    function fn3(){
        return 'world'
        console.log('你好 我是function后面的代码')//不执行
    }
    fn3()
    console.log('我是整体后面的代码') //会执行
    function fn4(){
        //抛出错误
        throw new Error()
        console.log('你好 我是function后面的代码')//不执行
    }
    fn4()
    console.log('我是整体后面的代码') //不会执行
    
  • break (用于跳出循环代码块或switch代码块) 和 continue (跳过本次循环)

练习

封装一个俩个数求和的函数

function sum(first,last){
	if(typeof first !='number' || typeof last !='number'){
		throw new Error('当前传入的参数错误')
	}
	return first + last
}
//调用
console.log(sum(2,3)) //5

arguments

arguments是一个伪数组(存储多个值的一个列表),主要是接收对应的传入的实参。它是一个内置对象。它存在于function中。

示例
function fn() {
    console.log(arguments) //接收的a b c的值
    //通过下标来访问arguments里面的值 具备下标 (下标从0开始 到arguments.length-1结束)
    console.log(arguments[0]) //获取arguments的第一个值 a
    console.log(arguments.length) //获取arguments里面的参数的个数 3
    //可以使用循环来进行遍历
    for(var i=0;i<arguments.length;i++){
        console.log(arguments[i]) //通过下标来访问值
    }
}
fn('a', 'b', 'c')
arguments的特点
  • arguments存在于function中 (只能在function里面使用)
  • arguments的长度通过length属性来获取 (arguments.length 获取长度)
  • arguments具备下标,通过下标可以访问对应的arguments里面的元素(下标从0开始 到arguments.length-1结束)
  • 如果使用arguments来获取实参,那么对应的形参就不需要定义
练习

传入不定的值来计算他们的和

function sum(){
	//通过arguments接收传入的实参 进行遍历计算
	var sum = 0
	//for循环遍历arguments
	for(var i=0;i<arguments.length;i++){
		sum += arguments[i]
	}
	return sum
}
//调用
console.log(sum(1,2,3,4))
console.log(sum(7,8,9,10,11))
console.log(sum(45,67))

传入不定个数的值 得出他们的最大值

//获取最大值
function getMax() {
    var max = arguments[0]
    //遍历arguments数组
    for (var i = 1; i < arguments.length; i++) {
        //如果比最大值还大那么重新赋值
        if (max < arguments[i]) {
            max = arguments[i]
        }
    }
    return max
}
//调用
console.log(getMax(1, 3, 4, 8, 6, 9))
console.log(getMax(37, 1, 2))

作用域及作用域链

作用域

一个变量的作用范围称为作用域

作用域的划分
  • 全局作用域 (全局都可以访问 全局声明)
  • 局部作用域 (在局部才可以访问 函数内声明的 (函数作用域))
示例
console.log(a) //undefined
var a = 10 //全局作用域
function fn() {
    console.log(a) //访问的局部作用域 undefined
    var a = 11 //局部作用域
    var b = 20
    console.log(a) //访问的局部作用域 11
}
fn()
console.log(a) //访问的全局作用域 10
console.log(b) //b is not define 

全局作用域可以在全局访问 局部作用域只能在局部访问 外部不能访问

作用域链

根据作用域查找对应的变量的过程称为作用域链

function允许嵌套
console.log(a) //undefined
var a = 10
function fn(){
	fn1()
	console.log(a) //全局作用域 10
	function fn1(){
		fn2()
		console.log(a) //局部变量 30
		var a = 20 //局部作用域
		function fn2(){
			console.log(a) //局部变量 fn1里面的a undefined
			a = 30 //局部变量 fn1里面的a赋值
			console.log(a) // 30
		}
	}
}
fn()
console.log(a) //全局变量 10

作用域链一层一层的向外找(没有var关键词声明)找最近的var关键词声明的变量。

事件驱动

利用dom操作中的事件来执行对应的方法

获取dom元素
document.getElementById(id选择器名字) //根据id获取元素
获取input框的值 value属性
<!-- 使用事件驱动  onclick 点击事件
当你点击按钮的时候 自动执行handler函数 事件驱动
-->
<button onclick="handler()">获取input框的值</button>
<input type="text" id="input">
<script>
    function handler(){
        //获取input框
        var input = document.getElementById('input')
        //打印input框的值
        console.log(input.value)
    }
</script>
显示内容到标签中 使用innerHTML属性
<!-- 计算俩个数的和 -->
<input type="text" id="number1"> +
<input type="text" id="number2"> =
<span id="result"></span>
<input type="text" id="sum">
<button onclick="sum()">计算</button>
<script>
    function sum(){
        //获取俩个input框的值 
        var number1 = document.getElementById('number1').value
        var number2 = document.getElementById('number2').value
        //显示到span中
        document.getElementById('result').innerHTML = Number(number1) + Number(number2)
        //显示在input中
        document.getElementById('sum').value = Number(number1) + Number(number2)
    }
</script>

递归 (Ologn)

递归是一个基础算法,它可以完成任何循环可以完成的操作。

递归三要素

  • 找初始值(没有规律的值)
  • 找规律
  • 自己调自己 (在函数内部调用自己这个函数)

简单递归

function fn(参数){
	if(没有规律的条件){
		//返回没有规律的值
	}else{
		//返回有规律的值 自己调用自己
	}
}
示例

打印1-100的值

function fn(n){
    console.log(n)
	if(n==1){
		return 1
	}else{
		return fn(n-1) + 1
	}
}
fn(100)

1 3 5 7 9 打印第一百位的值

//1 3 5 7 9打印100位的值 
function fn1(n) {
    if (n == 1) {
        return 1
    } else {
        //上一位的值 + 2
        return fn1(n - 1) + 2
    }
}
console.log(fn1(100))

1 1 2 3 5 取第十位的值

//1 1 2 3 5 取第十位的值
function fn2(n) {
    if (n == 1 || n == 2) {
        return 1
    } else {
        //当前的值 = 上一位的值 + 上上的位的值
        return fn2(n - 1) + fn2(n - 2)
    }
}
console.log(fn2(10))

2 5 9 14 20求第十位的值

//2 5 9 14 20求第十位的值
function fn3(n) {
    if (n == 1) {
        return 2
    } else {
        //上一个值 +  n + 1
        return fn3(n - 1) + n + 1
    }
}
console.log(fn3(10))

10的阶乘

//1*2*3*4*5...
function fn4(n){
	if(n==1){
		return 1
	}else{
		return fn4(n-1) * n
	}
}
console.log(fn4(10))