共计 4853 个字符,预计需要花费 13 分钟才能阅读完成。
作者: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 function
world.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 true
const greetFunc = world.greet;
// 惯例函数调用
greetFunc(); // => logs false
world.greet()
是一个办法调用。对象world
, 前面是一个点.
,最初是使办法调用的办法自身。
greetFunc
与 world.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
。然而,此时,咱们想要的this
是world
对象。
上述箭头性能外部 this
等于全局对象:window
。'Hello, ${this.who}!'
后果是 Hello, ${windows.who}!
,最初是 'Hello, undefined!'
。
我喜爱箭头性能,然而它们不能用作办法。
6. 总结
该办法是一个属于对象的函数。办法的上下文 (this
) 等于该办法所属的对象。
还能够在类上定义方法。这个类的办法外部等于实例。JS 特有的一点是,仅仅定义一个办法是不够的。咱们还须要确保应用办法调用。通常,办法调用具备以下语法
// Method invocation
myObject.myMethod('Arg 1', 'Arg 2');
乏味的是,在 JS 中,咱们能够定义一个惯例函数,但不属于一个对象,而后作为一个任意对象的办法调用该函数。能够应用间接函数调用或将函数绑定到特定上下文来实现这一点
// Indirect function invocation
myRegularFunc.call(myObject, 'Arg 1', 'Arg 2');
myRegularFunc.apply(myObject, 'Arg 1', 'Arg 2');
// Bound function
const myBoundFunc = myRegularFunc.bind(myObject);
myBoundFunc('Arg 1', 'Arg 2');
我是小智,我要去刷碗了,咱们下期见~
代码部署后可能存在的 BUG 没法实时晓得,预先为了解决这些 BUG,花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。
原文:https://dmitripavlutin.com/ja…
交换
有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。
本文 GitHub https://github.com/qq44924588… 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。