Layer 1: 单一对象

粗略的说, 在javascript中所有对象都是maps的键值对. 键值对的实体在对象中称为属性( property).属性的key经常为 string类型,而他的value则可以是任何类型包括函数(function). 方法也可以作为函数的值充当属性.

属性的种类(Kinds of Properties)

3种属性的种类:

  • 数据属性(Properties or named data properties)
javascript对象中的常见的属性键值对(mappings from string keys to values). 数据属性包含方法. 这也是最常见的属性.
  • 存取器属性 (Accessors or named accessor properties)
当用到读,写属性的时候会用到特殊的方法. 一般的属性会在本地存储原型的值;存取器允许你计算属性的值. 你可以将这些属性虚拟化. 关于存取器的详情见 Accessors (Getters and Setters) .
  • 内部属性
只在 ECMAScript规格说明书中有详细的描述. 从 JavaScript不能直接访问,但是可以间接地访问他们. 规格说明书规定内部属性的 keys在括号中. 例如, [[Prototype]] 持有对象属性并且通过 Object.getPrototypeOf()可以读到此对象的属性值.

对象的‘字面值’(Object Literals)

JavaScript的对象允许你直接通过赋值的方式创建简单的对象(direct instances of Object。原因是Object的接口). 下面的代码表示通过对变量 jane赋值,将一个变量转换为对象. 对象有两个属性:name 和 describedescribe 是一个方法:

  1. var jane = {
  2. name: 'Jane',
  3.  
  4. describe: function () {
  5. return 'Person named '+this.name; // (1)
  6. }, // (2)
  7. };
  1. 在这个方法中通过 this引用当前对象 (also called the receiver of a method invocation).
  2. ECMAScript 5 允许在对象的属性值末尾有个小逗号(注意:这里说的是最后一个属性的后面) . 哎, 但是不是所有的浏览器都支持. 这个小逗号是很有用的, 因为你可以从新排列你的属性而且不担心他是不是最后一个属性.

你可以通过键值对的映射得到你想要的对象效果. 且他们一般都是设置好的有目的性的对象. 例如, 你可以在对象之间使用继承 (see Layer 2: The Prototype Relationship Between Objects。), 你也可以保护一个对象的属性防止他发生改变. 这种直接创建对象的能力是 JavaScript一个杰出的特性:你可以从当前的对象(不需要类!)开始也可以慢慢的引入抽象 .例如,构造器, 对象的工场 (as discussed in Layer 3: Constructors—Factories for Instances), 相对于使用类的语言简单明了.

Dot Operator (.): 可以通过对象Keys访问属性

"."操作符提供了一种简洁的访问对象属性的的语法. 属性的 keys必须被定义 (consult Legal Identifiers). 如果你想读写对象中的任意属性值,你只需要在方括号中加入你要的属性值的名字 (see Bracket Operator ([]): Accessing Properties via Computed Keys).

The examples in this section work with the following object:

  1. var jane = {
  2. name: 'Jane',
  3.  
  4. describe: function () {
  5. return 'Person named '+this.name;
  6. }
  7. };

Getting properties

'.'操作符通过 “get” 方法读取他的值. 例子如下:

  1. > jane.name // get property `name`
  2. 'Jane'
  3. > jane.describe // get property `describe`
  4. [Function]

获取对象不存在的属性值时返回 undefined:

  1. > jane.unknownProperty
  2. undefined

回调函数

"."操作符也可以使用回调函数,代码如下:

  1. > jane.describe() // call method `describe`
  2. 'Person named Jane'

Setting properties

你也可以使用等号 (=) 对属性从新赋值. 代码如下:

  1. > jane.name = 'John'; // set property `name`
  2. > jane.describe()
  3. 'Person named John'

如果一个属性不存在, 往里面赋值的时候会自动创建这个对象的属性. 如果他的属性存在那么改变他原有的属性.

Deleting properties

delete 操作符可以删除对象的全部属性(the whole key-value pair). 代码如下:

  1. > var obj = { hello: 'world' };
  2. > delete obj.hello
  3. true
  4. > obj.hello
  5. undefined

如果你仅仅是将对象的属性值定义为 undefined, 对象的属性依旧存在且包含他的 key:

  1. > var obj = { foo: 'a', bar: 'b' };
  2.  
  3. > obj.foo = undefined;
  4. > Object.keys(obj)
  5. [ 'foo', 'bar' ]

如果删除他的属性则他的 key 也被删除:

  1. > delete obj.foo
  2. true
  3. > Object.keys(obj)
  4. [ 'bar' ]

delete 操作直接影响对象的属性. 他的原型并不受到影响 (see Deleting an inherited property).

注意:

尽量少的使用 delete 操作. 现代大多数Javascript引擎为接口构造器提供优化保持"模型"不会被改变 (简单的说: 没有属性被添加、删除).删除属性可能会因为优化而被阻止.

The return value of delete

如果属性是构造器内部的属性 delete 将返回返回false删除失败. 代码如下.

其他不能删除的情况参见 (Getting and Defining Properties via Descriptorsexplains Object.defineProperty()):

  1. var obj = {};
  2. Object.defineProperty(obj, 'canBeDeleted', {
  3. value: 123,
  4. configurable: true
  5. });
  6. Object.defineProperty(obj, 'cannotBeDeleted', {
  7. value: 456,
  8. configurable: false
  9. });

delete returns false for own properties that can’t be deleted:

  1. > delete obj.cannotBeDeleted
  2. false

delete returns true in all other cases:

  1. > delete obj.doesNotExist
  2. true
  3. > delete obj.canBeDeleted
  4. true

delete returns true even if it doesn’t change anything (inherited properties are never removed):

  1. > delete obj.toString
  2. true
  3. > obj.toString // still there
  4. [Function: toString]

与众不同的属性键(Unusual Property Keys)

当你不想使用保留字(例如var与function)作为变量名,你可以使用他们的属性键:

  1. > var obj = { var: 'a', function: 'b' };
  2. > obj.var
  3. 'a'
  4. > obj.function
  5. 'b'

Numbers类型也可以作为对象的属性键在对象的‘字面值’中,但是他们会解析成为字符串.‘点’操作符只能在他们的属性键为标示符(identifiers)的时候来访问他们的属性值.因此,在这个时候你可以通过中括号的形式去访问(如果你想更理解标示符identifiers的含义,参见 http://en.wikipedia.org/wiki/Identifier#Identifiers_in_various_disciplines):

  1. > var obj = { 0.7: 'abc' };
  2. > Object.keys(obj)
  3. [ '0.7' ]
  4. > obj['0.7']
  5. 'abc'

你可以使用任意的字符串 (标识符和数字) 作为属性键.当你引用他们,访问他们的值的时候,你还是需要使用中括号:

  1. > var obj = { 'not an identifier': 123 };
  2. > Object.keys(obj)
  3. [ 'not an identifier' ]
  4. > obj['not an identifier']
  5. 123

中括号:通过属性键的计算访问属性的值(Bracket Operator ([]): Accessing Properties via Computed Keys)

‘点’操作符允许你访问属性值当属性键是确定的时候,而中括号则可以让你通过表达式的方式来访问属性值。

通过中括号获取属性值(Getting properties via the bracket operator)

中括号操作符让你通过表达式计算的方式获取你的属性键:

  1. > var obj = { someProperty: 'abc' };
  2.  
  3. > obj['some' + 'Property']
  4. 'abc'
  5.  
  6. > var propKey = 'someProperty';
  7. > obj[propKey]
  8. 'abc'

你也可以访问属性值,当你的属性键不为标示符的时候:

  1. > var obj = { 'not an identifier': 123 };
  2. > obj['not an identifier']
  3. 123

注意:在中括号的内部,他会强制转型为string. For example:

  1. > var obj = { '6': 'bar' };
  2. > obj[3+3] // key: the string '6'
  3. 'bar'

利用中括号操作符进行回调(Calling methods via the bracket operator)

你可以利用中括号进行方法回调:

  1. > var obj = { myMethod: function () { return true } };
  2. > obj['myMethod']()
  3. true

Setting properties via the bracket operator

类似于点操作符一样,使用中括号进行赋值:

  1. > var obj = {};
  2. > obj['anotherProperty'] = 'def';
  3. > obj.anotherProperty
  4. 'def'

利用中括号删除属性(Deleting properties via the bracket operator)

类似于点操作符一样,使用中括号操作符删除属性:

  1. > var obj = { 'not an identifier': 1, prop: 2 };
  2. > Object.keys(obj)
  3. [ 'not an identifier', 'prop' ]
  4. > delete obj['not an identifier']
  5. true
  6. > Object.keys(obj)
  7. [ 'prop' ]

值与对象的相互转换(Converting Any Value to an Object)

这不是一个经常发生的场景,但有的时候你需要去将任意值转化为一个对象. Object(), 使用 function (而不是构造器),提供转型服务. 遵循以下过程:

Value Result

(Called with no parameters)

{}

undefined

{}

null

{}

A boolean bool

new Boolean(bool)

A number num

new Number(num)

A string str

new String(str)

An object obj

obj (unchanged, nothing to convert)

Here are some examples:

  1. > Object(null) instanceof Object
  2. true
  3.  
  4. > Object(false) instanceof Boolean
  5. true
  6.  
  7. > var obj = {};
  8. > Object(obj) === obj
  9. true

以下方法,判断一个值是不是对象:

  1. function isObject(value) {
  2. return value === Object(value);
  3. }

你也可以调用对象的构造器,作为函数去回调会产生一样的结果:

  1. > var obj = {};
  2. > new Object(obj) === obj
  3. true
  4.  
  5. > new Object(123) instanceof Number
  6. true

this作为函数与方法的隐式参数(this as an Implicit Parameter of Functions and Methods)

当你回调函数的时候,"this"经常作为隐式的参数:

一般函数'sloppy模式"下

虽然在一般的函数中没有使用 this,但是 it依然作为特殊的全局对象 存在 (window in browsers; see The Global Object):

  1. > function returnThisSloppy() { return this }
  2. > returnThisSloppy() === window
  3. true
一般函数‘strict 模式’下

this 被定义为 undefined:

  1. > function returnThisStrict() { 'use strict'; return this }
  2. > returnThisStrict() === undefined
  3. true
Methods

this 被object方法引用时,方法得到调用:

  1. > var obj = { method: returnThisStrict };
  2. > obj.method() === obj
  3. true

在一些方法中, this的 值作为方法回调的接收器.

使用回调函数(call(), apply(), and bind())给 this赋值

记住functions也是对象。因此,每个 function 都有属于他自己的方法。这些 function 再使用回调时分为3个部分。在使用这些回调函数的时候有一些陷阱 .再引用上面jane对象, jane:

  1. var jane = {
  2. name: 'Jane',
  3. sayHelloTo: function (otherName) {
  4. 'use strict';
  5. console.log(this.name+' says hello to '+otherName);
  6. }
  7. };

Function.prototype.call(thisValue, arg1?, arg2?, ...)

第一个参数是 function内部调用的值,剩下的作为函数的参数被函数自身调用。以下3种调用方式是等价的:

  1. jane.sayHelloTo('Tarzan');
  2.  
  3. jane.sayHelloTo.call(jane, 'Tarzan');
  4.  
  5. var func = jane.sayHelloTo;
  6. func.call(jane, 'Tarzan');

在第二个回调步骤中,你需要重复的传入 jane 对象 ,因为 call()方法在被调用的时候不知道你是如何获取 function 的.

Function.prototype.apply(thisValue, argArray)

第一个参数是 function内部调用的值,而第二个数组作为函数被调用的参数. 以下3种调用方式是等价的:

  1. jane.sayHelloTo('Tarzan');
  2.  
  3. jane.sayHelloTo.apply(jane, ['Tarzan']);
  4.  
  5. var func = jane.sayHelloTo;
  6. func.apply(jane, ['Tarzan']);

在第二个回调步骤中,你需要重复的传入 jane 对象 ,因为apply()方法在被调用的时候不知道你是如何获取 function 的 .

Function.prototype.bind(thisValue, arg1?, ..., argN?)

这个方法执行局部的函数应用-意味着它将创建一个bind()回调函数的接收器: thisValue 和 arg1 .. argN作为新函数的参数.见一下例子:

  1. function func() {
  2. console.log('this: '+this);
  3. console.log('arguments: '+Array.prototype.slice.call(arguments));
  4. }
  5. var bound = func.bind('abc', 1, 2);

数组的 slice 将 arguments转型为数组, 记录他们是必要的 (this operation is explained in Array-Like Objects and Generic Methods). bound 是一个新的函数. 见以下代码:

  1. > bound(3)
  2. this: abc
  3. arguments: 1,2,3

The following three invocations of sayHelloTo are all equivalent:

  1. jane.sayHelloTo('Tarzan');
  2.  
  3. var func1 = jane.sayHelloTo.bind(jane);
  4. func1('Tarzan');
  5.  
  6. var func2 = jane.sayHelloTo.bind(jane, 'Tarzan');
  7. func2();

构造器手动模拟apply()(Manually simulating an apply() for constructors)

我们分两个阶段手动模拟 apply() .

Step 1

给Date对象传递参数并回调 (参数暂时不为数组):

  1. new (Date.bind(null, 2011, 11, 24))

代码被 bind()使用之前,会创建一个无参的构造器并且为之调用.

Step 2

apply()为 bind()传递数组.因为 bind()是回调方法,我们可以使用 apply():

  1. new (Function.prototype.bind.apply(
  2. Date, [null, 2011, 11, 24]))

数组在使用之前有很多的元素,与 null. 我们在此之前可以使用concat() :

  1. var arr = [2011, 11, 24];
  2. new (Function.prototype.bind.apply(
  3. Date, [null].concat(arr)))

陷阱:方法中Functions的 this 阴影(Pitfall: Functions Inside Methods Shadow this)

如下: function 在 (1)尝试访问方法 (2)处的 this:

  1. var obj = {
  2. name: 'Jane',
  3. friends: [ 'Tarzan', 'Cheeta' ],
  4. loop: function () {
  5. 'use strict';
  6. this.friends.forEach(
  7. function (friend) { // (1)
  8. console.log(this.name+' knows '+friend); // (2)
  9. }
  10. );
  11. }
  12. };

很明显, 失败, 因为 function 在 (1) 处 有他自身的 this,在这里是 undefined :

  1. > obj.loop();
  2. TypeError: Cannot read property 'name' of undefined

有3种解决此问题的方式.

Workaround 1: that = this

我们将this定义成为一个变量:

  1. loop: function () {
  2. 'use strict';
  3. var that = this;
  4. this.friends.forEach(function (friend) {
  5. console.log(that.name+' knows '+friend);
  6. });
  7. }

结果为:

  1. > obj.loop();
  2. Jane knows Tarzan
  3. Jane knows Cheeta

Workaround 2: bind()

使用 bind()  对 this进行回调—换句话说, 也就是方法(1)中的 this (line (1)):

  1. loop: function () {
  2. 'use strict';
  3. this.friends.forEach(function (friend) {
  4. console.log(this.name+' knows '+friend);
  5. }.bind(this)); // (1)
  6. }

Workaround 3: a thisValue for forEach()

forEach()方法提供了第二个参数 (see Examination Methods) 进行回调 this :

  1. loop: function () {
  2. 'use strict';
  3. this.friends.forEach(function (friend) {
  4. console.log(this.name+' knows '+friend);
  5. }, this);
  6. }

Layer 1: Single Objects的更多相关文章

  1. Chapter 17. Objects and Inheritance(对象与继承)

    javascript面向对象编程有几个层面: 1: 单一对象 (covered in Layer 1: Single Objects) 2: 对象之间的 prototype  (described i ...

  2. Performance Optimization (2)

    DesktopGood performance is critical to the success of many games. Below are some simple guidelines f ...

  3. [非官方]ArcGIS10.2 for Desktop扩展工具包——XTools Pro

    XTools Pro 是一套为ArcGIS平台设计的矢量空间分析. 形状转换和表管理扩展工具,大大增强了 ArcGIS 的功能,使用该工具能够提高 ArcGIS 用户的效率和性能. XTools Pr ...

  4. 说说 DWRUtil

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcytp27 说说 DWRUtil 比如我们从服务器端获得了一个citylist的数 ...

  5. 3DSMAX中英文对比大全(从A-Z分类)

    A Absolute Mode Transform Type-in绝对坐标方式变换输入 Absolute/Relative Snap Toggle Mode绝对/相对捕捉开关模式 ACIS Optio ...

  6. (转载)23种设计模式的uml图表示及通俗介绍

    转载自: https://www.cnblogs.com/ningskyer/articles/3615312.html 0.分类 创建型模式 1.FACTORY2.BUILDER3.FACTORY ...

  7. Streamline Your App with Design Patterns 用设计模式精简你的应用程序

    Back to Design Patterns Streamline Your App with Design Patterns 用设计模式精简你的应用程序 In Objective-C progra ...

  8. Framework for Graphics Animation and Compositing Operations

    FIELD OF THE DISCLOSURE The subject matter of the present disclosure relates to a framework for hand ...

  9. Advanced Architecture for ASP.NET Core Web API

    转自: https://www.infoq.com/articles/advanced-architecture-aspnet-core ASP.NET Core's new architecture ...

随机推荐

  1. hyperlink

    在list中create column时,注意HyperlinkOrPicture这一选项,如果某一列为HyperLinkOrPicture,那么在后台就不要再加<a></a> ...

  2. js中的null与undefined

    null undefined

  3. redhat6.5 配置使用centos的yum源

    新安装了redhat6.5安装后,登录系统,使用yum update 更新系统.提示: This system is not registered to Red Hat Subscription Ma ...

  4. 经历:如何设置jquery easyui中下拉框不可编辑

    今天,在项目中碰到一个这样的问题,当选择按钮时候,查询条件是可以输入的,否则,表单框是不可用的[图1].但是,批量查询中的船名和装港用到了自动配置,即jquery-easyui中的combox的配置. ...

  5. (九)Hibernate 检索策略

    所有项目导入对应的hibernate的jar包.mysql的jar包和添加每次都需要用到的HibernateUtil.java 这里的hibernate.cfg.xml配置信息我就不再写了 第一节:检 ...

  6. 暑假集训(3)第二弹 -----Jungle Roads(Hdu1301)

    问题梗概:自从上次某个acmer来设计了拉格瑞圣岛的交通路线后,岛上的酋长就相当苦恼,他发现,虽然这些修好的公路便利了岛上的 交通,并且让拉格瑞圣岛的旅游业更加兴旺,甚至他们还收到了一笔不小的国际资金 ...

  7. OpenJudge 2811 熄灯问题 / Poj 1222 EXTENDED LIGHTS OUT

    1.链接地址: http://bailian.openjudge.cn/practice/2811 http://poj.org/problem?id=1222 2.题目: 总时间限制: 1000ms ...

  8. Linux中的磁盘

    Linux的磁盘管理 (很重要请注意高能预警) 硬盘:几个盘片,双面,磁性颗粒, 处理速率不同步:借助于一个中间层 文件系统(FileSystem)     可以实现对磁盘行的文件进行读写     文 ...

  9. mysql的1045解决方法

    mysql的连接方式有两种: UNIX域套接字连接,如: mysql -u root -p mysql -h localhost -u root -p TCP/IP套接字连接,如: mysql -h ...

  10. 不使用BeanUtils,利用Java反射机制:表单数据自动封装到JavaBean

    在百度搜“java反射 将表单数据自动封装到javabean ”,第一页显示的都是一样的代码,都是利用导入第三方jar包<commons-beanutils>和<commons-lo ...