JavaScript中的方法是什么

开发 前端
如果who是一个对象的属性呢?要方便访问对象的属性,我们可以将函数附加到该对象,换句话说,就是创建一个方法。

[[395756]]

1.什么是方法

定义并调用一个常规函数:

  1. function greet(who) { 
  2.   return `Hello, ${who}!`; 
  3.  
  4. greet('World'); // => 'Hello, World!' 

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

greet('World')是常规的函数调用。函数greet('World')接受参数中的数据。

如果who是一个对象的属性呢?要方便访问对象的属性,我们可以将函数附加到该对象,换句话说,就是创建一个方法。

我们将greet()作为对象world的一种方法:

  1. const world = { 
  2.   who: 'World'
  3.  
  4.  greet() { return `Hello, ${this.who}!`; }} 
  5.  
  6. world.greet(); // => 'Hello, World!' 

greet() { ... }现在是属于world对象的方法, world.greet()是方法调用。

在greet()方法内部,this指向该方法所属的对象—world,这就是为啥可以this.who访问 word属性的原因。

注意,this也称为上下文。

上下文是可选的

在上一个示例中,我们使用this来访问该方法所属的对象,但是 JS 没有强制让方法使用 this。

因此,可以将对象用作方法的命名空间:

  1. const namespace = { 
  2.   greet(who) { 
  3.     return `Hello, ${who}!`; 
  4.   }, 
  5.  
  6.   farewell(who) { 
  7.     return `Good bye, ${who}!`; 
  8.   } 
  9.  
  10. namespace.greet('World');    // => 'Hello, World!' 
  11. namespace.farewell('World'); // => 'Good bye, World!' 

namespace是一个包含2个方法的对象:namespace.greet()和namespace.farewell()。

2. 对象字面量方法

如前所述,我们可以直接在对象字面量中定义方法

  1. const world = { 
  2.   who: 'World'
  3.  
  4.  greet() { return `Hello, ${this.who}!`; }}; 
  5.  
  6. world.greet(); // => 'Hello, World!' 

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

  1. const world = { 
  2.   who: 'World'
  3.   greet: function() {  
  4.     return `Hello, ${this.who}!`;  
  5.   } 
  6.  
  7. world.greet(); // => 'Hello, World!' 

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

动态添加方法

方法只是一个函数,它作为属性存储在对象上。因此,我们可以向对象动态添加方法:

  1. const world = { 
  2.   who: 'World'
  3.  
  4.   greet() { 
  5.     return `Hello, ${this.who}!`; 
  6.   } 
  7. }; 
  8.  
  9. // A a new property holding a function 
  10. world.farewell = function () { 
  11.   return `Good bye, ${this.who}!`; 
  12.  
  13. world.farewell(); // => 'Good bye, World!' 

3.类方法

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

类也可以有方法:

  1. class Greeter { 
  2.   constructor(who) { 
  3.     this.who = who; 
  4.   } 
  5.  
  6.  greet() { console.log(this === myGreeter); // logs true return `Hello, ${this.who}!`; }} 
  7.  
  8. const myGreeter = new Greeter('World'); 
  9. 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值是什么:

  1. const world = { 
  2.   who: 'World'
  3.  
  4.   greet() { 
  5.  console.log(this === world);    return `Hello, ${this.who}!`; 
  6.   } 
  7. }; 
  8.  
  9. // 方法调用 
  10. world.greet(); // logs true 
  11. const greetFunc = world.greet; 
  12. // 常规函数调用 
  13. greetFunc(); // => logs false 

world.greet()是一个方法调用。对象world,后面是一个点.,最后是使方法调用的方法本身。

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

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

将方法与其对象分离可以采用不同的形式:

  1. // 方法分离, this 丢失了! 
  2. const myMethodFunc = myObject.myMethod; 
  3.  
  4. // 方法分离, this 丢失了! 
  5. setTimeout(myObject.myMethod, 1000); 
  6.  
  7. // 方法分离, this 丢失了! 
  8. myButton.addEventListener('click', myObject.myMethod) 
  9.  
  10. // 方法分离, this 丢失了! 
  11. <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:

  1. function greet() { 
  2.   return `Hello, ${this.who}!`; 
  3.  
  4. const aliens = { 
  5.   who: 'Aliens' 
  6. }; 
  7.  
  8. greet.call(aliens); // => 'Hello, Aliens!' 
  9. greet.apply(aliens); // => 'Hello, Aliens!' 

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

4.3 绑定函数调用

最后,还有一种在对象上使函数作为方法调用的第三种方法。我们可以将函数绑定为具有特定上下文。

可以使用特殊方法创建绑定函数

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

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

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

  1. function greet() { 
  2.   return `Hello, ${this.who}!`; 
  3.  
  4. const aliens = { 
  5.   who: 'Aliens' 
  6. }; 
  7.  
  8. const greetAliens = greet.bind(aliens); 
  9.  
  10. greetAliens(); // => 'Hello, Aliens!' 

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

同样,使用绑定函数可以模拟方法调用。当调用绑定函数greetAliens()时,this等于该函数中的 aliens。

5. 箭头函数作为方法

不推荐使用箭头函数作为方法,原因如下。

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

  1. const world = { 
  2.   who: 'World'
  3.  
  4.   greet: () => { 
  5.     return `Hello, ${this.who}!`; 
  6.   } 
  7. }; 
  8.  
  9. world.greet(); // => 'Hello, undefined!' 

不幸的是,world.greet()返回'Hello, undefined!而不是我们期待的'Hello, World!'。

问题是箭头函数内部的this等于外部作用域的this。但是,此时,我们想要的this是world对象。

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

我喜欢箭头功能, 但是它们不能用作方法。

6. 总结

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

还可以在类上定义方法。这个类的方法内部等于实例。JS 特有的一点是,仅仅定义一个方法是不够的。我们还需要确保使用方法调用。通常,方法调用具有以下语法

  1. // Method invocation 
  2. myObject.myMethod('Arg 1''Arg 2'); 

有趣的是,在 JS 中,我们可以定义一个常规函数,但不属于一个对象,然后作为一个任意对象的方法调用该函数。可以使用间接函数调用或将函数绑定到特定上下文来实现这一点

  1. // Indirect function invocation 
  2. myRegularFunc.call(myObject, 'Arg 1''Arg 2'); 
  3. myRegularFunc.apply(myObject, 'Arg 1''Arg 2'); 
  4.  
  5. // Bound function 
  6. const myBoundFunc = myRegularFunc.bind(myObject); 
  7. myBoundFunc('Arg 1''Arg 2'); 

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

作者:Shadeed 译者:前端小智 来源:dmitripavlutin 原文:https://dmitripavlutin.com/javascript-method/

本文转载自微信公众号「大迁世界」,可以通过以下二维码关注。转载本文请联系大迁世界公众号。

 

责任编辑:武晓燕 来源: 大迁世界
相关推荐

2009-06-09 22:11:44

JavaScriptObject

2022-11-09 08:05:15

JavaScriptsuper()

2021-08-16 08:45:38

JavaScript开发代码

2019-11-27 09:03:49

JavaScriptJavaCSS

2021-02-07 22:59:55

JavaScript编程方法链

2016-10-13 19:33:10

javascript数组indexOf

2021-09-10 06:50:03

HashMapHash方法

2023-03-02 08:48:43

Linuxsubshell

2010-06-29 13:58:17

SNMPMIB

2022-09-15 09:54:34

nullPython字符

2009-07-10 17:15:13

Javascript

2021-09-22 23:17:09

Java开发数组

2016-12-27 10:19:42

JavaScriptindexOf

2020-03-23 10:09:27

云安全云计算

2023-03-28 07:03:15

gRPCMetadata

2022-06-29 08:37:03

事件循环JS 语言

2019-05-20 10:58:40

物联网IOT技术

2021-12-03 18:29:31

GoAny 泛型

2009-09-07 19:02:07

JSON是什么

2022-07-28 08:34:59

事件委托JS
点赞
收藏

51CTO技术栈公众号