与对象和属性一起工作

wufei123 2024-06-02 阅读:4 评论:0
复杂对象可以保存任何允许的 JavaScript 值。在以下代码中,我创建一个名为 myObject 的 Object() 对象,然后添加表示 JavaScript 中可用的大多数值的属性。 复杂对象 示例:sample29.html...

与对象和属性一起工作

复杂对象可以保存任何允许的 JavaScript 值。在以下代码中,我创建一个名为 myObject 的 Object() 对象,然后添加表示 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)。

示例: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.object 或 cody['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 不会删除在原型链上找到的属性。

删除是实际从对象中删除属性的唯一方法。将属性设置为 undefined 或 null 仅更改该属性的值。它不会从对象中删除属性。

如何解析对对象属性的引用

如果您尝试访问对象中未包含的属性,JavaScript 将尝试使用原型链查找该属性或方法。在下面的示例中,我创建一个数组并尝试访问尚未定义的名为 foo 的属性。您可能会认为,由于 myArray.foo 不是 myArray 对象的属性,JavaScript 将立即返回 undefined。但是 JavaScript 会在另外两个地方(Array.prototype 和 Object.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
  • isUn​​defined
结论

我喜欢这个库,因为它利用了浏览器支持的 JavaScript 的新本机添加功能,而且还为不支持的浏览器提供了相同的功能,所有这些都无需更改 JavaScript 的本机实现,除非必须这样做。 p>

开始使用 Underscore.js 之前,请确保您的代码中可能已使用的 JavaScript 库或框架尚未提供您所需的功能。

以上就是与对象和属性一起工作的详细内容,更多请关注知识资源分享宝库其它相关文章!

版权声明

本站内容来源于互联网搬运,
仅限用于小范围内传播学习,请在下载后24小时内删除,
如果有侵权内容、不妥之处,请第一时间联系我们删除。敬请谅解!
E-mail:dpw1001@163.com

分享:

扫一扫在手机阅读、分享本文

发表评论
热门文章
  • 华为 Mate 70 性能重回第一梯队 iPhone 16 最后一块遮羞布被掀

    华为 Mate 70 性能重回第一梯队 iPhone 16 最后一块遮羞布被掀
    华为 mate 70 或将首发麒麟新款处理器,并将此前有博主爆料其性能跑分将突破110万,这意味着 mate 70 性能将重新夺回第一梯队。也因此,苹果 iphone 16 唯一能有一战之力的性能,也要被 mate 70 拉近不少了。 据悉,华为 Mate 70 性能会大幅提升,并且销量相比 Mate 60 预计增长40% - 50%,且备货充足。如果 iPhone 16 发售日期与 Mate 70 重合,销量很可能被瞬间抢购。 不过,iPhone 16 还有一个阵地暂时难...
  • 酷凛 ID-COOLING 推出霜界 240/360 一体水冷散热器,239/279 元

    酷凛 ID-COOLING 推出霜界 240/360 一体水冷散热器,239/279 元
    本站 5 月 16 日消息,酷凛 id-cooling 近日推出霜界 240/360 一体式水冷散热器,采用黑色无光低调设计,分别定价 239/279 元。 本站整理霜界 240/360 散热器规格如下: 酷凛宣称这两款水冷散热器搭载“自研新 V7 水泵”,采用三相六极马达和改进的铜底方案,缩短了水流路径,相较上代水泵进一步提升解热能力。 霜界 240/360 散热器的水泵为定速 2800 RPM 设计,噪声 28db (A)。 两款一体式水冷散热器采用 27mm 厚冷排,...
  • 惠普新款战 99 笔记本 5 月 20 日开售:酷睿 Ultra / 锐龙 8040,4999 元起

    惠普新款战 99 笔记本 5 月 20 日开售:酷睿 Ultra / 锐龙 8040,4999 元起
    本站 5 月 14 日消息,继上线官网后,新款惠普战 99 商用笔记本现已上架,搭载酷睿 ultra / 锐龙 8040处理器,最高可选英伟达rtx 3000 ada 独立显卡,售价 4999 元起。 战 99 锐龙版 R7-8845HS / 16GB / 1TB:4999 元 R7-8845HS / 32GB / 1TB:5299 元 R7-8845HS / RTX 4050 / 32GB / 1TB:7299 元 R7 Pro-8845HS / RTX 2000 Ada...
  • Nginx服务器的HTTP/2协议支持和性能提升技巧介绍

    Nginx服务器的HTTP/2协议支持和性能提升技巧介绍
    Nginx服务器的HTTP/2协议支持和性能提升技巧介绍 引言:随着互联网的快速发展,人们对网站速度的要求越来越高。为了提供更快的网站响应速度和更好的用户体验,Nginx服务器的HTTP/2协议支持和性能提升技巧变得至关重要。本文将介绍如何配置Nginx服务器以支持HTTP/2协议,并提供一些性能提升的技巧。 一、HTTP/2协议简介:HTTP/2协议是HTTP协议的下一代标准,它在传输层使用二进制格式进行数据传输,相比之前的HTTP1.x协议,HTTP/2协议具有更低的延...
  • python怎么调用其他文件函数

    python怎么调用其他文件函数
    在 python 中调用其他文件中的函数,有两种方式:1. 使用 import 语句导入模块,然后调用 [模块名].[函数名]();2. 使用 from ... import 语句从模块导入特定函数,然后调用 [函数名]()。 如何在 Python 中调用其他文件中的函数 在 Python 中,您可以通过以下两种方式调用其他文件中的函数: 1. 使用 import 语句 优点:简单且易于使用。 缺点:会将整个模块导入到当前作用域中,可能会导致命名空间混乱。 步骤:...