`
footman265
  • 浏览: 114492 次
  • 性别: Icon_minigender_1
  • 来自: 宁波
社区版块
存档分类
最新评论

JavaScript对象模型-执行模型(笔记)

阅读更多

JavaScript对象模型-执行模型

数据类型
基本数据类型
基本数据类型是JS语言最底层的实现。
简单数值类型: 有Undefined, Null, Boolean, Number和String。注意,描述中的英文单词在这里仅指数据类型的名称,并不特指JS的全局对象Nan, Boolean, Number, String等,它们在概念上的区别是比较大的。

对象: 一个无序属性的集合,这些属性的值为简单数值类型、对象或者函数。同上,这里的对象并不特指全局对象Object。
函数: 函数是对象的一种,实现上内部属性[[Class]]值为"Function",表明它是函数类型,除了对象的内部属性方法外,还有[[Construct]]、[[Call]]、[[Scope]]等内部属性。函数作为函数调用与构造器(使用new关键字创建实例对象)的处理机制不一样(Function对象除外),内部方法[[Construct]]用于实现作为构造器的逻辑,方法[[Call]]实现作为函数调用的逻辑。同上,这里的函数并不特指全局对象Function。
函数在JS这个Prototype语言中可以看作是面向对象语言的类,可以用它来构造对象实例。既然函数可以看作是类,所以每一个函数可以看作是一种扩展数据类型。

内置数据类型(内置对象)
Function: 函数类型的用户接口。
Object: 对象类型的用户接口。
Boolean, Number, String: 分别为这三种简单数值类型的对象包装器,对象包装在概念上有点类似C#中的Box/Unbox。
Date, Array, RegExp: 可以把它们看作是几种内置的扩展数据类型。

首先,Function, Object, Boolean, Number, String, Date, Array, RegExp等都是JavaScript语言的内置对象,它们都可以看作是函数的派生类型,例如Number instanceof Function为true,Number instanceof Object为true。在这个意义上,可以将它们跟用户定义的函数等同看待。
其次,它们各自可以代表一种数据类型,由JS引擎用native code或内置的JS代码实现,是暴露给开发者对这些内置数据类型进行操作的接口。在这个意义上,它们都是一种抽象的概念,后面隐藏了具体的实现机制。
在每一个提到Number, Function等单词的地方,应该迅速的在思维中将它们实例化为上面的两种情况之一。

数据类型实现模型描述
    
Build-in *** data structure: 指JS内部用于实现***类型的数据结构,这些结构我们基本上无法直接操作。
Build-in *** object: 指JS内置的Number, String, Boolean等这些对象,这是JS将内部实现的数据类型暴露给开发者使用的接口。
Build-in *** constructor: 指JS内置的一些构造器,用来构造相应类型的对象实例。它们被包装成函数对象暴露出来,例如我们可以使用下面的方法访问到这些函数对象:

//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
//
access the build-in number constructor
var number = new Number(123);
var numConstructor1 = number.constructor; //or
var numConstructor2 = new Object(123).constructor;
//both numConstructor1 and numConstructor2 are the build-in Number constructor
numConstructor1 == numConstructor2 //result: true
//
access the build-in object constructor
var objConstructor1 = {}.constructor; //or
var objConstructor2 = new Object().constructor;
//both objConstructor1 and objConstructor2 are the build-in Object constructor
objConstructor1==objConstructor2 //result: true

具体实现上,上图中横向之间可能也存在关联,例如对于build-in data structure和constructor,Function、 Date、 Array、 RegExp等都可以继承Object的结构而实现,但这是具体实现相关的事情了。

关于简单数值类型的对象化
这是一个细微的地方,下面描述对于Boolean, String和Number这三种简单数值类型都适用,以Number为例说明。
JS规范要求: 使用var num1=123;这样的代码,直接返回基本数据类型,就是说返回的对象不是派生自Number和Object类型,用num1 instanceof Object测试为false;使用new关键字创建则返回Number类型,例如var num2=new Number(123); num2 instanceof Number为true。
将Number当作函数调用,返回结果会转换成简单数值类型。下面是测试代码:

//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
var num1 = new Number(123); //num1 derived from Number & Object
num1 instanceof Number //result: true
num1 instanceof Object //result: true
//convert the num1 from Number type to primitive type, so it's no longer an instance of Number or Object
num1 = Number(num1); 
num1 instanceof Number //result: false
num1 instanceof Object //result: false
var num2 = 123//num2 is a primitive type
num2 instanceof Number //result: false
num2 instanceof Object //result: false

虽然我们得到了一个简单数值类型,但它看起来仍然是一个JS Object对象,具有Object以及相应类型的所有属性和方法,使用上基本没有差别,唯一不同之处是instanceof的测试结果。

Prototype继承
Prototype

每个对象都有一个[[Prototype]]的内部属性它的值为null或者另外一个对象函数对象都有一个显示的prototype属性,它并不是内部[[Prototype]]属性。不同的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  //会去找"父类"的属性和方法,直到顶端
调用对象的方法跟访问属性搜索过程一样,因为方法的函数对象就是对象的一个属性值。
提示: 上面步骤中隐含了一个递归过程,步骤3中obj.__proto__是另外一个对象,同样将采用1, 2, 3这样的步骤来搜索propName属性。

例如下图所示,object1将具备属性prop1, prop2, prop3以及方法fn1, fn2, fn3。图中虚线箭头表示prototype链。
    
这就是基于Prototype的继承和共享。其中object1的方法fn2来自object2,概念上即object2重写了object3的方法fn2。
JavaScript对象应当都通过prototype链关联起来,最顶层是Object,即对象都派生自Object类型。

类似C++等面向对象语言用类(被抽象了的类型)来承载方法,用对象(实例化对象)承载属性,Prototype语言只用实例化的对象来承载方法和属性。本质区别是前者基于内存结构的描述来实现继承,后者基于具体的内存块实现。

对象创建过程
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();是使用用户定义的类型创建实例化对象。

new Fn(args)的创建过程如下(即函数对象的[[Construct]]方法处理逻辑,对象的创建过程)。另外函数对象本身的创建过程(指定义函数或者用Function创建一个函数对象等方式)虽然也使用了下面的处理逻辑,但有特殊的地方,后面再描述。
1. 创建一个build-in object对象obj并初始化
2. 如果Fn.prototype是Object类型,则将obj的内部[[Prototype]]设置为Fn.prototype,否则obj的[[Prototype]]将为其初始化值(即Object.prototype)

3. 将obj作为this,使用args参数调用Fn的内部[[Call]]方法
    3.1 内部[[Call]]方法创建当前执行上下文
    3.2 调用F的函数体
    3.3 销毁当前的执行上下文
    3.4 返回F函数体的返回值,如果F的函数体没有返回值则返回undefined
4. 如果[[Call]]的返回值是Object类型,则返回这个值,否则返回obj
注意步骤2中, prototype指对象显示的prototype属性,而[[Prototype]]则代表对象内部Prototype属性(隐式的)。
构成对象Prototype链的是内部隐式的[[Prototype]],而并非对象显示的prototype属性。显示的prototype只有在函数对象上才有意义,从上面的创建过程可以看到,函数的prototype被赋给派生对象隐式[[Prototype]]属性,这样根据Prototype规则,派生对象和函数的prototype对象之间才存在属性、方法的继承/共享关系。
//--创建对象时用内置prototype来产生继承效果,内置prototype被赋的值是函数对象的显式prototype,这个显式的prototype的值是什么?
用代码来做一些验证:

//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function fn(){}
//the value of implicit [[Prototype]] property of those objects derived from fn will be assigned to fn.prototype
fn.prototype={ attr1:"aaa", attr2:"bbb"};
var obj=new fn();
document.write(obj.attr1 
+ "<br />"); //result: aaa
document.write(obj.attr2 + "<br />"); //result: bbb
document.write(obj instanceof fn); //result: true
document.write("<br />");
//I change the prototype of fn here, so by the algorithm of Prototype the obj is no longer the instance of fn,
//
but this won't affect the obj and its [[Prototype]] property, and the obj still has attr1 and attr2 properties
fn.prototype={};   //修改了fn的显式prototype
document.write(obj.attr1 + "<br />"); //result: aaa
document.write(obj.attr2 + "<br />"); //result: bbb
document.write(obj instanceof fn); //result: false  //obj不是fn的实例

关于创建过程返回值的验证:

//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function fn(){
    
//according to step 4 described above, 
    //the new fn() operation will return the object { attr1: 111, attr2: 222 }, it's not an instance of fn!
    return { attr1: 111, attr2: 222 };
}
fn.prototype
={ attr1:"aaa", attr2:"bbb"};
var obj=new fn();
document.write(obj.attr1 
+ "<br />"); //result: 111
document.write(obj.attr2 + "<br />"); //result: 222
document.write(obj instanceof fn); //result: false


做个练习
经过上面的理解应,请写出下面这幅图的实现代码。图中CF是一个函数,Cfp是CF的prototype对象,cf1, cf2, cf3, cf4, cf5都是CF的实例对象。虚线箭头表示隐式Prototype关系,实线箭头表示显示prototype关系。
    

//创建新对象时,内置prototype被赋成[对象定义]的现式prototype,这个显式的prototype(cfp)到底是什么?为什么不给内置prototype赋[对象定义]得内置prototype?

供参考的实现方案:

//Passed in FF2.0, IE7, Opera9.25, Safari3.0.4
function CF(q1, q2){
    
this.q1=q1;
    
this.q2=q2;
}
CF.P1
="P1 in CF"; 
CF.P2
="P2 in CF";
function Cfp(){
    
this.CFP1="CFP1 in Cfp";
}
alert(CF.prototype);//result: [object Object]
CF.prototype
=new Cfp();
alert(CF.prototype)//result: [object Object]   //这是什么情况,不是应该是Cfp么...
var cf1=new CF("aaa""bbb");
document.write(cf1.CFP1 
+ "<br />"); //result: CFP1 in Cfp
document.write(cf1.q1 + "<br />"); //result: aaa
document.write(cf1.q2 + "<br />"); //result: bbb

//定义实例的类(cf,原来应为object)的父类被修改为cfp,所以cf的实例可以访问到新的父类cfp的属性(cfp1)

分享到:
评论

相关推荐

    JavaScript核心笔记

    JS的核心笔记,写给想打好JS基础的你!

    JavaScript笔记

    事件驱动:JavaScript的执行都是由事件引发 解释执行:先读到的先执行,后读到的会替代先读的 可以使用任何文本编辑工具编写 JavaScript 代码,然后由浏览器解释执行。 JavaScript常用于实现如下功能: |--控制...

    Javascript 备忘笔记

    知识点比较全面的javascript备忘笔记,特点有: 1、知识点全面,相应案例全 2、Javascript面向对象方面做了大量的研究 3、对内置对象的知识很全面 4、DOM模型的控制事例很多 5、Cookie技术和Ajax技术 6、收集常用的...

    CSS样式-JavaScript笔记.pdf

    1. 能够使用CSS的基本选择器选择元素 ...3. 能够说出盒子模型的属性 4. 能够说出JS中五种数据类型 5. 能够使用JS中常用的运算符 6. 能够使用JS中的流程控制语句 7. 能够在JS中定义命名函数和匿名函数

    JavaScript学习笔记

    JavaScript学习笔记 W3C文档对象模型node部分查询:http://www.w3schools.com/dom/dom_node.asp

    js笔记.docx

    JavaScript是一种描述性语言 也是一种基于对象(object)和事件驱动(Event Driven)的 并具有安全性能的脚本语言 JavaScript应用程序多要下载到浏览器的客户端执行从而减轻服务器负担  JavaScript主要用来在HTML...

    javascript学习基础笔记之DOM对象操作

    DOM文档对象模型是HTML和XML的应用程序接口(API),DOM将整个页面规划成由节点层次构成的文档。DOM对象给予开发者对HTML的访问权限,并且使开发者能将HTML作为XML文档来处理和查看。DOM对象是与语言无关的API,意味...

    java script听课笔记

    Javascript 输入网址 JS文件客户端保存 浏览器引擎执行Js 通过交互响应返回 Firefox插件-&gt;Filebug -&gt;fetwork ECMAscript核心、DOM文档对象模型、BOM浏览器对象类型 ECMaScript Javascript是面向对象

    JavaScript 核心参考教程 内置对象

    这个标准基于 JavaScript... 本系列教程旨在向大家分享本人当年学习Javascript的笔记和心得。本系列教程预计分五个部分。 第一部分:Javascript内置对象。 第二部分:浏览器对象。 第三部分:文档对象模型。 第四部分:

    谷歌师兄的leetcode刷题笔记-reading-notes:读书笔记

    问题域、对象文字、文档对象模型 域建模、表、函数、方法和对象 HTML 链接和 CSS 布局 表单、列表、表格、表单和事件 调试 图像、音频和视频 图表和画布元素 本地存储 变换、过渡和动画 谷歌从建立完美团队的努力...

    javascript入门笔记

    2、文档对象模型(Document Object Model) - DOM 允许让 JS 与 HTML 文档打交道 3、浏览器对象模型(Browser Object Model) - BOM 允许让 JS 与 浏览器进行交互 JS是一款基于对象的编程语言 2、JS的基础语法 1...

    [removed]JavaScript基础笔记

    一个完整JavaScript由ECMAScript(核心),DOM(文档对象模型),BOM(浏览器对象模型); 文档对象模型(DOM):是针对XML但经过扩展HTML的应用程序编程接口(API,应用程序编程接口)。DOM将整个页面映射为一个多层...

    Javascript 面向对象编程(一) 封装

    因为Javascript的Object模型很独特,和其他语言都不一样,初学者不容易掌握。 下面就是我的学习笔记,希望对大家学习这个部分有所帮助。我主要参考了以下两本书籍: 《面向对象的Javascript》(Object-Oriented ...

    JavaScript高级程序设计学习笔记(一)

    2、文档对象模型(DOM),提供访问和操作网页内容的方法和接口。 3、浏览器对象模型(BOM),提供与浏览器交互的方法和接口。 第二章 script标签 延迟脚本:定义defer属性,表明脚本在执行时不会影响页面的构造,也...

    Ruby学习笔记

    对象模型比起JavaScript好的不是一点两点,clone关键字真是为原型式编程量身打造的,new就显得不伦不类了,尤其是我从Java开始的。恩,废话就少提,下面我学习Ruby的各个部分。其中Ruby风格这一部分是开放的,因为我...

    千峰python课件笔记+源码 (凯哥)

    2、Django中的模型 3、Django中的视图 4、Django中的模板 5、Django的高级使用 6、Django爱鲜蜂项目第一天 7、Django爱鲜蜂项目第二天 8、Django爱鲜蜂项目第三天 9、Git的使用 第四章 Tornado 1、走通Tornado基础...

    javascript从入门到跑路—–小文的js学习笔记(8)—–bom的对象及其用法—window 、History、location、navigator 、screen

     ECMAScript是 JavaScript的核心,但是在 Web中使用的 JavaScript, BOM (浏览器对象模型)才是真正的核心。BOM 提供了很多对象,用于访问浏览器的功能,但这些功能与任何网页内容无关。 二、window 对象下的属性...

    JavaScript 学习笔记之基础中的基础

    ECMAScript(核心) DOM(文档对象模型) BOM(浏览器对象模型) 1.1ECMAScript  ECMAScript是通过ECMA-262标准化的脚本语言,ECMA-262规定语言的:语法、类型、语句、关键字、保留字、操作符、对象 1.2 DOM  ...

    javascript基础语法学习笔记

     [2]DOM文档对象模型,提供访问和操作网页内容的方法的接口  [3]BOM浏览器对象模型,提供与浏览器交互的方法的接口  二、引入  引入javascript有两种办法:在页面内嵌入js代码和引入外部文件  [1]页面内嵌入 ...

Global site tag (gtag.js) - Google Analytics