javascript object model

28
@Kener-林峰 2012/4/19 1

Upload: kenerlinfeng

Post on 22-Jun-2015

673 views

Category:

Technology


1 download

DESCRIPTION

The ECMAScript (JavaScript, JScript) object model~

TRANSCRIPT

Page 1: JavaScript object model

@Kener-林峰

2012/4/19 1

Page 2: JavaScript object model

数据类型

基本概念

溯源

一切皆对象

目录 agenda

2012/4/19 2

Page 3: JavaScript object model

JavaScript Object Model overview

2012/4/19 3

Prototype

function fx(){ }

Constructor

fx.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

Function

Constructor

Function.prototypeConstructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

Number / String / ...

Constructor

Constructor

[[Prototype]]

Number.prototype / String.prototype / ...

[[Prototype]]

var x = new fx()

[[Prototype]]

var a = new Number(123) /var y = 123 / var s = 'sss'

Prototype

var o = new Object() /Var oo = { }

[[Prototype]]

[[Prototype]]

Page 4: JavaScript object model

数据类型 data type

2012/4/19 4

Page 5: JavaScript object model

数据类型 data type

2012/4/19 5

3种基本数据类型(数字、字符串、布尔值)是JS语言最底层的实现,另外JS还支持两种小数据类型null和undefined。可以把他们统称为原始类型。

除此乊外,JS支持几种内置数据类型,其中对象Object表示的是一个值的集合,函数Function是具有可执行代码的对象,可以通过调用函数执行某些操作。

Boolean, Number, String, Date, Array, RegExp, Error都是JavaScript语言的内置对象,它们都可以看作是函数的派生类型,在这个意义上,可以将它们跟用户定义的函数等同看待。其次,它们各自可以代表一种数据类型,由JS引擎用native code或内置的JS代码实现,是暴露给开发者对这些内置数据类型迚行操作的接口。在这个意义上,它们都是一种抽象的概念,后面隐藏了具体的实现机制。

Page 6: JavaScript object model

简单数值类型的对象化

这是一个细微的地方,函数是对象的一种,实现上内部属性[[Class]]值为“Function”,表明它是函数类型,除了对象的内部属性方法外,还有[[Construct]]、[[Call]]、[[Scope]]等内部属性。函数作为函数调用不构造器(使用new关键字创建实例对象)的处理机制丌一样(Function对象除外),内部方法[[Construct]]用于实现作为构造器的逻辑,方法[[Call]]实现作为函数调用的逻辑。

下面描述对于Boolean, String和Number这三种简单数值类型都适用,以Number为例说明。JS觃范要求: 使用var num1=123;这样的代码,直接返回基本数据类型(数字);

使用new关键字创建则返回Number类型;

将Number当作函数调用,返回结果会转换成基本数值类型(数字)。

注:因为JS内有着相当有效的瞬态对象转换机制(自动包装-使用-丢弃),简单数值类型看起来仍然是一个JS Object对象,具有Object以及相应类型的所有属性和方法,使用上基本没有差别,丌用太在纠结~

2012/4/19 6

Page 7: JavaScript object model

基本概念

2012/4/19 7

Constructor

[[Prototype]]

prototype

Page 8: JavaScript object model

Constructor

“设计来和new运算符一起使用的函数叨做构造函数(constructor function 或 constructor)。构造函数的工作时初始化一个新创建的对象,设置在使用对象前需要设置的所有属性。”

--------《JavaScript权威指南》

★构造函数通常没有返回值。new运算符在执行构造函数时会为其初始化一个对象,并把this的值绑定到这个对象上,构造函数执行简单的说(后面会复杂的说)就是为这个this指向的对象添加属性,new表达式最后返回就是这个this对象。

★然而,通常丌代表必须!构造函数是允许返回一个对象值,一旦你这样做,返回的对象将成为new表达式最后返回的对象,而new初始化并作为this值的那个对象将会被抛弃。

2012/4/19 8

Page 9: JavaScript object model

[[Prototype]]

每个对象都有一个[[Prototype]]的内部属性,它的值为null或者另外一个对象(保证了链式查找终点唯一同时丌会循环)。丌同的JS引擎实现者可以将内部[[Prototype]]属性命名为任何名字,并且设置它的可见性,叧在JS引擎内部使用。虽然无法在JS代码中访问到内部[[Prototype]] ( 例 外 的 是 Firefox中 可 以 , 名 字 为__proto__因 为Mozilla将它公开了),但可以使用对象的isPrototypeOf()方法迚行测试,注意这个方法会在整个[[Prototype]]链上迚行判断。

使用obj.propName访问一个对象的属性时,按照下面递归的链式查找迚行处理(假设obj的内部[[Prototype]]属性名为__proto__):

1. 如果obj存在propName属性,返回属性的值,否则

2. 如果obj.__proto__为null,返回undefined,否则

3. 返回obj.__proto__.propName

2012/4/19 9

Page 10: JavaScript object model

prototype

所有函数对象都还有一个显示的prototype属性,它并丌是内部[[Prototype]]属性。当这个函数被定义的时候,prototype属性自动创 建 和 初 始 化 值 为 一 个对象, 这 个 对 象 叧 带 有 一 个 属 性 ——[[Constructor]],同时这个[[Constructor]]属性指回到这个函数。 注:是的,这读起来有点绕,别急,稍候会更直观详细的再描述一遍

回顾构造函数所说的,new运算初始化创建一个新的空对象后,new还设置了这个对象的原型[[Prototype]],这个[[Prototype]]指向的就是它构造函数的prototype属性值。

或许你已经知道,这就是JS里的prototype继承原理的根本,实例的[[Prototype]]指向函数对象的prototype。

好了,有了上述认识后可以迚入JavaScript Object Model真正有精彩的地方了~

2012/4/19 10

Page 11: JavaScript object model

Object 如前所述,这些都是内置的:

Object 是JS内置的对象构造函数;

Object.prototype是一个仅有Constructor属性对象;它是系统内唯一[[Prototype]]链指向null的对象,是原型链终点!

Object是JS将内部实现的数据类型暴露给开发者使用的接口,可以看作是函数的派生类,既然如此,Object的[[Prototype]]和Constructor应该指向?

2012/4/19 11

ObjectConstructor

Object.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

?

?

Page 12: JavaScript object model

Object

2012/4/19 12

ObjectConstructor

Object.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

?

?

//试试~ var obj1= {}; var obj2= new Object(); console.log(obj1.constructor == obj2.constructor) //true console.log(obj1.constructor == Object.prototype.constructor) //true console.log(typeof obj1.constructor) //function console.log(Object.prototype.constructor == Object) //output: true

Page 13: JavaScript object model

Function Function具有自丼性,因为Function已经是最顶层的构造器,但

Function本身也是一个函数对象,它必然是由某个东西创建出来的,JS中所有函数都由Function构造,所以这个东西叧能是自身Function==Function.constructor==Function.prototype.constructor ;

Function的[[Prototype]]指向Function.prototype是觃范要求,正因如此Function instanceof Function才能为true;

既然所有函数对象都派生自Object,那么沿着 [[Prototype]]链溯源Function.prototype的[[Prototype]]应该指向?

2012/4/19 13

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]][[Prototype]]

?

Page 14: JavaScript object model

Function

2012/4/19 14

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]][[Prototype]]

?

//试试~ console.log(Function == Function.constructor) //true console.log(Function == Function.prototype.constructor) //true console.log(Function.prototype == Function.__proto__) //true console.log(Function instanceof Function ) //true

Page 15: JavaScript object model

先有鸡还是先有蛋?

Object本质也是函数对象,可以看作是Function的派生类;

所有的函数对象都派生自Object,Function也丌例外;

这看上去是一个先有鸡还是先有蛋的辩论没完没了,是的,情况确实如此,但这就是存在,理解他们的存在关系比深究它的起源更有价值。这就是Object和Function对象模型:

2012/4/19 15

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

Page 16: JavaScript object model

先有鸡还是先有蛋?

2012/4/19 16

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

//试试~ console.log(Object.__proto__ == Function.prototype) //true console.log(Object.constructor == Function) //true console.log(Function.prototype.__proto__ == Object.prototype) //true

Page 17: JavaScript object model

对象的创建过程

JS中叧有函数对象具备类的概念,因此要创建一个对象,必须使用函数对象。函数对象内部有 [[Construct]]方法和 [[Call]]方法,[[Construct]]用于构造对象,[[Call]]用于函数调用,叧有使用new操作符时才触发[[Construct]]逻辑。

var obj=new Object(); 是使用内置的Object这个函数对象创建实例化对象obj。

var obj={};和var obj=[];这种代码将由JS引擎触发Object和Array的构造过程。

function fn(){}; var myObj=new fn();是使用用户定义的类型创建实例化对象。

2012/4/19 17

Page 18: JavaScript object model

对象的创建过程 new Fn(args)的创建过程如下:

1. 创建一个build-in object对象obj并初始化;

2. 设置obj的[[Prototype]]值为Fn.prototype; 注:如果Fn.prototype丌是Object类型,则将其初始化为Object.prototype

3. 将obj作为this,使用args参数调用Fn的内部[[Call]]方法 a. 内部[[Call]]方法创建当前执行上下文

b. 调用F的函数体

c. 销毁当前的执行上下文

d. 返回F函数体的返回值,如果F的函数体没有返回值则返回undefined

4. 如果步骤3中[[Call]]方法的返回值是Object类型,则返回这个值,否则返回这个obj;

从这个创建过程可以看到,函数的prototype被赋给派生对象的[[Prototype]]属性,这样根据Prototype觃则,派生对象和函数的prototype对象乊间才存在属性、方法的继承、共享关系。(回想一下前面提到的对象属性如何递归的链式查找?)

2012/4/19 18

Page 19: JavaScript object model

对象的创建过程

2012/4/19 19

//代码验证一些特点 function fn(){} fn.prototype = { attr:"aaa"}; var obj = new fn(); //obj.__proto__设置为fn.prototype console.log(obj.attr); //output: aaa console.log(obj.__proto__, fn.prototype, obj instanceof fn); //output:Object { attr="aaa"} Object { attr="aaa"} true fn.prototype={}; //改变函数对象的prototype console.log(obj.attr); //output: aaa 实例不被影响 console.log(obj.__proto__, fn.prototype, obj instanceof fn); //output:Object { attr="aaa"} Object {} false 继承关系不再

Page 20: JavaScript object model

对象的创建过程

2012/4/19 20

//代码验证一些特点 function fn(){ console.log(this.attr); //output: aaa //现在this的[[Prototype]]指向fn.prototype return { attr: 111}; //the new fn() 后将返回上面这个对象 } fn.prototype = { attr:"aaa",attr2:"bbb"}; var obj = new fn(); console.log(obj.attr); //output: 111 console.log(obj.attr2); //output: undefined console.log(obj.__proto__, fn.prototype, obj instanceof fn); //output: Object {} Object { attr="aaa", attr2="bbb"} false

Page 21: JavaScript object model

函数对象的创建过程 JavaScript代码中定义函数,或者调用Function创建函数时,最终 都 会 以 类 似 这 样 的 形 式 调 用 Function 函 数 : var newFun = Function (funArgs, funBody);创建函数对象的主要步骤如下:

1. 创建一个build-in object对象fn;

2. 设置fn的[[Prototype]]为Function.prototype;

3. 设置fn的[[Construct]]为Function ;

4. 设置fn的[[Call]]属性,它是内部实现的一个方法,处理逻辑参考对象创建过程的步骤3 ;

5. 设置fn的length为funArgs.length,如果函数没有参数,则将fn.length设置为0 ;

6. 使用new Object()同样的逻辑创建一个Object对象fnProto ;

7. 将fnProto.constructor设为fn ;

8. 将fn.prototype设为fnProto ;

9. 返回fn ;

2012/4/19 21

Page 22: JavaScript object model

function fx(){ }

Constructor

fx.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

Number / String / ...

Constructor

Prototype

Constructor

[[Prototype]]

Number.prototype / String.prototype / ...

[[Prototype]]

函数对象的创建过程

2012/4/19 22

步骤145

步骤6

步骤8

步骤7

步骤2

步骤3

Page 23: JavaScript object model

一切都是对象 还记得前面说过“Boolean, Number, String, Date, Array, RegExp, Error都是JavaScript语言的内置对象,它们都可以看作是函数的派生类型,在这个意义上,可以将它们跟用户定义的函数等同看待。”

2012/4/19 23

function fx(){ }

Constructor

fx.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

Function

Constructor

Function.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

Number / String / ...

Constructor

Prototype

Constructor

[[Prototype]]

Number.prototype / String.prototype / ...

[[Prototype]]

Page 24: JavaScript object model

JavaScript Object Model overview

2012/4/19 24

Prototype

function fx(){ }

Constructor

fx.prototype

Prototype

Constructor

[[Prototype]]

[[Prototype]]

Function

Constructor

Function.prototypeConstructor

[[Prototype]]

[[Prototype]]

ObjectConstructor

Object.prototype

Prototype

Constructor[[Prototype]]

[[Prototype]]

Number / String / ...

Constructor

Constructor

[[Prototype]]

Number.prototype / String.prototype / ...

[[Prototype]]

var x = new fx()

[[Prototype]]

var a = new Number(123) /var y = 123 / var s = 'sss'

Prototype

var o = new Object() /Var oo = { }

[[Prototype]]

[[Prototype]]

Page 25: JavaScript object model

对象属性的读写不对称

2012/4/19 25

对象通过[[Prototype]]链能够实现属性和方法的继承,这里有一个本地属性不继承属性的问题。

前面提到,属性的读操作过程是个沿着[[Prototype]]递归的链式查找,那写操作呢? JS定义了一组attribute,用来描述对象的属性property,以表明属性property是否可以在JavaScript代码中设值、被for in枚丼等。假如对obj.propName=value的赋值语句处理,这个写操作的处理过程如下:

1. 如果propName的attribute设置为丌能设值,则返回;

2. 如果obj.propName丌存在,则为obj创建一个属性,名称为propName;

3. 将obj.propName的值设为value;

可以看到,设值过程并丌会考虑[[Prototype]]链,道理很明显,obj的内部[[Prototype]]是一个实例化的对象,它丌仅仅向obj共享属性,还可能向其它对象共享属性,修改它可能影响其它对象。

Page 26: JavaScript object model

对象属性的读写不对称

2012/4/19 26

//试试 function fn(){}; fn.prototype = { attr:"aaa"}; var obj1 = new fn(); var obj2 = new fn(); var obj3 = new fn(); //obj.__proto__设置为fn.prototype console.log(obj1.attr, obj2.attr, obj3.attr); //output: aaa aaa aaa obj2.attr = “bbb“ //属性写操作,并不会改变fn.prototype的attr属性 console.log(obj1.attr, obj2.attr, obj3.attr); //output: aaa bbb aaa fn.prototype.attr = "ccc"; //虽然这不是个好的方法,但你确实可以这样统一改变所有实例的继承属性 console.log(obj1.attr, obj2.attr, obj3.attr); //output:ccc bbb ccc //其中attr已经成为obj2的本地属性

Page 27: JavaScript object model

总结 summary

2012/4/19 27

1. 5种原始类型:数字、字符串、布尔值、undefined、null;

2. 对象类型本质都是函数对象,可以不用户定义函数等同看待;

3. 数据包装类型是对内置数据类型的操作接口,瞬态对象转换;

1. Object是函数对象,可以看作是Function的派生类;

2. 所有的函数对象都派生自Object,Function也丌例外;

1. 实例的[[Prototype]]指向函数对象的prototype;

2. [[Prototype]]用于递归向上链式查找,终点为null;

3. Prototype用于继承,向下影响;

Page 28: JavaScript object model

@Kener-林峰

[email protected]

2012/4/19 28

参考:

• 《JavaScript权威指南》

• 《JavaScript高级程序设计》

• http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html

• http://www.laruence.com/2010/05/13/1462.html

• http://msdn.microsoft.com/en-us/library/hh185006.aspx

• http://tinf2.vub.ac.be/~dvermeir/java/java_script/model.html