js中的函数(三)

方法

  什么是js的方法?简单讲,绑定到对象的函数就是方法。

this

  在对象的方法中,我们常常使用this关键字。this关键字代表方法所绑定的对象。

 var wangqiang = {
      name : "wangqiang",
      age : 18,
      city : "guangzhou",
      address : "tianhe",
      //绑定到对象的函数叫方法
      getBirth:function(){
          let now = new Date();
          return now.getFullYear() - this.age;
      }
  }
  wangqiang.getBirth(); //2005
  var birth = wangqiang.getBirth;
  birth();  //NaN,脱离了绑定的对象。

  上述代码所示,在方法getBirth()内部,我们用到了一个this关键字。这个关键字指向了绑定的对象,要正确执行方法,需要按照 obj.xxx()的方式才能正确地调用方法,保证方法绑定的对象,this的指向才能正确。

再看如下代码:

  var lili = {
      name : "lili",
      age : 12,
      city : "beijing",
      address : "chaoyang",
      getBirth : function(){
          let diff = function(year){
              //超出了this的作用范围,this为undefined
              return year-this.age;
          }
          let now = new Date();
          console.log(diff(2022));
          return now.getFullYear() - this.age;
      }
  }

  在getBirth方法中,我们有定义了一个匿名函数。在匿名函数不能再使用this,因为这时的this是undefined。我们可以在匿名函数外部用一个 变量接收this,在匿名函数内部再使用这个变量。也就是this对象不能跨越两层函数进行使用。

  var lili = {
      name : "lili",
      age : 12,
      city : "beijing",
      address : "chaoyang",
      //方法的简写
      getBirth(){
          let that = this;
          let diff = function(year){
              return year-that.age;
          }
          let now = new Date();
          console.log(diff(2022));
          return now.getFullYear() - this.age;
      }
  }

  为此,可以在第一次函数里用一个变量that接收this,在第二层函数里再使用that,从而避免this变量不能跨越两层的障碍。

apply

函数通过apply方法,应用到对象上。

  var xiaoli = {
      name : "xiaoli",
      age : 12,
      city : "beijing",
      address : "chaoyang",
      birth : getBirth
  }
  
  function getBirth(){
      let now = new Date();
      return now.getFullYear() - this.age;
  }
  xiaoli.birth();
  getBirth.apply(xiaoli,[]);//应用到xiaoli对象上,参数数组为[]
  getBirth();  // Uncaught TypeError

  另一个与apply()类似的方法是call(),唯一区别是:

  • apply()把参数打包成Array再传入;
  • call()把参数按顺序传入。

  比如调用Math.max(3, 5, 4),分别用apply()和call()实现如下:

  Math.max.apply(null, [3, 5, 4]); // 5
  Math.max.call(null, 3, 5, 4); // 5

闭包

  在JavaScript中,一个函数可以作为另外一个函数的参数进行传递。同样地,一个函数也可以作为另外一个函数的返回值。例如:

  function lazy_sum(...rest){
      return function sum(){
          let reduce = rest.reduce(function(s,x){
              return  s += x;
          },6);
          return reduce;
      }
  }
  var lazy_sum1 = lazy_sum(1,2,4,6);
  var lazy_sum2 = lazy_sum(1,2,4,6);
  lazy_sum1();  //调用sum()函数,返回13
  lazy_sum2();  //调用sum()函数,返回13
  typeof lazy_sum1(); // 返回function
  typeof lazy_sum2(); // 返回function
  lazy_sum1 == lazy_sum2 // false

  上述代码所示,调用lazy_sum1和lazy_sum2函数,它们都返回一个sum()函数。虽然返回的名称相同,但不同于数值的相等比较,它们并不相等。

看起来作用不大,只是可以延迟调用而已。再看下边的例子:

  //闭包可以在函数内部封装一个变量
  function wrap(initial){
      initial = initial || 0;
      return function inc(){
          initial += 1;
          return initial;
      }
  }
  var w  = wrap(2); 
  w();  //返回3
  w();  //返回4
  w();  //返回5

  上述代码所示,wrap()是一个函数,它接收一个initial作为参数,这个函数的返回值也是一个函数,它是inc()。我们将inc()函数赋值给变量w, w函数调用一次返回3。接下来再调用一次,其内部的变量initial已经保留了3这个值,所以这时的返回值就是4。接下来的每次调用逻辑都是一致的。 这种在函数中封装了一个变量的函数形成了闭包。这种在函数中封装既封装了变量,又封装了方法的闭包,是不是有点像Java中的类呢?

闭包

  ES6标准新增了一种新的函数:Arrow Function(箭头函数)。为什么叫Arrow Function?因为它的定义用的就是一个箭头:

  x => x * x

使用规则

  上面的箭头函数相相当于一个匿名函数:

  function (x) {
      return x * x;
  }

  箭头函数简化了函数定义。箭头函数有两种格式,一种像上面的,只包含一个表达式,连{ ... }和return都省略掉了。 还有一种可以包含多条语句,这时候就不能省略{ ... }和return:

  x => {
      if (x>0){
          return x;
      }else{
          return -x;
      }
  }

  如果函数有多个参数,需使用括号,参数之间以逗号隔开

  // 两个参数:
  (x, y) => x * x + y * y
        
  // 无参数:
  () => 3.14
        
  // 可变参数:
  (x, y, ...rest) => {
      var i, sum = x + y;
      for (i=0; i < rest.length; i++) {
          sum += rest[i];
      }
      return sum;
  }

  如果要返回一个对象,就要注意,如果是单表达式,这么写的话会报错:

  // SyntaxError:
  x => { foo: x }

  表达式的对象和函数体的{...}相冲突,需在对象外加上括号:

  x => ({foo:x});

  前面章节指出了对象方法上,this使用的注意事项:

  var lili = {
      name : "lili",
      age : 12,
      city : "beijing",
      address : "chaoyang",
      getBirth(){
          let diff = function(year){
              return year-this.age;  // this指向window或undefined
          };
          let now = new Date();
          return now.getFullYear() - this.age;
      }
  }

  现在,箭头函数完全修复了this的指向,this总是指向词法作用域,也就是外层调用者obj:

  var lili = {
      name : "lili",
      age : 12,
      city : "beijing",
      address : "chaoyang",
      getBirth(){
          let diff = (year)=>year-this.age;  // this指向lili
          let now = new Date();
          return now.getFullYear() - this.age;
      }
  }

文章同时发表在:码农编程网 欢迎访问

本节重点:

  • 什么是方法,方法的调用;
  • 注意对象方法内部的this指向,避免指向错误;
  • apply,call的使用和区别;
  • 定义一个返回类型为函数的函数;
  • 如何形成闭包,闭包的使用;
  • 什么是箭头函数,箭头函数的使用;
  • 箭头函数修复了对象方法中的this指向。

posted on 2023-07-07 14:28  崎岖行者  阅读(14)  评论(0编辑  收藏  举报

导航