首頁  >  文章  >  web前端  >  理解“this”關鍵字

理解“this”關鍵字

PHPz
PHPz原創
2023-08-30 17:05:09914瀏覽

理解“this”關鍵字

建立函數時,會建立一個名為 this 的關鍵字(在幕後),該關鍵字會連結到函數運行的物件。換句話說,this 可用於其函數的範圍,但它是對該函數作為屬性或方法的物件的參考。

#讓我們來看看上一篇文章中的 cody 物件:

範例:sample98.html

<!DOCTYPE html><html lang="en"><body><script>

	var cody = {
		living: true,
		age: 23,
		gender: 'male',
		getGender: function () { return cody.gender; }
	};

	console.log(cody.getGender()); // Logs 'male'.

</script></body></html>

注意在getGender 函數內部,我們如何在cody 物件本身上使用點表示法(cody.gender) 存取gender 屬性。可以使用 this 重寫來存取 cody 對象,因為 this 指向 cody 物件。

範例:sample99.html

<!DOCTYPE html><html lang="en"><body><script>

	var cody = {
		living: true,
		age: 23,
		gender: 'male',
		getGender: function () { return this.gender; }
	};

	console.log(cody.getGender()); // Logs 'male'.

</script></body></html>

this.gender 中使用的 this 只是指操作該函數的 cody 物件。

this 的主題可能會令人困惑,但事實並非如此。請記住,一般來說, this 在函數內部使用來引用該函數所包含的對象,而不是函數本身(例外情況包括使用new 關鍵字或 call()應用())。

關鍵字 this 的外觀和行為與任何其他變數類似,只是您無法修改它。

arguments 和發送到函數的任何參數相反,this 是呼叫/激活物件中的關鍵字(而不是屬性)。


this 的值是如何決定的?

傳遞給所有函數的 this 的值是基於運行時呼叫該函數的上下文。請注意這裡,因為這是您只需要記住的怪癖之一。

以下程式碼範例中的 myObject 物件被賦予一個名為 sayFoo 的屬性,該屬性指向 sayFoo 函數。當從全域範圍呼叫 sayFoo 函數時,this 引用 window 物件。當作為 myObject 的方法呼叫時,this 指的是 myObject

由於 myObject 有一個名為 foo 的屬性,因此使用該屬性。

範例:sample100.html

#
<!DOCTYPE html><html lang="en"><body><script>

	var foo = 'foo';
	var myObject = { foo: 'I am myObject.foo' };

	var sayFoo = function () {
		console.log(this['foo']);
	};

	// Give myObject a sayFoo property and have it point to the sayFoo function.
	myObject.sayFoo = sayFoo;

	myObject.sayFoo(); // Logs 'I am myObject.foo'.
	sayFoo(); // Logs 'foo'.

</script></body></html>

顯然,this 的值是基於呼叫該函數的上下文。考慮 myObject.sayFoosayFoo 都指向相同的函式。但是,根據呼叫 sayFoo() 的位置(上下文),this 的值會有所不同。

如果有幫助,這裡是明確使用頭物件(window)的相同程式碼。

範例:sample101.html

#
<!DOCTYPE html><html lang="en"><body><script>

	window.foo = 'foo';
	window.myObject = { foo: 'I am myObject.foo' };

	window.sayFoo = function () {
		console.log(this.foo);
	};

	window.myObject.sayFoo = window.sayFoo;

	window.myObject.sayFoo();
	window.sayFoo();

</script></body></html>

確保當您傳遞函數或對函數進行多次引用時,您意識到 this 的值將根據您呼叫該函數的上下文而變化。

thisarguments 之外的所有變數都遵循詞法範圍


this 關鍵字引用巢狀函數中的頭物件

您可能想知道當 this 在一個包含在另一個函數中的函數內部使用時會發生什麼。壞消息是在 ECMA 3 中,this 迷失了方向並引用了頭物件(瀏覽器中的 window 物件),而不是定義該函數的物件。

在下面的程式碼中,func2func3 中的this 迷失了方向,並且不是指向myObject 而是指向頭對象。

範例:sample102.html

#
<!DOCTYPE html><html lang="en"><body><script>

	var myObject = {
		func1: function () {
			console.log(this); // Logs myObject.
			var func2 = function () {
				console.log(this) // Logs window, and will do so from this point on.
				var func3 = function () {
					console.log(this); // Logs window, as it’s the head object.
				} ();
			} ();
		}
	}

	myObject.func1();

</script></body></html>

好消息是,這個問題將會在 ECMAScript 5 中解決。現在,您應該意識到這種困境,尤其是當您開始將函數作為值傳遞給其他函數時。

考慮下一個範例以及將匿名函數傳遞給 foo.func1 時會發生什麼。當在 foo.func1 (函數中的函數)內部呼叫匿名函數時,匿名函數內部的 this 值將是對 head 物件的參考。

範例:sample103.html

#
<!DOCTYPE html><html lang="en"><body><script>

	var foo = {
		func1: function (bar) {
			bar(); // Logs window, not foo.
			console.log(this); // The this keyword here will be a reference to the foo object.
		}
	}

	foo.func1(function () { console.log(this) });

</script></body></html>

現在你永遠不會忘記:當其宿主函數封裝在另一個函數內或在另一個函數的上下文中呼叫時,this 值將始終是對頭物件的參考(同樣,這在ECMAScript 5 中已修復) )。


利用作用域鏈解決巢狀函數問題

為了讓 this 值不會遺失,您可以簡單地使用作用域鏈在父函數中保留對 this 的參考。以下範例示範如何使用名為 that 的變數並利用其作用域,我們可以更好地追蹤函數上下文。

範例:sample104.html

#
<!DOCTYPE html><html lang="en"><body><script>

var myObject = {
	myProperty: 'I can see the light', 
	myMethod : function(){
		var that = this; // Store a reference to this (myObject) in myMethod scope.
		var helperFunction = function() { // Child function.
			// Logs 'I can see the light' via scope chain because that = this.
			console.log(that.myProperty); // Logs 'I can see the light'.
			console.log(this); // Logs window object, if we don't use "that".
		}();
	}
}

myObject.myMethod(); // Invoke myMethod.

</script></body></html>

使用 call()apply() 控制 this 的值

this 的值通常由调用函数的上下文确定(除非使用 new 关键字,稍后会详细介绍),但您可以使用 this 的值>apply() 或 call() 来定义调用函数时 this 指向什么对象。使用这些方法就像在说:“嘿,调用 X 函数,但告诉该函数使用 Z 对象作为 this 的值。”通过这样做,JavaScript 确定 this 值的默认方式将被覆盖。

在下一个示例中,我们创建一个对象和一个函数。然后我们通过 call() 调用该函数,以便函数内 this 的值使用 myObject 作为其上下文。 myFunction 函数内的语句将使用属性填充 myObject,而不是填充头对象。我们更改了 this (在 myFunction 内部)引用的对象。

示例:sample105.html

<!DOCTYPE html><html lang="en"><body><script>

	var myObject = {};

	var myFunction = function (param1, param2) {
		// Set via call(), 'this' points to myObject when function is invoked.
		this.foo = param1;
		this.bar = param2;
		console.log(this) // Logs Object {foo = 'foo', bar = 'bar'}
	};

	myFunction.call(myObject, 'foo', 'bar'); // Invoke function, set this value to myObject.

	console.log(myObject) // Logs Object {foo = 'foo', bar = 'bar'}

</script></body></html>

在前面的示例中,我们使用了 call(),但也可以使用 apply()。两者之间的区别在于函数参数的传递方式。使用 call(),参数只是逗号分隔的值。使用 apply(),参数值在数组内部传递,如以下示例所示。

示例:sample106.html

<!DOCTYPE html><html lang="en"><body><script>

	var myObject = {};

	var myFunction = function (param1, param2) {
		// Set via apply(), this points to myObject when function is invoked.
		this.foo = param1;
		this.bar = param2;
		console.log(this) // Logs Object {foo = 'foo', bar = 'bar'}
	};

	myFunction.apply(myObject, ['foo', 'bar']); // Invoke function, set this value.

	console.log(myObject) // Logs Object {foo = 'foo', bar = 'bar'}

</script></body></html>

这里您需要学习的是,您可以覆盖 JavaScript 在函数作用域中确定 this 值的默认方式。


在用户定义的构造函数中使用 this 关键字

当使用 new 关键字调用函数时,构造函数中声明的 this 的值指的是实例本身。换句话说:在构造函数中,我们可以在实际创建对象之前通过 this 来利用该对象。在这种情况下, this 的默认值的更改方式类似于使用 call()apply()

在下面的示例中,我们设置了一个 Person 构造函数,该函数使用 this 来引用正在创建的对象。当创建 Person 的实例时,this.name 将引用新创建的对象,并在新对象中放置一个名为 name 的属性,并将参数 (name) 中的值传递给构造函数。 p>

示例:sample107.html

<!DOCTYPE html><html lang="en"><body><script>

	var Person = function (name) {
		this.name = name || 'john doe'; // this will refer to the instance created.
	}

	var cody = new Person('Cody Lindley'); // Create an instance based on the Person constructor.

	console.log(cody.name); // Logs 'Cody Lindley'.

</script></body></html>

同样,当使用 new 关键字调用构造函数时,this 指的是“将成为的对象”。如果我们没有使用 new 关键字,则 this 的值将是调用 Person 的上下文 - 在本例中为头对象。让我们看一下以下场景:

示例:sample108.html

<!DOCTYPE html><html lang="en"><body><script>

	var Person = function (name) {
		this.name = name || 'john doe';
	}

	var cody = Person('Cody Lindley'); // Notice we did not use 'new'.

	console.log(cody.name); // Undefined. The value is actually set at window.name

	console.log(window.name); // Logs 'Cody Lindley'.

</script></body></html>

原型方法中的关键字 this 引用构造函数实例

当在添加到构造函数 prototype 属性的函数中使用时,this 指的是调用该方法的实例。假设我们有一个自定义 Person() 构造函数。作为参数,它需要人的全名。如果我们需要访问人员的全名,我们将 whatIsMyFullName 方法添加到 Person.prototype 中,以便所有 Person 实例继承该方法。当使用 this 时,该方法可以引用调用它的实例(以及它的属性)。

这里我演示了创建两个Person对象(codylisa)以及继承的whatIsMyFullName方法,其中包含this关键字来访问实例。

示例:sample109.html

<!DOCTYPE html><html lang="en"><body><script>

	var Person = function (x) {
		if (x) { this.fullName = x };
	};

	Person.prototype.whatIsMyFullName = function () {
		return this.fullName; // 'this' refers to the instance created from Person()
	}

	var cody = new Person('cody lindley');
	var lisa = new Person('lisa lindley');

	// Call the inherited whatIsMyFullName method, which uses this to refer to the instance.
	console.log(cody.whatIsMyFullName(), lisa.whatIsMyFullName());

	/* The prototype chain is still in effect, so if the instance does not have a fullName property, it will look for it in the prototype chain. Next, we add a fullName property to both the Person prototype and the Object prototype. See the notes that follow this sample. */

	Object.prototype.fullName = 'John Doe';
	var john = new Person(); // No argument is passed so fullName is not added to the instance.
	console.log(john.whatIsMyFullName()); // Logs 'John Doe'.

</script></body></html>

结论

这里要带走的概念是 that 关键字 this 用于在 prototype 对象中包含的方法内部使用时引用实例。如果实例不包含该属性,则开始查找原型。

如果 this 指向的实例或对象不包含所引用的属性,则应用适用于任何属性查找的相同规则,并且将在原型链上“查找”该属性。因此,在我们的示例中,如果 fullName 属性未包含在我们的实例中,则将在 Person.prototype.fullName 中查找 fullName 属性,然后在 Object.prototype.fullName 中查找。

以上是理解“this”關鍵字的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn