一、初识函数
可以封装一段特定功能的代码,然后通过函数名可以重复调用此段代码
语法: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 想指向的对象