Javascript的核心知识点-函数

一、初识函数

可以封装一段特定功能的代码,然后通过函数名可以重复调用此段代码

语法:function fn(){ //函数体 }

js 复制代码
函数是不会自己运行,需要调用时才有效(函数不调用,自己不执行)
想获取变量值时,用变量名获取,想调用函数时,同样通过函数名来调用

// 定义一个函数:
function getSum(){
  var sum = 0;
  for(var i=0; i<=100; i++){
    sum += i; 
 }
  console.log(sum);
}
getSum();  // 调用函数

1.求三个数的最大值

js 复制代码
function getMax(a, b, c) {
  if(a > b && a > c) {
    console.log(a);
  }else if(b > a && b > c) {
    console.log(b);
  }else{
    console.log(c);
  }
}
getMax(11, 33, 88); // 88

2.定义一个函数,求一组数的最大值

js 复制代码
function getMax(arr){
  var max = arr[0];
  for(var i=0; i< arr.length; i++) {
    if (max < arr[i]) {
      max = arr[i];
    }
  }
  console.log(max);
}
var array = [12, 8, 40, 4, 18];
getMax(array);  // 40

二、函数的定义方式

1.函数声明

js 复制代码
function f(a,b) { return a + b; }
console.log(f(5,6));   // 预解析 会提升

2.函数表达式

js 复制代码
var fn = function (a,b){ return a + b; }  //fn和f等价    // 右侧是匿名函数
console.log(fn(6,7));     // 预解析 不会提升

函数声明和函数表达式的区别:

js 复制代码
// 1、预解析(变量、函数提升)的区别
console.log(f(5,6)); // 11 正常打印,不会报错
function f(a,b) {return a + b;} 
//上面代码执行没有问题,JavaScript解析器首先会把当前作用域的函数声明提前到整个作用域的最前面

myFun(6,7); //报错:myFun is not a function  
var myFun = function (a,b){return a + b;} // 这个指挥提升变量myFun--> undefined 在解析代码前,会进行函数和变量的提升

// 2、现代浏览器不会 提升if语句中的函数声明
if (true) {
    function fn(){
        console.log(fn + 'ture');
    }
} else{
    function fn(){
        console.log(fn + 'false');
    }
}
fn();  // true   ie8 以前的浏览器 会提升if语句中的函数声明

3.构造函数

js 复制代码
function Fun() {}  //首字母要大写
var fun = new Fun(); // 调用:   通过构造函数创建的是对象 不推荐使用

构造函数的流程:
    1、调用时,用 new 会创建一个新的对象
    2、将新建的对象设置为this,在构造函数中可以使用this来引用新建的对象
    3、执行函数中的代码
    4、将新建的对象作为返回值返回
    利用构造函数创建多个对象 比工厂方法要 更好用

使用同一个构造函数创建的对象,我们称为一类对象,也将一个构造函数称为一个类 
将通过一个构造函数创建的对象,称为该类的实例
function Person(name, age, gender, sayName) {
  this.name = name;
  this.age = age;
  this.gender = gender;
  this.sayName = function(){
    console.log(this.name);
  }
}
var per01 = new Person('孙悟空', '30', '男');
var per02 = new Person('唐僧', '50', '男');
console.log(per01);
console.log(per02);

使用instanceof 可以检查一个对象是否是一个类的实例

js 复制代码
// 语法:对象 instanceof 构造函数
console.log(per01 instanceof Person);  // true
// 如果是返回true, 反之 false

构造函数 方法的性能优化/提升:

perl 复制代码
将方法在全局作用域中定义,但是:将函数定义在全局作用域,污染了全局作用域的命名空间,而且定义在全局作用域也很不安全 。   --- > 原型 prototype
我们所创建的每一个函数,解析器都会向函数中添加一个属性 prototype
如果函数租用普通函数调用prototype 没有任何作用
当函数以构造函数形式调用时, 它所创建的对象的对象中都会有一个隐含属性
指向该构造函数的原型对象,可以通过 _ _proto_ _ 来访问该属性


构造函数与普通函数的区别 就是调用方式的不同:
  普通函数直接调用,构造函数需要只用new关键字来调用

4.匿名函数

匿名函数:没有命名的函数,也叫自调用函数

js 复制代码
匿名函数如何使用:
1、将匿名函数赋值给一个变量这样就可以通过变量进行调用,就是函数表达式 getMax()
2、匿名函数自调用: (function(){})();
    
// 定时器里的自调用函数
setTimeout(function(){}, 1000)

三、函数中的参数

什么叫参数? 参与运算的变量。定义形参就相当于在函数作用域中声明了变量

1.形参:给实参占位

js 复制代码
实现修改值,不修改规则的作用
占位,没有实际的值,特殊在没有声明,就可以直接拿来用

function fn(a) {
  alert(a);
}
fn();  //undefined

2.实参:实际参与运算的

js 复制代码
// 函数的参数
function getSum(a, b) {
  console.log(a + b);
}
getSum(123, 456); //  实际参数,把123, 456 赋值给了a,  b  
		 // 传递不同参数,就有不同结果 

3.arguments的使用

适用于参数个数不固定的情况(形式参数)

js 复制代码
// 实例:求任意个数的最大值
function getMax() {
  var max = arguments[0];
  for(var i = 1; i < arguments.length; i++) {
    if(max < arguments[i]) {
      max = arguments[i];
    }
  }
  return max;
}
console.log(getMax(12, 6, 88, 0, 9)); // 88

// 实例:求任意个数的和
function getSum() {
  var sum = 0;
  for(var i = 0; i < arguments.length; i++) {
    sum += arguments[i];
 }
  return sum;
}
console.log(getSum(2, 6, 3, 0, 9));  // 20

四、函数的返回值

kotlin 复制代码
函数的返回值只能有一个,适用于固定数组值, 可以通过变量来接收这个返回值
如果函数没有显示使用return 语句,那么函数有默认的返回值: undefined 
如果函数使用return 语句,那么跟在return 后面的值,即函数的返回值 
return 之后的所有代码都不会执行!!!

1.语法

js 复制代码
语法:
function 函数名(形参1, 形参2,....){
  // 函数体	
  return 返回值;
}

function getMax(arr){
  var max = arr[0]; // 初始化最大值,就是数组中的第一个
  for(var i=0; i< arr.length; i++) {
    if (max < arr[i]) { 		// 逐个比较 
       max = arr[i];	 		// 最大值 = 比较后的最大值 
    }
  }
  return max;		// 返回最大值
}
var array = [12, 8, 4, 18];
var result = getMax(array); // 通过变量接收函数的返回值
console.log(result);

2.返回值 的类型

js 复制代码
// 3个方法有3个不一样的值:说明 返回值 的类型是不同的
var bool1 = confirm('我们结婚吧!');
console.log(bool1);   // true or false

var str1 = alert('你好吗?');
console.log(str1);  // undefined

var str2 = prompt('请输入你的姓名:');
console.log(str2);  // zs

五、函数内部的关键词

kotlin 复制代码
return 可以切断函数
break 跳出整个循环
continue 跳出本次循环,进入下一循环

六、实例

1. 求阶乘

js 复制代码
// 实例: 求阶乘,累乘 例:5的阶乘 即 5*4*3*2*1
function getMult(n) {
  var result = 1;
  for (var i = 1; i <= n; i++) {
    result *= i;
  }
  return result;
}
console.log(getMult(5)); //120

实例: 求阶乘的累加 求 1-n之间每个数的阶乘的累加

思路:先求阶乘结果,再累加每个数的阶乘

js 复制代码
function getMult(n) {
  var result = 1;
  for (var i = 1; i <= n; i++) {
    result *= i;
  }
  return result;   // 阶乘结果
}
function getSum(n) {
  var sum = 0;
  for(var i =1; i <= n; i++) {
    sum += getMult(i);   // 每个阶乘结果的累加
  }
  return sum;
}
console.log(getSum(5));  // 153

2.实例:斐波那契数列

Fibonacci (前两个数相加=后一个数)的第n 个数是多少?

js 复制代码
function getFib(n) {
  var n1 = 1;
  var n2 = 1;
  var n3;
  for (var i = 3; i <= n; i++) {
    n3 = n1 + n2;
    n1 = n2;
    n2 = n3; 
  }
  return n3;
}
console.log(getFib(6));  // 8

3.实例:翻转数组

ini 复制代码
function reverse(arr) {
  var newArr = [];
  for (var i = arr.length -1; i >= 0; i--) {
    newArr[newArr.length] = arr[i];
  }
  return newArr;
}
var array = [5, 4, 3, 2, 1];
console.log(reverse(array)); // [1, 2, 3, 4, 5]

4.实例:封装冒泡排序函数

优点:想对谁排序,传值就行(之前是给定一个数组)

js 复制代码
function sort(arr){
  for(var i = 0; i < arr.length-1; i++) {	
    // 假设已经排好顺序了
    var isSort = true;
    for( var j = 0; j < arr.length-1-i; j++) {  
      if(arr[j] > arr[j+1]) {
        var isSort = false; 	// 没有排好
        var tem = arr[j];
        arr[j] = arr[j+1];
        arr[j+1] = tem;
      }
    }
    if(isSort){
      break;	//排好序后,跳出循环
    }
  }
  return arr;
}
console.log(sort([2, 5, 8, 3, 4])); //  [2, 3, 4, 5, 8]

5.实例:判断是否是闰年

能被4整除且不能被100整除,或者能被400整除

js 复制代码
function isRun(year) {
  var result = false; // 假设不是闰年
  if ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0) ){
    result = true;
  }
  return result;
}
console.log(isRun(2000)); // true

6.判断某天是这一年的第几天

实例:输入某年某月某日,判断这一天是这一年的第几天

js 复制代码
function isRun(year) {
	var result = false; // 假设不是闰年
	if ((year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0) ){
		result = true;
	}
	return result;
}
function getDays(year, month, day) {
  // 计算总共有多少天 定义一个变量,接收累加的天数 
  var days = day; //  当前月份的天数
  for(var i = 1; i < month; i++) {
    switch (i) {
      case 1:
      case 3:
      case 5:
      case 7:
      case 8:
      case 10:
      case 12:
        days += 31;
        break;
      case 4:
      case 6:
      case 9:
      case 11:
        days += 30;
        break;
      case 2:
        if(isRun(year)){
          days += 29;
        }else {
          days += 28;
        }
          break;
    }
  }
  return days;
}
console.log(getDays(1998, 3, 18)); // 77

7.求圆的周长和面积

js 复制代码
// 1.圆的周长: 2*pi*半径
function long(r) {
  var pi = 3.141592653; // or var pi = Math.PI;
  return 2 * pi * r;
}
console.log(long(4));

// 2. 圆的面积 :area = pi*r*r
function getArea(r){
  // // 通俗版
  // var pi = 3.14;
  // var a = pi * r * r;
  // return a;  //or return pi * Math.pow(r,2);
  // //精简版
  // var pi = Math.PI;
  // var a = pi * Math.pow(r,2);
  // return a;
  //最终版
  return Math.PI * Math.pow(r,2);
}
alert(getArea(5));

七、高阶函数

scss 复制代码
定义:函数作为参数/函数作为返回值的时候
(在js中,函数是一等公民,它特别特别重要,因为在js中,函数特别灵活:它既可以作为一个变量的值,又可以作为函数的参数,还可以作为函数的返回值)

1.为什么需要让函数作为参数?

js 复制代码
function eat(fn){
  setTimeout(function(){
    console.log('吃晚饭');
    fn(); // 晚饭过后要做的 不固定的事情
  },2000)
}
eat(function(){
  console.log('wander');
})

sort()模拟排序

js 复制代码
Array.prototype.mySort = function(fn){
  for(var i = 0; i < this.length-1; i++) {
    var isSort = true;
    for(var j = 0; j < this.length -i-1; j++){
      if(fn(this[j], this[j+1]) > 0) {
      isSort = false;
      var tmp = this[j];
      this[j] = this[j+1];
      this[j+1] = tmp;
      }
    }
    if(isSort) {
      break;
    }
  }
}
var arr = [10, 4, 6, 8];
arr.mySort(function(a, b){
  return a - b;
})
console.log(arr); // [4, 6, 8, 10]

2.函数作为返回值

js 复制代码
// 写一个函数,生成1-10之间的随机数
function getRandom(){
  return parseInt(Math.random()*10) + 1;
}
console.log(getRandom());

// 写一个函数,生成1-10之间的随机数
// 第一次调用生成随机数,以后每次调用都返回第一次的随机值
function getRandom(){   // getRandom 返回值 fn(){}
  var random = parseInt(Math.random()*10) + 1;
  return function(){
    return random;
  } 
}
var fn = getRandom();  // 通过一个变量 接收函数
console.log(fn()); // 多次调用返回的都是第一次产生的随机数
console.log(fn());
console.log(fn());

// 求两个数的和 : 第一个参数是固定值,另一个是变化的
// 100 +n 、 1000+n、 10000+n
function getSum(n){  // n 固定值
  return function(m){  // m 不固定值
    return n + m;
  }
}
// 求100 + m
var sum01 = getSum(100);
// 求1000 + m
var sum02 = getSum(1000);

console.log(sum01(1));   // 101
console.log(sum02(1));    // 1001

八、改变函数中的this

js 复制代码
// 1. call() 作用:调用函数,改变函数中的this
// 参数1:设置函数内部this的指向   参数2:其它参数:对应函数的参数
// 返回值:函数的返回值
function fn(x, y) {
  console.log(this);   // obj
  console.log(x + y); // 11
}
var  obj = {name:'zs'};
fn.call(obj, 5, 6);   


// 2.apply()   语法:fn.apply(对象, [])    apply的第二个参数(数组变量):可以把数组中的每一项展开
// Math.max();  求一组数的最大值,能不能求数组中的最大值?
var arr = [5, 10, 1, 3, 6];
console.log(Math.max(arr));   // NaN  -->不能求数组中的最大值

// 求最大值
var arr = [5, 10, 1, 3, 6];
var result = Math.max.apply(null, arr);  // apply 可以把数组中的每一项展开 
console.log(result);  // 10

// 在控制台的一行中打印 数组
var  arr = [1, 2, 3, 4, 5, 6];
console.log.apply(console, arr);     // 1 2 3 4 5 6


// 3.bind()  通过bind()改变 定时器中匿名函数的this
// 隔一秒中打印对象中的name
var obj = {
  name: 'zs',
  fun: function(){
    setInterval(function(){
      console.log(this.name);
    }.bind(this),1000)
  }
}
obj.fun();

// 通过bind 改变时间处理函数中的this指向
btn.onclick = function(){
	// 事件处理函数中的this 是触发该事件的对象
	// 通过bind 改变事件处理函数中this的指向
}.bind(obj);  // obj 想指向的对象
相关推荐
一个专注写代码的程序媛1 小时前
vue组件间通信
前端·javascript·vue.js
一笑code1 小时前
美团社招一面
前端·javascript·vue.js
懒懒是个程序员2 小时前
layui时间范围
前端·javascript·layui
NoneCoder2 小时前
HTML响应式网页设计与跨平台适配
前端·html
凯哥19702 小时前
在 Uni-app 做的后台中使用 Howler.js 实现强大的音频播放功能
前端
烛阴2 小时前
面试必考!一招教你区分JavaScript静态函数和普通函数,快收藏!
前端·javascript
GetcharZp2 小时前
xterm.js 终端神器到底有多强?用了才知道!
前端·后端·go
JiangJiang2 小时前
🚀 React 弹窗还能这样写?手撸一个高质量 Modal 玩起来!
前端·javascript·react.js
吃炸鸡的前端2 小时前
el-transfer穿梭框数据量过大的解决方案
前端·javascript
高德开放平台2 小时前
文末有奖|高德MCP 2.0 出行领域首发打通大模型与高德地图APP互联
前端