與物件和屬性一起工作

WBOY
發布: 2023-09-03 08:33:10
原創
1300 人瀏覽過

與物件和屬性一起工作

複雜物件可以保存任何允許的 JavaScript 值。在以下程式碼中,我建立一個名為 myObjectObject() 對象,然後新增表示 JavaScript 中可用的大多數值的屬性。


複雜物件

#範例:sample29.html

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

	var myObject = {};

	// Contain properties inside of myObject representing most of the native JavaScript values.
	myObject.myFunction = function () { };
	myObject.myArray = [];
	myObject.myString = 'string';
	myObject.myNumber = 33;
	myObject.myDate = new Date();
	myObject.myRegExp = /a/;
	myObject.myNull = null;
	myObject.myUndefined = undefined;
	myObject.myObject = {};
	myObject.myMath_PI = Math.PI;
	myObject.myError = new Error('Darn!');

	console.log(myObject.myFunction, myObject.myArray, myObject.myString, myObject.myNumber, myObject.myDate, myObject.myRegExp, myObject.myNull, myObject.myNull, myObject.myUndefined, myObject.myObject, myObject.myMath_PI, myObject.myError);

	/* Works the same with any of the complex objects, for example a function. */
	var myFunction = function () { };

	myFunction.myFunction = function () { };
	myFunction.myArray = [];
	myFunction.myString = 'string';
	myFunction.myNumber = 33;
	myFunction.myDate = new Date();
	myFunction.myRegExp = /a/;
	myFunction.myNull = null;
	myFunction.myUndefined = undefined;
	myFunction.myObject = {};
	myFunction.myMath_PI = Math.PI;
	myFunction.myError = new Error('Darn!');

	console.log(myFunction.myFunction, myFunction.myArray, myFunction.myString, myFunction.myNumber, myFunction.myDate, myFunction.myRegExp, myFunction.myNull, myFunction.myNull, myFunction.myUndefined, myFunction.myObject, myFunction.myMath_PI, myFunction.myError);

</script></body></html>
登入後複製

這裡要學習的簡單概念是,複雜物件可以包含任何可以在 JavaScript 中名義上表達的內容。當您看到此操作完成時,您不應該感到驚訝,因為所有本機物件都可以發生變化。這甚至適用於物件形式的String()Number()Boolean() 值,即使用new 運算子創建它們時。


以程式設計方式有益的方式封裝複雜物件

Object()Array()Function() 物件可以包含其他複雜物件。在下面的範例中,我透過使用 Object() 物件來設定物件樹來示範這一點。

範例:sample30.html

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

// Encapsulation using objects creates object chains.
var object1 = {
	object1_1: {
		object1_1_1: {foo: 'bar'}, 
		object1_1_2: {}, 
	}, 
	object1_2: {
		object1_2_1: {}, 
		object1_2_2: {}, 
	}
};

console.log(object1.object1_1.object1_1_1.foo); // Logs 'bar'.

</script></body></html>
登入後複製

可以使用 Array() 物件(又稱多維數組)或 Function() 物件完成相同的操作。

範例:sample31.html

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

	// Encapsulation using arrays creates a multidimensional array chain.
	var myArray = [[[]]]; // An empty array, inside an empty array, inside an empty array.

	/* Here is an example of encapsulation using functions: An empty function inside an empty function inside an empty function. */
	var myFunction = function () {
		// Empty function.
		var myFunction = function () {
			// Empty function.
			var myFunction = function () {
				// Empty function.
			};
		};
	};

	// We can get crazy and mix and match too.
	var foo = [{ foo: [{ bar: { say: function () { return 'hi'; } }}]}];
	console.log(foo[0].foo[0].bar.say()); // Logs 'hi'.

</script></body></html>
登入後複製

這裡要掌握的主要概念是,一些複雜物件被設計為以程式設計上有益的方式封裝其他物件。


使用點表示法或括號表示法來取得、設定和更新物件的屬性

我們可以使用點符號或方括號符號來取得、設定或更新物件的屬性。

在下面的範例中,我示範了點表示法,這是透過使用物件名稱後跟句點,然後後面跟著要取得、設定或更新的屬性來完成的(例如,objectName.property )。 < /p>

範例:sample32.html

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

	// Create a cody Object() object.
	var cody = new Object();

	// Setting properties.
	cody.living = true;
	cody.age = 33;
	cody.gender = 'male';
	cody.getGender = function () { return cody.gender; };

	// Getting properties.
	console.log(
		cody.living,
		cody.age,
		cody.gender,
		cody.getGender()
		); // Logs 'true 33 male male'.

	// Updating properties, exactly like setting.
	cody.living = false;
	cody.age = 99;
	cody.gender = 'female';
	cody.getGender = function () { return 'Gender = ' + cody.gender; };

	console.log(cody);

</script></body></html>
登入後複製

點表示法是取得、設定或更新物件屬性最常見的表示法。

除非需要,否則括號表示法並不常用。在下面的範例中,我將上一個範例中使用的點符號替換為括號符號。物件名稱後面跟著一個左括號、屬性名稱(用引號引起來),然後是一個右括號:

範例:sample33.html

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

	// Creating a cody Object() object.
	var cody = new Object();

	// Setting properties.
	cody['living'] = true;
	cody['age'] = 33;
	cody['gender'] = 'male';
	cody['getGender'] = function () { return cody.gender; };

	// Getting properties.
	console.log(
		cody['living'],
		cody['age'],
		cody['gender'],
		cody['getGender']() // Just slap the function invocation on the end!
		); // Logs 'true 33 male male'.

	// Updating properties, very similar to setting.
	cody['living'] = false;
	cody['age'] = 99;
	cody['gender'] = 'female';
	cody['getGender'] = function () { return 'Gender = ' + cody.gender; };

	console.log(cody);

</script></body></html>
登入後複製

當您需要存取屬性鍵並且您必須使用包含表示屬性名稱的字串值的變數時,括號表示法非常有用。在下一個範例中,我透過使用方括號表示法來存取屬性 foobar 來示範括號表示法相對於點表示法的優勢。我使用兩個變數來執行此操作,這兩個變數在連接時會產生 foobarObject 中包含的屬性鍵的字串版本。

範例:sample34.html

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

	var foobarObject = { foobar: 'Foobar is code for no code' };

	var string1 = 'foo';
	var string2 = 'bar';

	console.log(foobarObject[string1 + string2]); // Let's see dot notation do this!

</script></body></html>
登入後複製

此外,括號表示法可以方便地取得無效 JavaScript 標識符的屬性名稱。在下面的程式碼中,我使用一個數字和一個保留關鍵字作為屬性名稱(作為字串有效),只有括號表示法才能存取該屬性名稱。

範例:sample35.html

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

	var myObject = { '123': 'zero', 'class': 'foo' };

	// Let's see dot notation do this! Keep in mind 'class' is a keyword in JavaScript.
	console.log(myObject['123'], myObject['class']); //Logs 'zero foo'.

	// It can't do what bracket notation can do, in fact it causes an error.
	// console.log(myObject.0, myObject.class);

</script></body></html>
登入後複製

因為物件可以包含其他對象,所以cody.object.object.object.objectcody['object']['object']['object']['object' ] 可以在以下位置查看次。這稱為對象鏈。物件的封裝可以無限期地進行下去。

物件在 JavaScript 中是可變的,這意味著可以隨時對大多數物件執行取得、設定或更新它們。透過使用括號表示法(例如,cody['age']),您可以模仿其他語言中的關聯數組。

如果物件內的屬性是方法,您要做的就是使用 () 運算子(例如 cody.getGender())來呼叫屬性方法。


刪除物件屬性

delete 運算子可用來完全刪除物件的屬性。在下面的程式碼片段中,我們從 foo 物件中刪除 bar 屬性。

範例:sample36.html

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

	var foo = { bar: 'bar' };
	delete foo.bar;
	console.log('bar' in foo); // Logs false, because bar was deleted from foo.

</script></body></html>
登入後複製

delete 不會刪除在原型鏈上找到的屬性。

刪除是實際從物件中刪除屬性的唯一方法。將屬性設為 undefinednull 僅變更該屬性的值。它不會從物件中刪除屬性。


如何解析對物件屬性的參考

如果您嘗試存取物件中未包含的屬性,JavaScript 將嘗試使用原型鏈尋找該屬性或方法。在下面的範例中,我建立一個陣列並嘗試存取尚未定義的名為 foo 的屬性。您可能會認為,由於 myArray.foo 不是 myArray 物件的屬性,JavaScript 會立即傳回 undefined。但 JavaScript 會在另外兩個地方(Array.prototypeObject.prototype)找出 foo 的值,然後傳回 undefined

範例:sample37.html

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

	var myArray = [];

	console.log(myArray.foo); // Logs undefined.

	/* JS will look at Array.prototype for Array.prototype.foo, but it is not there. Then it will look for it at Object.prototype, but it is not there either, so undefined is returned! */

</script></body></html>
登入後複製

财产。如果它有该属性,它将返回该属性的值,并且不会发生继承,因为原型链没有被杠杆化。如果实例没有该属性,JavaScript 将在对象的构造函数 prototype 对象中查找它。

所有对象实例都有一个属性,该属性是创建该实例的构造函数的秘密链接(又名 __proto__)。可以利用这个秘密链接来获取构造函数,特别是实例构造函数的原型属性。

这是 JavaScript 中对象最令人困惑的方面之一。但让我们来推理一下。请记住,函数也是具有属性的对象。允许对象从其他对象继承属性是有意义的。就像说:“嘿,对象 B,我希望你分享对象 A 拥有的所有属性。”默认情况下,JavaScript 通过 prototype 对象将这一切连接到本机对象。当您创建自己的构造函数时,您也可以利用原型链。

JavaScript 到底是如何实现这一点的?在您了解它的本质之前,您会感到困惑:只是一组规则。让我们创建一个数组来更仔细地检查 prototype 属性。

示例:sample38.html

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

	// myArray is an Array object.
	var myArray = ['foo', 'bar'];

	console.log(myArray.join()); // join() is actually defined at Array.prototype.join

</script></body></html>
登入後複製

我们的 Array() 实例是一个具有属性和方法的对象。当我们访问其中一种数组方法时,例如 join(),我们问自己:从 Array() 构造函数创建的 myArray 实例是否有自己的 join() 方法?我们来检查一下。

示例:sample39.html

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

	var myArray = ['foo', 'bar'];

	console.log(myArray.hasOwnProperty('join')); // Logs false.

</script></body></html>
登入後複製

不,没有。然而 myArray 可以访问 join() 方法,就好像它是它自己的属性一样。这里发生了什么?好吧,您刚刚观察了原型链的运行情况。我们访问了一个属性,尽管该属性不包含在 myArray 对象中,但 JavaScript 可以在其他地方找到该属性。其他地方是非常具体的。当 Array() 构造函数由 JavaScript 创建时,join() 方法被添加(除其他外)作为 Array()prototype 属性的属性。

重申一下,如果您尝试访问不包含该属性的对象上的属性,JavaScript 将在 prototype 链中搜索该值。首先,它将查看创建对象的构造函数(例如,Array),并检查其原型(例如,Array.prototype)以查看是否可以在那里找到该属性。如果第一个原型对象没有该属性,则 JavaScript 会继续在初始构造函数后面的构造函数中沿链向上搜索。它可以一直做到这一点,直到链的末端。

链条的终点在哪里?让我们再次检查该示例,在 myArray 上调用 toLocaleString() 方法。

示例:sample40.html

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

	// myArray and Array.prototype contain no toLocaleString() method.
	var myArray = ['foo', 'bar'];

	// toLocaleString() is actually defined at Object.prototype.toLocaleString
	console.log(myArray.toLocaleString()); // Logs 'foo,bar'.

</script></body></html>
登入後複製

toLocaleString() 方法未在 myArray 对象中定义。因此,原型链接规则被调用,JavaScript 在 Array 构造函数原型属性中查找属性(例如,Array.prototype)。它也不存在,因此再次调用链式规则,我们在 Object() 原型属性 (Object.prototype) 中查找该属性。是的,它在那里找到。如果没有在那里找到它,JavaScript 将产生一个错误,指出该属性是 undefined

由于所有原型属性都是对象,因此链中的最终链接是 Object.prototype。没有其他可以检查的构造函数原型属性。

前面有一整章将原型链分解为更小的部分,所以如果你完全不明白这一点,请阅读该章,然后再回到这个解释来巩固你的理解。从这篇简短的文章中,我希望您明白,当找不到属性时(并被视为 undefined),JavaScript 将查看几个原型对象来确定属性是 undefined。查找总是会发生,这个查找过程就是 JavaScript 处理继承以及简单属性查找的方式。


使用 hasOwnProperty 验证对象属性不是来自原型链

虽然 in 运算符可以检查对象的属性,包括来自原型链的属性,但 hasOwnProperty 方法可以检查对象的属性是否来自原型链。

在下面的示例中,我们想知道 myObject 是否包含属性 foo,并且它没有从原型链继承该属性。为此,我们询问 myObject 是否有自己的名为 foo 的属性。

示例:sample41.html

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

	var myObject = {foo: 'value'};

	console.log(myObject.hasOwnProperty('foo')) // Logs true.

	// Versus a property from the prototype chain.
	console.log(myObject.hasOwnProperty('toString'));  // Logs false.

</script></body></html>
登入後複製

当您需要确定属性是对象的本地属性还是从原型链继承时,应该利用 hasOwnProperty 方法。


使用 in 运算符检查对象是否包含给定属性

in 运算符用于验证(true 或 false)对象是否包含给定属性。在此示例中,我们检查 foo 是否是 myObject 中的属性。

示例:sample42.html

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

	var myObject = { foo: 'value' };
	console.log('foo' in myObject); // Logs true.

</script></body></html>
登入後複製

您应该知道 in 运算符不仅检查引用的对象中包含的属性,还检查对象通过 prototype 链继承的任何属性。因此,应用相同的属性查找规则,如果当前对象中没有该属性,则将在 prototype 链上搜索该属性。

这意味着上一个示例中的 myObject 实际上通过 prototype 链 (Object.prototype.toString) 包含一个 toString 属性方法,即使我们没有指定一个(例如 myObject.toString) = 'foo')。

示例:sample43.html

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

	var myObject = { foo: 'value' };
	console.log('toString' in myObject); // Logs true.

</script></body></html>
登入後複製

在最后一个代码示例中,toString 属性实际上并不位于 myObject 对象内部。但是,它是从 Object.prototype 继承的,因此 in 运算符得出的结论是 myObject 实际上具有继承的 toString() 属性方法。


使用 for in 循环枚举(循环)对象的属性

通过使用 for in,我们可以循环访问对象中的每个属性。在以下示例中,我们使用 for in 循环从 cody 对象中检索属性名称。

示例:sample44.html

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

	var cody = {
		age: 23,
		gender: 'male'
	};

	for (var key in cody) { // key is a variable used to represent each property name. 
		// Avoid properties inherited from the prototype chain.
		if (cody.hasOwnProperty(key)) {
			console.log(key);
		}
	}

</script></body></html>
登入後複製

for in 循环有一个缺点。它不仅会访问正在循环的特定对象的属性。它还将在循环中包含对象继承(通过原型链)的任何属性。因此,如果这不是期望的结果,而且大多数情况下都不是,我们必须在循环内使用简单的 if 语句来确保我们只访问我们正在循环的特定对象中包含的属性。这可以通过使用所有对象继承的 hasOwnProperty() 方法来完成。

在循环中访问属性的顺序并不总是在循环中定义它们的顺序。此外,您定义属性的顺序不一定是访问它们的顺序。

只有可枚举的属性(即在循环对象属性时可用)才显示在 for in 循环中。例如,构造函数属性将不会显示。可以使用 propertyIsEnumerable() 方法检查哪些属性是可枚举的。


主机对象和本机对象

您应该知道,执行 JavaScript 的环境(例如 Web 浏览器)通常包含所谓的主机对象。宿主对象不是 ECMAScript 实现的一部分,但在执行期间可作为对象使用。当然,宿主对象的可用性和行为完全取决于宿主环境提供的内容。

例如,在网络浏览器环境中,window/head 对象及其所有包含对象(不包括 JavaScript 提供的对象)都被视为宿主对象。

在下面的示例中,我检查 window 对象的属性。

示例:sample45.html

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

	for (x in window) {
		console.log(x); // Logs all of the properties of the window/head object.
	}

</script></body></html>
登入後複製

您可能已经注意到,本机 JavaScript 对象未在主机对象中列出。浏览器区分主机对象和本机对象是相当常见的。

就 Web 浏览器而言,所有托管对象中最著名的是用于处理 HTML 文档的界面,也称为 DOM。以下示例是列出浏览器环境提供的 window.document 对象内包含的所有对象的方法。

示例:sample46.html

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

	for (x in window.document) {
		console.log();
	}

</script></body></html>
登入後複製

我希望您在这里了解的是 JavaScript 规范本身并不关心宿主对象,反之亦然。 JavaScript 提供的内容(例如,JavaScript 1.5、ECMA-262、第 3 版与 Mozilla 的 JavaScript 1.6、1.7、1.8、1.8.1、1.8.5)和主机环境提供的内容之间存在一条分界线,并且这两者不应该存在感到困惑。

运行 JavaScript 代码的主机环境(例如 Web 浏览器)通常提供头对象(例如 Web 浏览器中的 window 对象),其中语言的本机部分与主机对象(例如 一起存储) window.location(Web 浏览器中的 window.location)和用户定义的对象(例如,您编写的在 Web 浏览器中运行的代码)。

有时,网络浏览器制造商作为 JavaScript 解释器的宿主,会在获得批准之前推出 JavaScript 版本或添加未来的 JavaScript 规范(例如,Mozilla 的 Firefox JavaScript 1.6、1.7、1.8、1.8.1) ,1.8.5)。


使用 Underscore.js 增强和扩展对象

当需要认真操作和管理对象时,JavaScript 1.5 有所欠缺。如果您在 Web 浏览器中运行 JavaScript,那么当您需要比 JavaScript 1.5 提供的更多功能时,我想在这里大胆建议使用 Underscore.js。 Underscore.js 在处理对象时提供以下功能。

这些函数适用于所有对象和数组:

  • each()
  • #map()
  • #reduce()
  • #reduceRight()
  • 檢測()
  • #選擇()
  • #reject()
  • #all()
  • #any()
  • #include()
  • #呼叫()
  • #pluck()
  • #max()
  • #min()
  • #sortBy()
  • sortIndex()
  • toArray()
  • #size()

#這些函數適用於所有物件:

  • keys()
  • #values()
  • #函數()
  • #extend()
  • #複製()
  • tap()
  • #isEqual()
  • isEmpty()
  • isElement()
  • #isArray()
  • #isArguments
  • #isFunction()
  • isString()
  • #isNumber
  • #isBoolean
  • #isDate
  • #isRegExp
  • #isNaN
  • #isNull
  • #isUndefined

結論

我喜歡這個庫,因為它利用了瀏覽器支援的JavaScript 的新本機添加功能,而且還為不支援的瀏覽器提供了相同的功能,所有這些都無需更改JavaScript 的本機實現,除非必須這樣做。 p>

開始使用 Underscore.js 之前,請確保您的程式碼中可能已使用的 JavaScript 程式庫或框架尚未提供您所需的功能。

以上是與物件和屬性一起工作的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!