Wenn es darum geht, kommen viele abstrakte Konzepte zum Vorschein, die den Menschen schwindelig machen. Hier werde ich nur auf den Kernpunkt eingehen – dieser zeigt in einer Funktion immer auf das Objekt, das ihn aufruft. Die folgenden Geschichten werden sich alle um diesen Punkt drehen.
[Geschichte] Eines Tages reiste Dis aus Versehen in eine andere Welt namens „Gavaskeli“ (Javascript). In diesem Moment war Dis mittellos, der erste Was er tun muss, ist, seinen Aufenthaltsort zu finden – das Objekt, um die Funktion aufzurufen
Standardbindung davon
[Geschichte – Route 1] Wenn Dis (dies) erst bei Einbruch der Dunkelheit verfügbar ist, kann kein Ort gefunden werden, an dem man ihn aufnehmen kann. Er war dabei, das Leben eines afrikanischen Flüchtlings zu führen. Zu diesem Zeitpunkt erschien ein gutherziger Zauberer, ein Fensterretter, wie ein Retter: Bleib zuerst in meinem Haus!
[Text]
Wenn eine Funktion kein klares Aufrufobjekt hat, das heißt, wenn sie einfach als aufgerufen wird eine unabhängige Funktion, hierfür wird die Standardbindung der Funktion verwendet: gebunden an das globale Fensterobjekt
function fire () {
console.log(this === window)
}
fire(); // 输出true
I Glauben Sie dem obigen Beispiel. Für die meisten Menschen ist es einfach, aber manchmal ist es verwirrend, wenn wir das Beispiel ändern:
function fire () {
// 我是被定义在函数内部的函数哦! function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用}
fire(); // 输出true
Die Funktion innerFire wird in einer externen Funktion fire deklariert und aufgerufen. An wen richtet sich dieser Hinweis? Stilles Fenster
Viele Menschen sind möglicherweise besorgt über die Auswirkungen des Umfangs der Feuerfunktion auf InnerFire, aber wir müssen nur unsere theoretische Waffe ergreifen – wenn es kein klares Rufobjekt gibt, werden wir dieses verwenden Funktion Standardbindung: An das globale Fensterobjekt binden, um die richtige Antwort zu erhalten
Das folgende erweiterte Versionsbeispiel gibt auf die gleiche Weise auch true aus
var obj = {
fire: function () {
function innerFire() {
console.log(this === window)
}
innerFire(); // 独立函数调用 }
}
obj.fire(); //输出 true
[Hinweis] In diesem Beispiel ist der Aufruf an obj.fire() verwendet tatsächlich die implizite Bindung davon. Darüber werde ich weiter unten sprechen.
[Zusammenfassung] Alle Funktionen sind unabhängig. Ein Funktionsaufruf, egal wo befindet, verhält sich genauso wie ein direkter Aufruf in der globalen Umgebung
diese implizite Bindung
[Story - Route 2] Als Dis (dies) in die andere Welt „Gavaskeli“ (Javascript) reiste, hatte er zufällig etwas Geld bei sich und fand ein Hotel. Übernachtet
Wenn eine Funktion in einem Objekt „enthalten“ ist, sagen wir, dass die Funktion implizit an das Objekt gebunden ist. Zu diesem Zeitpunkt können Sie dadurch direkt auf andere Eigenschaften im gebundenen Objekt zugreifen. wie zum Beispiel die folgende Eigenschaft
var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
Jetzt müssen wir etwas tiefer über die allgemeinen Codeoperationen nachdenken. Zuerst erzielen die beiden Codeteile den gleichen Effekt:
// 我是第一段代码function fire () {
console.log(this.a)
}
var obj = {
a: 1,
fire: fire
}
obj.fire(); // 输出1
// 我是第二段代码var obj = {
a: 1,
fire: function () {
console.log(this.a)
}
}
obj.fire(); // 输出1
Die Feuerfunktion macht keinen Unterschied, da es innerhalb und außerhalb des obj-Objekts definiert ist, d 🎜>1. Dies ist dynamisch gebunden, oder es ist während der Laufzeit des Codes gebunden und nicht während des Schreibzeitraums
2. Die Unabhängigkeit von Funktionen von Objekten, das Problem des Übertragungsverlusts davon
(下面的描述可能带有个人的情感倾向而显得不太严谨,但这是因为我希望阅读者尽可能地理解我想表达的意思)
隐式绑定下,作为对象属性的函数,对于对象来说是独立的
基于this动态绑定的特点,写在对象内部,作为对象属性的函数,对于这个对象来说是独立的。(函数并不被这个外部对象所“完全拥有”)
我想表达的意思是:在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
借用下面的隐式绑定中的this传递丢失问题来说明:
var obj = {
a: 1, // a是定义在对象obj中的属性 1 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 2var fireInGrobal = obj.fire;
fireInGrobal(); // 输出 2
上面这段简单代码的有趣之处在于: 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,其原因在于:我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window
上面的例子稍微变个形式就会变成一个可能困扰我们的bug:
var a = 2;var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
function otherFire (fn) {
fn();
}
otherFire(obj.fire); // 输出2
在上面,我们的关键角色是otherFire函数,它接受一个函数引用作为参数,然后在内部直接调用,但它做的假设是参数fn仍然能够通过this去取得obj内部的a属性,但实际上, this对obj的绑定早已经丢失了,所以输出的是全局的a的值(2),而不是obj内部的a的值(1)
在一串对象属性链中,this绑定的是最内层的对象
在隐式绑定中,如果函数调用位置是在一串对象属性链中,this绑定的是最内层的对象。如下所示:
var obj = {
a: 1,
obj2: {
a: 2,
obj3: {
a:3,
getA: function () {
console.log(this.a)
}
}
}
}
obj.obj2.obj3.getA(); // 输出3
this的显式绑定:(call和bind方法)
【故事——线路3】 迪斯(this)穿越来异世界“伽瓦斯克利”(javascript),经过努力的打拼,积累了一定的财富,于是他买下了自己的房子
上面我们提到了this的隐式绑定所存在的this绑定丢失的问题,也就是对于 “ fireInGrobal = obj.fire”
fireInGrobal调用和obj.fire调用的结果是不同的,因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候,call函数就派上用场了
call的基本使用方式: fn.call(object)
fn是你调用的函数,object参数是你希望函数的this所绑定的对象。
fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象
例子:
var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 var fireInGrobal = obj.fire;
fireInGrobal(); // 输出2fireInGrobal.call(obj); // 输出1
原本丢失了与obj绑定的this参数的fireInGrobal再次重新把this绑回到了obj
但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。
怎么办呢? 聪明的你一定能想到,在fireInGrobal.call(obj)外面包装一个函数不就可以了嘛!
var obj = {
a: 1, // a是定义在对象obj中的属性 fire: function () {
console.log(this.a)
}
}
var a = 2; // a是定义在全局环境中的变量 var fn = obj.fire;var fireInGrobal = function () {
fn.call(obj) //硬绑定}
fireInGrobal(); // 输出1
如果使用bind的话会更加简单
var fireInGrobal = function () {
fn.call(obj) //硬绑定}
可以简化为:
var fireInGrobal = fn.bind(obj);
call和bind的区别是:在绑定this到对象参数的同时:
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数
【其他】:至于apply,因为除了使用方法,它和call并没有太大差别,这里不加赘述
在这里,我把显式绑定和隐式绑定下,函数和“包含”函数的对象间的关系比作买房和租房的区别。
因为this的缘故
在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了
在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“
new绑定
【故事】 迪斯(this)组建了自己的家庭,并生下多个孩子(通过构造函数new了许多个对象)
执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象