JavaScript-函数

一、函数
1.函数的声明
  1. 函数的声明语句

     function fn(a,b,c){
    				console.log(a);
    				console.log(b);
    				console.log(c);
    			}
    			fn(2,3); 
    
  2. 函数的表达式

    var hello = function(x,y){
    				return x+y;
    			}
    			console.log(hello(3,5));
    // 个人理解: hello是变量名称,相当于函数的实参,既可以在函数内部也可以在函数外部使用
    // hel 是函数名称,相当于函数的形参,只能在函数的内部使用
               var hello = function hel(x,y){
    				console.log(hel===hello);
    				return x+y;
    			}
    			// console.log(x);
    			hello(3,4); 
    			// console.log(hello(3,5));
    			// console.log(hel(3,5));
    
  3. Function 构造函数

    var fn = new Function('x', 'y', 'return x + y;');
    			console.log(fn(3, 7));
    			// function fn(x,y){
    			// 	return x+y;
    			// }
    
2.函数返回值
  1. return 如果没有返回值,调用表达式结果是 undefined其后面的函数并不执行

    function fn() {
        return {
          name: "MJJ",
          age: 18
        };
        alert(1);
      }
      // console.log(fn());//如果没有返回值,调用表达式的结果是 undefined
      console.log(fn());
    
  2. try{} catch(e){} finally{}情况

    并不是所有的函数中的return之后的代码都不执行

    function testFinally(){
        try{
          // var a = 2;
          // var b = 3;
          // console.log(a+b);
          console.log(x);
          return 2;
        }catch(e){
          alert(e);
          //TODO handle the exception
          return 1;
        }finally{
          return 0;
        }
      }
      console.log(testFinally());
    
  3. 一个函数多个return

    function compare(x,y){
        if(x > y){
          return x - y;
        }else{
          return y - x;
        }
      } 
    
  4. 在调用函数时,使用 new 前缀时,

    • 返回值不是一个对象或者没有返回值时,则返回该对象(this)
    • 返回对象情况,则就是对象
      // 如果函数调用时在前面加上new前缀,且返回值不是一个对象或者没有返回值,则返回该对象 (this)
      function fn(){
      	console.log(this);
      	this.a = 2;
      	//return {b:23}; 返回对象情况,则就是对象
        return 0;
      }
      var test = new fn();
      //console.log(test);
      // constructor 构造函数,每个对象都有这个属性
      console.log(test.constructor)
    
3.函数调用

相同的函数,不同的调用方式,会出现不同的结果,特别是 this 指向问题

  1. 普通函数调用模式

    严格模式,在代码中 + ‘use strict’

    function add(x,y) {
        'use strict';     // 在严格模式,this 指向 underfined
        console.log(this);// 在非严格模式,this指向 window 对象
        return x + y;
    }
    var sun = add(3,4);
    console.log(sum);
    
    // 在非严格模式下,可能会出现重写情况!
    // 重写
     function fn(){
        this.a = 1;
        console.log(this);
      }
      fn();
      console.log(this);
      this.a = 5;
      console.log(this); 
    // 以上就是非严格下,在函数中,更改到了window 的属性 
    // 注意:小心避免全局的属性重写带来的问题
    
  2. 方法调用模式

      // 方法调用模式
       var obj = {
        a:1,
        // 这个fn称为obj对象的方法,this指向的是:obj
        fn:function(){
          console.log(this);
          // console.log('1');
          this.fn2();
        },
        fn2:function(){
          this.a = 2;
        }
      }
      obj.fn();
      // obj.fn2();
      console.log(obj.a);
    
  3. 构造调用模式

    构造调用:new 一个方法

    this指向问题: 当做普通函数调用,this指向了window,当做构造函数调用,this 指向当前的函数,当做对象的方法,这个 this 一般情况指向了当前的对象

      // 3.构造函数调用模式
       function fn(x,y){
        this.a = x + y;
      }
      // this指向问题: 当做普通函数调用,this指向了window,当做构造函数调用,this指向当前的函数,当做对象的方法,这个this一般情况指向了当前的对象
      var obj = new fn(2,3);
      console.log(obj);
       var obj = {a:5};
      function fn(){
        console.log(this);
        this.a = 10;
        return obj;
      }
      var a = new fn;//等价于var a = new fn();
      console.log(a);
    
  4. 间接调用模式

    改变this的指向方法: call({},参数1,参数2,…)、apply({},[参数1,参数2…])

    将调用的函数方法的 this 指向,指向为 call()、apply()的第一个对象

      // 间接调用模式call({},1,2,3)  apply({},[1,2,3])
      var obj = {
        a: 10
      };
    
      function sum(x, y) {
        console.log(this);
        return x + y + this.a;
      }
    
      // console.log(sum());
      console.log(sum.call(obj, 1, 2));
      console.log(sum.apply(obj, [1, 2]));
    
4.函数参数
  1. add 和 add() 是不一样的
    • add 表示的是函数 log返回的是代码,dir返回的是实际的函数对象属性和方法
    • add() 表示的是函数的结果内容 log返回的是结果,dir返回的直接是内容,但是结果的内容就是结果0
  2. log 和 dir 的区别?
    • log语句打印的是结果,直接显示信息;
    • dir语句打印的是内容,对显示对象的所有属性和方法。
参考本节的 参数个数

arguments : arguments它不是真正的数组,它是类数组,它能通过[]来访问它的每一个元素

console.log(arguments);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nFqmNkoY-1635122046289)(C:/Users/13059/AppData/Roaming/Typora/typora-user-images/image-20211007101752744.png)]

  1. 函数不在意有多少个参数、参数是什么数据类型,甚至可以不传参数

    // 函数不介意传递进来多少个参数,也不在乎传进来的参数是什么数据类型,甚至可以不传参数
    function add(x) {
        return x + 1;
      }
    
      console.log(add(1));
      console.log(add('1'));
      console.log(add());//NaN
      console.log(add(1, 2, 3));
    
  2. 同名的参数(形参)也是可以的,只有最后的参数有效。其余被覆盖

      function add(x,x,x){
      	'use strict';
      	return x;
      }
      console.log(add(1,2,3));
    
  3. 参数个数

    实参比形参个数少时,其余形参都将被设置为 undefined

       function add(x,y){
        console.log(x,y);
      }
      add(1,2,3,4); 
    

    实参比形参个数多时,其余实参无效

    解决办法:使用 arguments

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qaThfcdh-1635122046293)(C:/Users/13059/AppData/Roaming/Typora/typora-user-images/image-20211007101742754.png)]

      // 实参比形参个数多,考虑arguments
      function add(x,y){
      	console.log(arguments);
      	// arguments它不是真正的数组,它是类数组,它能通过[]来访问它的每一个元素
      	console.log(arguments[0],arguments[1],arguments[2]);
      	console.log('实参的个数:'+ arguments.length);
      	return 0;
      }
      add(1,2,3);
      // add 和 add() 是不一样的,
    	           // add   表示的是函数  log返回的是代码,dir返回的是实际的函数对象属性和方法,
    	           // add() 表示的是函数的结果内容 log返回的是结果,dir返回的直接是内容,但是结果的内容就是结果0
    	// log 和 dir 的区别?
    	// log语句打印的是结果,直接显示信息;
    	// dir语句打印的是内容,对显示对象的所有属性和方法。
    	console.dir(add());
      // 形参的个数
    	console.dir(add.length);
    
  4. JS中函数不存在 重载,会被覆盖

    // 重载 :定义相同的函数名,传入的不同参数,实现不同的功能
    

    为解决 : JS 函数不存在重载,会被后续同函数名方法给覆盖

    function add(a) {
     return a + 100;
    }
    function add(a, b) {
     return a + b + 100;
    }
    alert(add(10));
    

    可行方式:利用 arguments 类数组特性,实现相同效果,迂回实现

    function doAdd() {
     /* if(arguments.length == 0){
       return 100;
     }else if(arguments.length == 1){
       return arguments[0] + 100;
     }else if(arguments.length == 2){
       return arguments[0] + arguments[1] + 100;
     } */
     switch (arguments.length) {
       case 0:
         return 100;
         break;
       case 1:
         return arguments[0] + 100;
         break;
       case 2:
         return arguments[0] + arguments[1] + 100;
         break;
       default:
         break;
     }
    }
    alert(doAdd());
    alert(doAdd(10));
    alert(doAdd(10, 20));
    
5.函数参数传递
1.基本数据类型

在向参数传递基本数据类型的值时,被传递的值会被复制到一个局部变量–不改变原值

  • 如以下 Code,执行过程如图:
function add(num){
    num = num + 10;
    return num;
  }
  var count = 20;
  var result = add(count);
  console.log(result);
  console.log(count);
  • Javascript 执行过程

image-20211007105434776

2.引用数据类型

在向参数传递引用数据类型的值时,会把这个值在内存中的地址复制给局部变量–原值会发生变化

  1. 最基础版
  • Code
  // 2.引用数据类型
  // 在向参数传递引用数据类型的值时,会把这个值在内存中的地址复制给局部变量
 function setName(obj){
    obj.name = 'mjj';
  }
  var person = new Object();
  setName(person);
  console.log(person.name);
  • 执行图

image-20211007120802992

  1. 多个
  • Code
  function setName(obj) {
    obj.name = 'mjj';
    console.log(person.name);
    obj = new Object();
    obj.name = 'test';
    console.log(person.name);
  }

  var person = new Object();
  setName(person);
  • 执行图

image-20211007123017944

6.函数属性
1.length 属性
  • arguments对象中的length属性表示实参,而函数参数length属性表示的是形参的个数

    // length属性
      // arguments对象中的length属性表示实参,而函数参数length属性表示的是形参的个数
      function add(x, y) {
        console.log(arguments.length);
        console.log(add.length);
      }
    
      add(2, 3, 4, 5);
      console.dir(add)
    
2. name 属性
  • 表示当前函数的名字

      // name指的是当前函数的名字
       function fn(){};
      console.dir(fn.name);//fn
      var fn2 = function (){};
      console.log(fn2.name);//fn2
      var fn3 = function abc(){};
      console.log(fn3.name);//abc
    
3.prototype 属性 原型
  • 每一个函数都有一个prototype属性

    // 每一个函数都有一个prototype属性
      function fn(){};
      console.log(fn.prototype);
      fn.prototype.a = 1;
      console.log(fn.prototype);
    
7.函数方法:call、apply、bind

改变this的指向方法: call({},参数1,参数2,…)、apply({},[参数1,参数2…]) bind({})返回一个函数

将调用的函数方法的 this 指向,指向为 call()、apply()的第一个对象

1.call、apply()方法
  1. 基本概念

    call({},1,2,3)
    apply({},[])
    每个函数都包含两个非继承而来的方法

  2. 使用代码

      // apply() call()
      // call({},1,2,3)
      // apply({},[])
      // 每个函数都包含两个非继承而来的方法
    
      window.color = 'red';
      var obj = {color: 'blue'};
    
      function sayColor() {
        console.log(this.color);
      }
    
      sayColor();//red 因为当前的this指向了window
      sayColor.call(this);//red
      sayColor.call(window);//red
      sayColor.call(obj);//blue
    
  3. 严格模式和非严格模式下:call、apply 传null undefined

    • 在非严格模式下,如果我们使用call()或者是apply()方法,传入一个null或者undefined会被转换成一个全局window对象
    • 在严格模式下,函数的指向始终是指定的值
      // 在非严格模式下,如果我们使用call()或者是apply()方法,传入一个null或者undefined会被转换成一个全局window对象
      // 在严格模式下,函数的指向始终是指定的值
      var color = 'red';
    
      function displayColor() {
        'use strict';
        console.log(this);
        console.log(this.color);
      }
    
      displayColor.call(undefined);
    
  4. call、apply()方法的实际运用

    1. 找出数组的最大元素,Math.max()、apply(null,参数…)

       // 1.找出数组的最大元素 Math.max() apply(null,)
         var max = Math.max(2,3,4,5,10);
        var arr = [22222,1,10,30,88];
        var arrMax = Math.max.apply(null,arr);
        console.log(arrMax); 
      
    2. 将类数组转换成真正的数组 ?slice.apply ?

      slice(开始参数,结束参数) ,将数组从start,开始end结束的数组,并不影响原数组,从原数组复制到新数组,

        function add() {
          console.log(arguments);
          // arguments.push(5);
          // apply() slice()
          var arr = Array.prototype.slice.apply(arguments);
          console.log(arr);
        }
      
        add(1, 2, 3);
      
    3. 数组追加

      var arr = [];
        Array.prototype.push.apply(arr, [1, 2, 3, 4]);
        console.log(arr);
        Array.prototype.push.apply(arr, [8, 9, 0]);
        console.log(arr);
      
    4. 利用call和apply做继承 ?call apply?

      function Animal(name, age) {
          this.name = name;
          this.age = age;
          this.sayAge = function () {
            console.log(this.age);
          }
        }
      
        // Cat
        function Cat(name, age) {
          // 继承了Animal
          Animal.call(this, name, age);//把this指向了43行的c实例对象
        }
      
        var c = new Cat('小花', 20)
        c.sayAge();
        console.log(c.name);
      
        function Dog() {
          Animal.apply(this, arguments)
        }
      
        var d = new Dog('阿黄', 18);
        console.log(d);
      
      
    5. 使用log代理console.log()

      arguments 形参,类数组,存放传来的参数

      function log() {
          console.log.apply(console, arguments);
        }
      
2.bind() 方法 和call apply类似,bind有返回值(一个函数)
  1. bind es5新增的方法,主要作用:将函数绑定到某个对象中,并且有返回值(一个函数)

      // bind es5新增的方法,主要作用:将函数绑定到某个对象中,并且有返回值(一个函数)
      function fn(y) {
        return this.x + y;
      }
    
      var obj = {
        x: 1
      }
      var gn = fn.bind(obj);
      // console.log(gn);  // 返回 fn(y){...}
      console.log(gn(3));  // 4
    
  2. ???常见的函数式编程技术- 函数柯里化🔴

      // 常见的函数式编程技术- 函数柯里化
      function getConfig(colors, size, otherOptions) {
        console.log(colors, size, otherOptions);
      }
    
      var defaultConfig = getConfig.bind(null, '#ff6700', 1024 * 768);
      defaultConfig('123');
      defaultConfig('456');
      // 函数 作用域  闭包 this  面向对象编程(封装 继承 多态)
    
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值