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 是一个方法:

var jane = {
name: 'Jane', describe: function () {
return 'Person named '+this.name; // (1)
}, // (2)
};
  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:

var jane = {
name: 'Jane', describe: function () {
return 'Person named '+this.name;
}
};

Getting properties

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

> jane.name  // get property `name`
'Jane'
> jane.describe // get property `describe`
[Function]

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

> jane.unknownProperty
undefined

回调函数

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

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

Setting properties

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

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

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

Deleting properties

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

> var obj = { hello: 'world' };
> delete obj.hello
true
> obj.hello
undefined

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

> var obj = { foo: 'a', bar: 'b' };

> obj.foo = undefined;
> Object.keys(obj)
[ 'foo', 'bar' ]

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

> delete obj.foo
true
> Object.keys(obj)
[ 'bar' ]

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

注意:

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

The return value of delete

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

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

var obj = {};
Object.defineProperty(obj, 'canBeDeleted', {
value: 123,
configurable: true
});
Object.defineProperty(obj, 'cannotBeDeleted', {
value: 456,
configurable: false
});

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

> delete obj.cannotBeDeleted
false

delete returns true in all other cases:

> delete obj.doesNotExist
true
> delete obj.canBeDeleted
true

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

> delete obj.toString
true
> obj.toString // still there
[Function: toString]

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

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

> var obj = { var: 'a', function: 'b' };
> obj.var
'a'
> obj.function
'b'

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

> var obj = { 0.7: 'abc' };
> Object.keys(obj)
[ '0.7' ]
> obj['0.7']
'abc'

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

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

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

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

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

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

> var obj = { someProperty: 'abc' };

> obj['some' + 'Property']
'abc' > var propKey = 'someProperty';
> obj[propKey]
'abc'

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

> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123

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

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

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

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

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

Setting properties via the bracket operator

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

> var obj = {};
> obj['anotherProperty'] = 'def';
> obj.anotherProperty
'def'

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

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

> var obj = { 'not an identifier': 1, prop: 2 };
> Object.keys(obj)
[ 'not an identifier', 'prop' ]
> delete obj['not an identifier']
true
> Object.keys(obj)
[ '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:

> Object(null) instanceof Object
true > Object(false) instanceof Boolean
true > var obj = {};
> Object(obj) === obj
true

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

function isObject(value) {
return value === Object(value);
}

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

> var obj = {};
> new Object(obj) === obj
true > new Object(123) instanceof Number
true

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

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

一般函数'sloppy模式"下

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

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

this 被定义为 undefined:

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

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

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

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

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

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

var jane = {
name: 'Jane',
sayHelloTo: function (otherName) {
'use strict';
console.log(this.name+' says hello to '+otherName);
}
};

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

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

jane.sayHelloTo('Tarzan');

jane.sayHelloTo.call(jane, 'Tarzan');

var func = jane.sayHelloTo;
func.call(jane, 'Tarzan');

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

Function.prototype.apply(thisValue, argArray)

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

jane.sayHelloTo('Tarzan');

jane.sayHelloTo.apply(jane, ['Tarzan']);

var func = jane.sayHelloTo;
func.apply(jane, ['Tarzan']);

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

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

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

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

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

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

The following three invocations of sayHelloTo are all equivalent:

jane.sayHelloTo('Tarzan');

var func1 = jane.sayHelloTo.bind(jane);
func1('Tarzan'); var func2 = jane.sayHelloTo.bind(jane, 'Tarzan');
func2();

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

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

Step 1

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

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

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

Step 2

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

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

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

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

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

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

var obj = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
loop: function () {
'use strict';
this.friends.forEach(
function (friend) { // (1)
console.log(this.name+' knows '+friend); // (2)
}
);
}
};

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

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

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

Workaround 1: that = this

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

loop: function () {
'use strict';
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name+' knows '+friend);
});
}

结果为:

> obj.loop();
Jane knows Tarzan
Jane knows Cheeta

Workaround 2: bind()

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

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

Workaround 3: a thisValue for forEach()

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

loop: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' knows '+friend);
}, this);
}

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. #284 div.2 C.Crazy Town

    C. Crazy Town   Crazy Town is a plane on which there are n infinite line roads. Each road is defined ...

  2. android之TCP客户端框架

    一.程序框架 1.1 创建方法 onCreate 1.1.1 创建连接按键线程,并使能线程(触发原因:可按键.其他操作,并进行状态判断): Connect_Thread connect_Thread ...

  3. GitHub这么火,程序员你不学学吗? 超简单入门教程 干货

    本GitHub教程旨在能够帮助大家快速入门学习使用GitHub. 本文章由做全栈攻城狮-写代码也要读书,爱全栈,更爱生活.原创.如有转载,请注明出处. GitHub是什么? GitHub首先是个分布式 ...

  4. 安装Numpy和matplotlib

    (1)测试程序     这是我从网上(http://www.open-open.com/lib/view/open1393488232380.html)找到的一个使用Numpy和matplotlib的 ...

  5. HashMap使用

    /* * 测试HashMap的应用,判断 */ import java.util.HashMap; public class HuaWeiTest { private static final Int ...

  6. Java的基础概念

    JDK (Java Development Kit) Java Developer Kit contains tools needed to develop the Java programs, an ...

  7. iss 防火墙

    控制面板\系统和安全\Windows 防火墙\允许的程序 如下图 将万维网服务(HTTP)打勾即可访问你的网站. 转自:http://bbs.pcbeta.com/viewthread-604506- ...

  8. java集合_collection 中的方法 通过Arraylist来体现

    import java.util.*; /* Collection定义了集合框架的共性功能.1,添加    add(e);    addAll(collection); 2,删除    remove( ...

  9. Oracle PL/SQL 多重选择句

    Oracle中语句块的基本格式: declare --变量定义,初始化赋值. begin --变量的赋值,函数调用,if,while等. end: Oracle中的语句:关系运算符:= <> ...

  10. ThinkPHP3.2 加载过程(一)

    加载过程(官方介绍) : 用户URL请求 调用应用入口文件(通常是网站的index.php) 载入框架入口文件(ThinkPHP.php) 记录初始运行时间和内存开销 系统常量判断及定义 载入框架引导 ...