方法

什么是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(),唯一区别是:

比如调用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;      }  }

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

本节重点:

推荐内容