作者:Shadeed
译者:前端小智
起源:dmitripavlutin

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

1.什么是办法

定义并调用一个惯例函数:

function greet(who) {  return `Hello, ${who}!`;}greet('World'); // => 'Hello, World!'

function关键字后跟其名称,参数和主体:function greet(who){...}进行惯例的函数定义。

greet('World')是惯例的函数调用。函数greet('World')承受参数中的数据。

如果who是一个对象的属性呢?要不便拜访对象的属性,咱们能够将函数附加到该对象,换句话说,就是创立一个办法。

咱们将greet()作为对象world的一种办法:

const world = {  who: 'World', greet() { return `Hello, ${this.who}!`; }}world.greet(); // => 'Hello, World!'

greet() { ... }当初是属于world对象的办法, world.greet()是办法调用。

greet()办法外部,this指向该办法所属的对象—world,这就是为啥能够this.who拜访 word属性的起因。

留神,this也称为上下文。

上下文是可选的

在上一个示例中,咱们应用this来拜访该办法所属的对象,然而 JS 没有强制让办法应用 this

因而,能够将对象用作办法的命名空间:

const namespace = {  greet(who) {    return `Hello, ${who}!`;  },  farewell(who) {    return `Good bye, ${who}!`;  }}namespace.greet('World');    // => 'Hello, World!'namespace.farewell('World'); // => 'Good bye, World!'

namespace是一个蕴含2个办法的对象:namespace.greet()namespace.farewell()

2. 对象字面量办法

如前所述,咱们能够间接在对象字面量中定义方法

const world = {  who: 'World', greet() { return `Hello, ${this.who}!`; }};world.greet(); // => 'Hello, World!'

greet() { .... }是在对象定义的办法,这种定义类型称为速记办法定义(从ES2015开始可用)。办法定义的语法也更长:

const world = {  who: 'World',  greet: function() {     return `Hello, ${this.who}!`;   }}world.greet(); // => 'Hello, World!'

greet: function() { ... }是一个办法定义,留神附加的冒号和function关键字。

动静增加办法

办法只是一个函数,它作为属性存储在对象上。 因而,咱们能够向对象动静增加办法:

const world = {  who: 'World',  greet() {    return `Hello, ${this.who}!`;  }};// A a new property holding a functionworld.farewell = function () {  return `Good bye, ${this.who}!`;}world.farewell(); // => 'Good bye, World!'

3.类办法

在 JavaScript 中,类别语法定义了一个类别,该类别将用作其实例的模板。

类也能够有办法:

class Greeter {  constructor(who) {    this.who = who;  } greet() { console.log(this === myGreeter); // logs true return `Hello, ${this.who}!`; }}const myGreeter = new Greeter('World');myGreeter.greet(); // => 'Hello, World!' 

greet() { ... }是在类外部定义的办法。

每次咱们应用new操作符(例如myGreeter = new Greeter('World'))创立一个类的实例时,都能够在创立的实例上调用办法。

myGreeter.greet()是如何在实例上调用办法greet()的办法。 重要的是办法外部的this等于实例自身:this等于greet() { ... }办法外部的 myGreeter

4.如何调用办法

4.1办法调用

JavaScript 特地乏味的是,在对象或类上定义方法只能算实现工作的一半。为了保护办法的上下文,咱们必须确保将办法作为办法调用。

咱们来看看为什么它很重要。

回顾一下有greet()办法的world对象。咱们测试一下greet()作为一个办法和一个惯例函数调用时,this值是什么:

const world = {  who: 'World',  greet() { console.log(this === world);    return `Hello, ${this.who}!`;  }};// 办法调用world.greet(); // logs trueconst greetFunc = world.greet;// 惯例函数调用greetFunc(); // => logs false

world.greet()是一个办法调用。对象world,前面是一个点.,最初是使办法调用的办法自身。

greetFuncworld.greet是同一个函数。但当作为惯例函数greetFunc()调用时,这个在greet()中的并不等于world对象,而是全局对象(在浏览器中是window)

咱们将诸如greetFunc = world.greet之类的表达式命名为将办法与其对象拆散的办法。 调用拆散的办法greetFunc()时,this等于全局对象。

将办法与其对象拆散能够采纳不同的模式:

// 办法拆散, this 失落了!const myMethodFunc = myObject.myMethod;// 办法拆散, this 失落了!setTimeout(myObject.myMethod, 1000);// 办法拆散, this 失落了!myButton.addEventListener('click', myObject.myMethod)// 办法拆散, this 失落了!<button onClick={myObject.myMethod}>My React Button</button>

为了防止失落办法的上下文,请确保应用办法调用world.greet()或手动将办法绑定到对象greetFunc = world.greet.bind(this)

4.2间接函数调用

如上一节所述,惯例函数调用已将this解析为全局对象。 惯例函数是否能够通过办法自定义 this值?

欢送应用以下间接函数调用:

myFunc.call(thisArg, arg1, arg2, ..., argN);myFunc.apply(thisArg, [arg1, arg2, ..., argN]);

函数对象上可用的办法。

myFunc.call(thisArg)myFunc.apply(thisArg) 的第一个参数是间接调用的上下文(this值)。 换句话说,咱们能够手动指定函数外部 this 的值。

例如,让咱们将greet()定义为一个惯例函数,以及一个具有who属性的对象alien:

function greet() {  return `Hello, ${this.who}!`;}const aliens = {  who: 'Aliens'};greet.call(aliens); // => 'Hello, Aliens!'greet.apply(aliens); // => 'Hello, Aliens!'

greet.call(aliens)greet.apply(aliens)都是间接的办法调用。这个在greet()函数中的值等于aliens对象。

4.3 绑定函数调用

最初,还有一种在对象上使函数作为办法调用的第三种办法。 咱们能够将函数绑定为具备特定上下文。

能够应用非凡办法创立绑定函数

const myBoundFunc = myFunc.bind(thisArg, arg1, arg2, ..., argN);

myFunc.bind(thisArg)的第一个参数是函数要绑定到的上下文。

例如,让咱们重用greet()并将其绑定到aliens上下文

function greet() {  return `Hello, ${this.who}!`;}const aliens = {  who: 'Aliens'};const greetAliens = greet.bind(aliens);greetAliens(); // => 'Hello, Aliens!'

调用 greet.bind(aliens) 会创立一个新函数,该函数将 this 绑定到aliens对象。

同样,应用绑定函数能够模仿办法调用。当调用绑定函数greetAliens()时,this等于该函数中的 aliens

5. 箭头函数作为办法

不举荐应用箭头函数作为办法,起因如下。

咱们将greet()办法定义为一个箭头函数:

const world = {  who: 'World',  greet: () => {    return `Hello, ${this.who}!`;  }};world.greet(); // => 'Hello, undefined!'

可怜的是,world.greet()返回'Hello, undefined!而不是咱们期待的'Hello, World!'

问题是箭头函数外部的this等于内部作用域的this。 然而,此时,咱们想要的thisworld对象。

上述箭头性能外部 this 等于全局对象:window'Hello, ${this.who}!' 后果是 Hello, ${windows.who}!,最初是 'Hello, undefined!'

我喜爱箭头性能, 然而它们不能用作办法。

6. 总结

该办法是一个属于对象的函数。办法的上下文(this)等于该办法所属的对象。

还能够在类上定义方法。这个类的办法外部等于实例。 JS 特有的一点是,仅仅定义一个办法是不够的。咱们还须要确保应用办法调用。通常,办法调用具备以下语法

// Method invocationmyObject.myMethod('Arg 1', 'Arg 2');

乏味的是,在 JS 中,咱们能够定义一个惯例函数,但不属于一个对象,而后作为一个任意对象的办法调用该函数。能够应用间接函数调用或将函数绑定到特定上下文来实现这一点

// Indirect function invocationmyRegularFunc.call(myObject, 'Arg 1', 'Arg 2');myRegularFunc.apply(myObject, 'Arg 1', 'Arg 2');// Bound functionconst myBoundFunc = myRegularFunc.bind(myObject);myBoundFunc('Arg 1', 'Arg 2');

我是小智,我要去刷碗了,咱们下期见~


代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。

原文:https://dmitripavlutin.com/ja...

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq44924588... 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。