关于javascript proto中的__proto__问题

保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
单击提交则表示您同意developerWorks
的条款和条件。 .
所有提交的信息确保安全。
developerWorks 社区:
我的概要信息
选择语言:
JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征。本文将回归面向对象本意,从对语言感悟的角度阐述为什么 JavaScript 是一门彻底的面向对象的语言,以及如何正确地使用这一特性。
, 软件工程师,
曾滢著,JavaScript 爱好者,在加入 IBM 之前,曾负责多项 Web Application 的开发。目前供职于 IBM CSTL,从事 SystemX Director 的相关研发工作。
前言当今 JavaScript 大行其道,各种应用对其依赖日深。web 程序员已逐渐习惯使用各种优秀的 JavaScript 框架快速开发 Web 应用,从而忽略了对原生 JavaScript 的学习和深入理解。所以,经常出现的情况是,很多做了多年 JS 开发的程序员对闭包、函数式编程、原型总是说不清道不明,即使使用了框架,其代码组织也非常糟糕。这都是对原生 JavaScript 语言特性理解不够的表现。要掌握好 JavaScript,首先一点是必须摒弃一些其他高级语言如 Java、C# 等类式面向对象思维的干扰,全面地从函数式语言的角度理解 JavaScript 原型式面向对象的特点。把握好这一点之后,才有可能进一步使用好这门语言。本文适合群体:使用过 JS 框架但对 JS 语言本质缺乏理解的程序员,具有 Java、C++ 等语言开发经验,准备学习并使用 JavaScript 的程序员,以及一直对 JavaScript 是否面向对象模棱两可,但希望知道真相的 JS 爱好者。重新认识面向对象为了说明 JavaScript 是一门彻底的面向对象的语言,首先有必要从面向对象的概念着手 , 探讨一下面向对象中的几个概念:一切事物皆对象对象具有封装和继承特性对象与对象之间使用消息通信,各自存在信息隐藏以这三点做为依据,C++ 是半面向对象半面向过程语言,因为,虽然他实现了类的封装、继承和多态,但存在非对象性质的全局函数和变量。Java、C# 是完全的面向对象语言,它们通过类的形式组织函数和变量,使之不能脱离对象存在。但这里函数本身是一个过程,只是依附在某个类上。然而,面向对象仅仅是一个概念或者编程思想而已,它不应该依赖于某个语言存在。比如 Java 采用面向对象思想构造其语言,它实现了类、继承、派生、多态、接口等机制。但是这些机制,只是实现面向对象编程的一种手段,而非必须。换言之,一门语言可以根据其自身特性选择合适的方式来实现面向对象。所以,由于大多数程序员首先学习或者使用的是类似 Java、C++ 等高级编译型语言(Java 虽然是半编译半解释,但一般做为编译型来讲解),因而先入为主地接受了“类”这个面向对象实现方式,从而在学习脚本语言的时候,习惯性地用类式面向对象语言中的概念来判断该语言是否是面向对象语言,或者是否具备面向对象特性。这也是阻碍程序员深入学习并掌握 JavaScript 的重要原因之一。实际上,JavaScript 语言是通过一种叫做 原型(prototype)的方式来实现面向对象编程的。下面就来讨论 基于类的(class-based)面向对象和 基于原型的 (prototype-based) 面向对象这两种方式在构造客观世界的方式上的差别。基于类的面向对象和基于原型的面向对象方式比较在基于类的面向对象方式中,对象(object)依靠 类(class)来产生。而在基于原型的面向对象方式中,对象(object)则是依靠 构造器(constructor)利用 原型(prototype)构造出来的。举个客观世界的例子来说明二种方式认知的差异。例如工厂造一辆车,一方面,工人必须参照一张工程图纸,设计规定这辆车应该如何制造。这里的工程图纸就好比是语言中的 类 (class),而车就是按照这个 类(class)制造出来的;另一方面,工人和机器 ( 相当于 constructor) 利用各种零部件如发动机,轮胎,方向盘 ( 相当于 prototype 的各个属性 ) 将汽车构造出来。事实上关于这两种方式谁更为彻底地表达了面向对象的思想,目前尚有争论。但笔者认为原型式面向对象是一种更为彻底的面向对象方式,理由如下:首先,客观世界中的对象的产生都是其它实物对象构造的结果,而抽象的“图纸”是不能产生“汽车”的,也就是说,类是一个抽象概念而并非实体,而对象的产生是一个实体的产生;其次,按照一切事物皆对象这个最基本的面向对象的法则来看,类 (class) 本身并不是一个对象,然而原型方式中的构造器 (constructor) 和原型 (prototype) 本身也是其他对象通过原型方式构造出来的对象。再次,在类式面向对象语言中,对象的状态 (state) 由对象实例 (instance) 所持有,对象的行为方法 (method) 则由声明该对象的类所持有,并且只有对象的结构和方法能够被继承;而在原型式面向对象语言中,对象的行为、状态都属于对象本身,并且能够一起被继承(),这也更贴近客观实际。最后,类式面向对象语言比如 Java,为了弥补无法使用面向过程语言中全局函数和变量的不便,允许在类中声明静态 (static) 属性和静态方法。而实际上,客观世界不存在所谓静态概念,因为一切事物皆对象!而在原型式面向对象语言中,除内建对象 (build-in object) 外,不允许全局对象、方法或者属性的存在,也没有静态概念。所有语言元素 (primitive) 必须依赖对象存在。但由于函数式语言的特点,语言元素所依赖的对象是随着运行时 (runtime) 上下文 (context) 变化而变化的,具体体现在 this 指针的变化。正是这种特点更贴近 “万物皆有所属,宇宙乃万物生存之根本”的自然观点。在 中 window 便类似与宇宙的概念。清单 1. 对象的上下文依赖 &script&
var str = "我是一个 String 对象 , 我声明在这里 , 但我不是独立存在的!"
var obj = { des: "我是一个 Object 对象 , 我声明在这里,我也不是独立存在的。" };
var fun = function() {
console.log( "我是一个 Function 对象!谁调用我,我属于谁:", this );
console.log( this === window );
// 打印 true
console.log( window.str === str );
// 打印 true
console.log( window.obj === obj );
// 打印 true
console.log( window.fun === fun );
// 打印 true
// 打印 我是一个 Function 对象!谁调用我,我属于谁:window
obj.fun();
// 打印 我是一个 Function 对象!谁调用我,我属于谁:obj
fun.apply(str);
// 打印 我是一个 Function 对象!谁调用我,我属于谁:str
&/script&在接受了面向对象存在一种叫做基于原型实现的方式的事实之后,下面我们就可以来深入探讨 ECMAScript 是如何依据这一方式构造自己的语言的。最基本的面向对象ECMAScript 是一门彻底的面向对象的编程语言(),JavaScript 是其中的一个变种 (variant)。它提供了 6 种基本数据类型,即 Boolean、Number、String、Null、Undefined、Object。为了实现面向对象,ECMAScript设计出了一种非常成功的数据结构 - JSON(JavaScript Object Notation), 这一经典结构已经可以脱离语言而成为一种广泛应用的数据交互格式 ()。应该说,具有基本数据类型和 JSON 构造语法的 ECMAScript 已经基本可以实现面向对象的编程了。开发者可以随意地用 字面式声明(literal notation)方式来构造一个对象,并对其不存在的属性直接赋值,或者用 delete 将属性删除 ( 注:JS 中的 delete 关键字用于删除对象属性,经常被误作为 C++ 中的 delete,而后者是用于释放不再使用的对象 ),如 。清单 2. 字面式 (literal notation) 对象声明 var person = {
name: “张三”,
gender: “男”,
eat: function( stuff ) {
alert( “我在吃” + stuff );
person.height = 176;
delete person[ “age” ];在实际开发过程中,大部分初学者或者对 JS 应用没有太高要求的开发者也基本上只用到 ECMAScript 定义的这一部分内容,就能满足基本的开发需求。然而,这样的代码复用性非常弱,与其他实现了继承、派生、多态等等的类式面向对象的强类型语言比较起来显得有些干瘪,不能满足复杂的 JS 应用开发。所以 ECMAScript 引入原型来解决对象继承问题。使用函数构造器构造对象除了 字面式声明(literal notation)方式之外,ECMAScript 允许通过 构造器(constructor)创建对象。每个构造器实际上是一个 函数(function) 对象, 该函数对象含有一个“prototype”属性用于实现 基于原型的继承(prototype-based inheritance)和 共享属性(shared properties)。对象可以由“new 关键字 + 构造器调用”的方式来创建,如 :清单 3. 使用构造器 (constructor) 创建对象 // 构造器 Person 本身是一个函数对象
function Person() {
// 此处可做一些初始化工作
// 它有一个名叫 prototype 的属性
Person.prototype = {
name: “张三”,
gender: “男”,
eat: function( stuff ) {
alert( “我在吃” + stuff );
// 使用 new 关键字构造对象
var p = new Person();由于早期 JavaScript 的发明者为了使这门语言与大名鼎鼎的 Java 拉上关系 ( 虽然现在大家知道二者是雷锋和雷锋塔的关系 ),使用了 new 关键字来限定构造器调用并创建对象,以使其在语法上跟 Java 创建对象的方式看上去类似。但需要指出的是,这两门语言的 new含义毫无关系,因为其对象构造的机理完全不同。也正是因为这里语法上的类似,众多习惯了类式面向对象语言中对象创建方式的程序员,难以透彻理解 JS 对象原型构造的方式,因为他们总是不明白在 JS 语言中,为什么“函数名可以作为类名”的现象。而实质上,JS 这里仅仅是借用了关键字 new,仅此而已;换句话说,ECMAScript 完全可以用其它 非new 表达式来用调用构造器创建对象。彻底理解原型链 (prototype chain)在 ECMAScript 中,每个由构造器创建的对象拥有一个指向构造器 prototype 属性值的 隐式引用(implicit reference),这个引用称之为 原型(prototype)。进一步,每个原型可以拥有指向自己原型的 隐式引用(即该原型的原型),如此下去,这就是所谓的 原型链(prototype chain)
()。在具体的语言实现中,每个对象都有一个 __proto__ 属性来实现对原型的 隐式引用。说明了这一点。清单 4. 对象的 __proto__ 属性和隐式引用 function Person( name ) {
this.name =
var p = new Person();
// 对象的隐式引用指向了构造器的 prototype 属性,所以此处打印 true
console.log( p.__proto__ === Person.prototype );
// 原型本身是一个 Object 对象,所以他的隐式引用指向了
// Object 构造器的 prototype 属性 , 故而打印 true
console.log( Person.prototype.__proto__ === Object.prototype );
// 构造器 Person 本身是一个函数对象,所以此处打印 true
console.log( Person.__proto__ === Function.prototype );有了 原型链,便可以定义一种所谓的 属性隐藏机制,并通过这种机制实现继承。ECMAScript 规定,当要给某个对象的属性赋值时,解释器会查找该对象原型链中第一个含有该属性的对象(注:原型本身就是一个对象,那么原型链即为一组对象的链。对象的原型链中的第一个对象是该对象本身)进行赋值。反之,如果要获取某个对象属性的值,解释器自然是返回该对象原型链中首先具有该属性的对象属性值。说名了这中隐藏机制:图 1. 原型链中的属性隐藏机制在图 1 中,object1-&prototype1-&prototype2 构成了 对象 object1 的原型链,根据上述属性隐藏机制,可以清楚地看到 prototype1 对象中的 property4 属性和 prototype2 对象中的 property3 属性皆被隐藏。理解了原型链,那么将非常容易理解 JS 中基于原型的继承实现原理, 是利用原型链实现继承的简单例子。清单 5. 利用原型链 Horse-&Mammal-&Animal 实现继承 // 声明 Animal 对象构造器
function Animal() {
// 将 Animal 的 prototype 属性指向一个对象,
// 亦可直接理解为指定 Animal 对象的原型
Animal.prototype = {
name: animal",
weight: 0,
eat: function() {
alert( "Animal is eating!" );
// 声明 Mammal 对象构造器
function Mammal() {
this.name = "mammal";
// 指定 Mammal 对象的原型为一个 Animal 对象。
// 实际上此处便是在创建 Mammal 对象和 Animal 对象之间的原型链
Mammal.prototype = new Animal();
// 声明 Horse 对象构造器
function Horse( height, weight ) {
this.name = "horse";
this.height =
this.weight =
// 将 Horse 对象的原型指定为一个 Mamal 对象,继续构建 Horse 与 Mammal 之间的原型链
Horse.prototype = new Mammal();
// 重新指定 eat 方法 , 此方法将覆盖从 Animal 原型继承过来的 eat 方法
Horse.prototype.eat = function() {
alert( "Horse is eating grass!" );
// 验证并理解原型链
var horse = new Horse( 100, 300 );
console.log( horse.__proto__ === Horse.prototype );
console.log( Horse.prototype.__proto__ === Mammal.prototype );
console.log( Mammal.prototype.__proto__ === Animal.prototype ); 中对象原型继承逻辑实现的关键在于 Horse.prototype = new Mammal() 和 Mammal.prototype = new Animal() 这两句代码。首先,等式右边的结果是构造出一个临时对象,然后将这个对象赋值给等式左边对象的 prototype 属性。也就是说将右边新建的对象作为左边对象的原型。读者可以将这两个等式替换到相应的程序清单 5 代码最后两行的等式中自行领悟。JavaScript 类式继承的实现方法从代码清单 5 可以看出,基于原型的继承方式,虽然实现了代码复用,但其行文松散且不够流畅,可阅读性差,不利于实现扩展和对源代码进行有效地组织管理。不得不承认,类式继承方式在语言实现上更具健壮性,且在构建可复用代码和组织架构程序方面具有明显的优势。这使得程序员们希望寻找到一种能够在 JavaScript 中以类式继承风格进行编码的方法途径。从抽象的角度来讲,既然类式继承和原型继承都是为实现面向对象而设计的,并且他们各自实现的载体语言在计算能力上是等价的 ( 因为图灵机的计算能力与 Lambda 演算的计算能力是等价的 ),那么能不能找到一种变换,使得原型式继承语言通过该变换实现具有类式继承编码的风格呢?目前一些主流的 JS 框架都提供了这种转换机制,也即类式声明方法,比如 Dojo.declare()、Ext.entend() 等等。用户使用这些框架,可以轻易而友好地组织自己的 JS 代码。其实,在众多框架出现之前,JavaScript 大师 Douglas Crockford 最早利用三个函数对 Function 对象进行扩展,实现了这种变换,关于它的实现细节可以()。此外还有由 Dean Edwards实现的著名的 Base.js()。值得一提的是,jQuery 之父 John Resig 在搏众家之长之后,用不到 30 行代码便实现了自己的 Simple Inheritance。使用其提供的 extend 方法声明类非常简单。是使用了 Simple Inheritance库实现类的声明的例子。其中最后一句打印输出语句是对 Simple Inheritance实现类式继承的最好说明。清单 6. 使用 Simple Inheritance 实现类式继承 // 声明 Person 类
var Person = Class.extend( {
_issleeping: true,
init: function( name ) {
this._name =
isSleeping: function() {
return this._
// 声明 Programmer 类,并继承 Person
var Programmer = Person.extend( {
init: function( name, issleeping ) {
// 调用父类构造函数
this._super( name );
// 设置自己的状态
this._issleeping =
var person = new Person( "张三" );
var diors = new Programmer( "张江男", false );
// 打印 true
console.log( person.isSleeping() );
// 打印 false
console.log( diors.isSleeping() );
// 此处全为 true,故打印 true
console.log( person instanceof Person && person instanceof Class
&& diors instanceof Programmer &&
diors instanceof Person && diors instanceof Class );如果您已对原型、函数构造器、闭包和基于上下文的 this 有了充分的理解,那么理解 Simple Inheritance 的实现原理也并非相当困难。从本质上讲,var Person = Class.extend(...)该语句中,左边的 Person 实际上是获得了由 Class 调用 extend 方法返回的一个构造器,也即一个 function 对象的引用。顺着这个思路,我们继续介绍 Simple Inheritance 是如何做到这一点,进而实现了由原型继承方式到类式继承方式的转换的。 是 Simple Inheritance 的源码及其附带注释。为了方便理解,用中文对代码逐行补充说明。图 2.Simple Inheritance 源码解析抛开代码第二部分,整体连贯地考察第一和第三部分会发现,extend 函数的根本目的就是要构造一个具有新原型属性的新构造器。我们不禁感叹 John Resig的大师手笔及其对 JS 语言本质把握的细腻程度。至于 John Resig是如何想到这样精妙的实现方法,感兴趣的读者可以阅读本文 (),其中有详细介绍关于最初设计 Simple Inheritance 的思维过程。JavaScript 私有成员实现到此为止,如果您任然对 JavaScript 面向对象持怀疑态度,那么这个怀疑一定是,JavaScript 没有实现面向对象中的信息隐藏,即私有和公有。与其他类式面向对象那样显式地声明私有公有成员的方式不同,JavaScript 的信息隐藏就是靠闭包实现的。见 :清单 7. 使用闭包实现信息隐藏 // 声明 User 构造器
function User( pwd ) {
// 定义私有属性
var password =
// 定义私有方法
function getPassword() {
// 返回了闭包中的 password
// 特权函数声明,用于该对象其他公有方法能通过该特权方法访问到私有成员
this.passwordService = function() {
return getPassword();
// 公有成员声明
User.prototype.checkPassword = function( pwd ) {
return this.passwordService() ===
// 验证隐藏性
var u = new User( "123456" );
// 打印 true
console.log( u.checkPassword( "123456" ) );
// 打印 undefined
console.log( u.password );
// 打印 true
console.log( typeof u.gePassword === "undefined" );JavaScript 必须依赖闭包实现信息隐藏,是由其函数式语言特性所决定的。本文不会对函数式语言和闭包这两个话题展开讨论,正如上文默认您理解 JavaScript 中基于上下文的 this 一样。关于 JavaScript 中实现信息隐藏,Douglas Crockford在《 Private members in JavaScript 》()一文中有更权威和详细的介绍。结束语JavaScript 被认为是世界上最受误解的编程语言,因为它身披 c 语言家族的外衣,表现的却是 LISP 风格的函数式语言特性;没有类,却实也彻底实现了面向对象。要对这门语言有透彻的理解,就必须扒开其 c 语言的外衣,从新回到函数式编程的角度,同时摒弃原有类的面向对象概念去学习领悟它。随着近些年来 Web 应用的普及和 JS 语言自身的长足发展,特别是后台 JS 引擎的出现 ( 如基于 V8 的 NodeJS 等 ),可以预见,原来只是作为玩具编写页面效果的 JS 将获得更广阔发展天地。这样的发展趋势,也对 JS 程序员提出了更高要求。只有彻底领悟了这门语言,才有可能在大型的 JS 项目中发挥她的威力。
参考资料 ,学习它,可以让你全面理解 JavaScript 的本质。
:jQuery 之父 John Resig 的鼎力之作。他不是一本介绍语法知识及相关入门的书。您可以在书中学习到现代 JavaScript 编程方法。
:学习它可以理解 JSON 的构造本质。
:John Resig 关于实现的简单 JS 继承的详细介绍,包含源码和思维过程及使用实例。
:这是 JS 大师 Douglas Crockford 写的一篇关于介绍 JavaScript 语言本质的文章。
:JS 大师 Dean Edwards 实现的 Base.js。
:这是一篇全面介绍如何使用 JavaScript 实现信息隐藏的文章。
:通过专门关于 Web 技术的文章和教程,扩展您在网站开发方面的技能。:这是有关 Ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 Ajax 的新信息都能在这里找到。,这是有关 Web 2.0 相关信息的一站式中心,包括大量 Web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 栏目,迅速了解 Web 2.0 的相关概念。查看 ,了解更多和 HTML5 相关的知识和动向。加入 。查看开发人员推动的博客、论坛、组和维基,并与其他 developerWorks 用户交流。
developerWorks: 登录
标有星(*)号的字段是必填字段。
保持登录。
单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件。
在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。
所有提交的信息确保安全。
选择您的昵称
当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。昵称长度在 3 至 31 个字符之间。
您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。
标有星(*)号的字段是必填字段。
(昵称长度在 3 至 31 个字符之间)
单击提交则表示您同意developerWorks 的条款和条件。 .
所有提交的信息确保安全。
IBM PureSystems(TM) 系列解决方案是一个专家集成系统
通过学习路线图系统掌握软件开发技能
软件下载、试用版及云计算
static.content.url=/developerworks/js/artrating/SITE_ID=10Zone=Web developmentArticleID=870827ArticleTitle=全面理解面向对象的 JavaScriptpublish-date=javascript中的__proto__, prototype和constructor -
- ITeye技术网站
博客分类:
1》__proto__
javascript中一切都是对象,每个对象都是基于原型对象创建的,每个对象中都有__proto__属性,这个属性指向的就是它基于的原型对象。
__proto__属性是系统(浏览器)自动给创建的,在对象被创建的时候自动指向基于的原型对象。
function Foo(){
var foo=new Foo();
foo.__proto__指向的就是Foo.prototype
因为Foo函数本身也是个对象,所以Foo.__proto__指向的是Function.prototype
Function.prototype本身也是对象,所以Function.prototype.__proto__指向的是Object.prototype
2》prototype
只有构造函数对象才有prototype属性,构造函数的作用是创建对象,创建对象的时候,它要知道这个对象基于哪个原型来创建,这个prototype指向的就是这个原型。
prototype属性也是系统(浏览器)给创建的,并指向创建对象时基于的原型。
注意不是构造函数本身基于的原型,本身基于的原型都是Function.prototype。
function Foo(){
//系统自动把Foo的prototype属性指向Foo.prototype
//所以,new Foo()的时候,就基于Foo.prototype来创建,
//foo.__proto__就是Foo.prototype
var foo=new Foo();
foo.__proto__和Foo.prototype指向的都是Foo.prototype。
自定义一个Foo构造函数的时候,系统默认会自动指定一个Foo.prototype原型对象,其实就是一个Object对象。
3》constructor
只有原型对象才有constructor属性,而且也是系统(浏览器)给创建的。前面说过构造函数对象的prototype属性会指向一个原型对象,那么这个原型对象中的constructor属性指向的就是这个构造函数。
constructor属性其实是给自定义对象使用的,自定义对象通过constructor属性就可以知道自己是用哪个构造函数new出来的。比如:
function Foo(){
var foo=new Foo();
alert(foo.constructor)
// function Foo(){}
// foo中没有constructor,foo访问的是它的原型Foo.prototype中的constructor属性。
一个对象被new出来以后,就可以知道自己的两方面事情:
1. 通过foo.__proto__,可以知道自己是基于哪个原型创建出来的,相当于自己的父类
2. 通过foo.constructor,可以知道自己是用哪个构造函数构造出来的相当于自己的类
blogzhoubo
浏览: 35511 次
来自: 大连
写的很好啊~~~
小蝶兒 写道这样子和直接放在head里有什么区别呐,还是没有解 ...
这样子和直接放在head里有什么区别呐,还是没有解决想要把&l ...
struts.xml:namespace不配置的话,相当于缺省 ...Javascript:有关对象
1.Javascirpt definitive guide 5ed chapter 9,10;
by infinte
by Crockford
1. "对象" 和 对象衍生关系
2. prototype object / 对象属性查找机制-原型链(__proto__)
3. instanceof / typeof
4. 对象的属性/方法,模拟OOP的类-实例的对象关系
5. js对象实例化
Javascript data Big
Picture(incomplete):
*-----&+-----------------+
*---&+--------------------+
*---------&+-----------------------------+
*--+-----&|Function
*-+---&|Function.prototype
|Function.prototype.prototype | &final&
|-----------------|
*-+---&|--------------------|
|-----------------------------|
| =|--&|prototype
|-------* |
| prototype
*------|costructor
|--&|__proto__
|-------* | *--| __proto__
*---|__proto__
*--+------|constructor(*)
|&--------+-+--| costructor
+-----------------+
+--------------------+
+-----------------------------+
*-----------------+-+----------------*
*-----------+-----------------*
|*---------------------------*
*------+---------------------------------------------------------*
*----------------*
+----------------+
*--------&+-------------------------+
+-----------------------------+
+-----------------------------+&final&
*-----++---&| Object
&final&| object
*--+---&|Rectangle
*--+-&|Rectangle.prototype
|----------------|
*---&|-------------------------|
|-----------------------------|
|-----------------------------|
|prototype
| __proto__ (-&null)
|prototype
*--|__proto__
|*----|__proto__
|&-------+----| constructor
|__proto__
|&-------|constructor
*-----|constructor(*)
*----|constructor
|toString()
+----------------+
| hasOwnProperty()
| propertyIsEnumerable()
+-----------------------------+
+-----------------------------+
| ........
+-------------------------+
+--object r2-----------+
+--object r1-----------+ |
+--object p------------+
&final& | object
+--object o------------+ |
|----------------------| |
| &final&| object
| __proto__
|-+-----------------*
|----------------------| |
*----------|constructor(*)
| __proto__
*--------| constructor(*)
+----------------------+
+----------------------+
1. "对象" 和 对象衍生关系
"douglas crockford: private member in
javascript:
JavaScript is fundamentally about objects. Arrays are objects.
Functions are objects. Objects are objects. So what are objects?
Objects are collections of name-value pairs. The names are strings,
and the values are strings, numbers, booleans, and objects
(including arrays and functions). Objects are usually implemented
as hashtables so values can be retrieved quickly."
对象是指一般意义上的对象,即有属性和行为的数据集合;
js中的数据,除primitive type外,都是对象.Function,function
instance,object,Object,instance of Built-in Object都是对象;是name-value
pair,对象的引用和对象本身。js的程序本身是一个嵌套在一起的对象结构。实现上是hash
table,即propertyname-value对的集合
js是即面向对象式的语言,也是函数式特性的语言。
js的函数调用,是对象之间发送消息,引用着函数的那个对象提供调用者的身份(函数对象中的this的值),而被引用着的函数对象(function
object)本身提供行为,而行为的结果是与提供给它的身份有关的。来看下面几个利用toString举例的例子。
Object.prototype和Function.prototype的toString方法;
Object.prototype.toString函数设计上是为了输出引用着它的对象的类型信息;Function.prototype.toString这个函数设计上为了输出引用着它的对象的定义函数。
eg: Function.prototype 对象的toString方法
//Function.prototype.toString 输出"引用该toString function的对象的"的"定义函数";
//Object.prototype.toString 输出"引用该toString function的对象"的"类型";
//"引用该toString function 的对象"即该函数内部的this
function Circle(r){this.radius =};
alert(Function.prototype) //function(){}
alert(Circle.toString()); //Constructor的toString的调用是沿着原型链访问调用Function.prototype.toString
alert(Function.prototype.toString.apply(Object)); //function Object(){[native code]};Object的定义函数是native code的;
alert(Function.prototype.toString.apply({})); //E
//输出对象的类型信息;
alert(Object.prototype.toString.apply(Function)); //[object Function]
var ss=Object.prototype.toS //用window.ss引用Object.prototype.toString所引用的这个系统内toString函数;
alert(ss()); //[object Window], this-&window, window引用的类型是W
alert(Object.prototype.toString()); //[object Object], this-&Object.prototype这个对象,这个对象的类型是Objec
使用不同的引用调用toString
//odd point?:
alert(Function.toString == Function.prototype.toString) //
alert(Function.hasOwnProperty("toString")); //
alert("toString" in Function) && alert(Function.prototype.hasOwnProperty("toString")); //
Function.toString(); // output: function Function() { [native code] }-&使用Function这个引用调用toString()
Function.prototype.toString() //output: function(){};-&使用Function.prototype这个引用调用
虽然调用了同一个toString方法,但是所使用引用不同,结果不同。Function.toString()的那次调用,依赖于js对象变量查找机制,
沿原型链找到toString
function,但是调用使用Function这个对象,相当于Function.prototype.toString.apply(Function)
依据Function.prototype.toString输出对象的定义函数的意义,输出了Function的定义函数,当然,这是interpretor中native
Function.prototype这个引用引用着的对象hasOwnProperty("toString"),它不必沿着原型链找到Object.prototype
那个对象中(见Big
picture),由于是Function.prototype这个对象引用着toString方法,toString输出这个对象定义函数,这个
Function.prototype是个空的函数function(){};
不管用什么引用去调用Function.prototype对象中的toString方法,该方法输出调用对象的函数定义.
以上几个例子也说明了,
picture表述的js数据中,有关的"只表达Object的instance的object对象",都没有函数式特征的一面,即它们没有定义函数;又或者可以理解为,它们都是final的,只有数据实例,它们不能够作为数据类型去定义其他子类对象。例如:
Function.prototype.prototype, {},
var o = new Object(); Object.prototype
用以上引用调用Function.prototype.toString会引发runtime error
//object是没有作为函数的一面的,object是final的,不用它作为数据类型去创建object
try{Function.toString.apply({})}catch(e){alert(e)}; -&type erro
引用MOF的观点描述js对象衍生关系:data - meta-data
picture2 : meta-data relationship of js data
+ ----------------*
| | ①is a meta
| |①is a meta
| v data of
| vdata of
*----intance
+---------------------*
| | ①
|| ①is a meta
| v is a meta
&--②
*----------------* |*------------Built-in Object
(Array / Date /Error RegExp etc)
②js new
|meta data
is a prototype
*----------------------&function
②new | |
js implementation/js
program中的对象衍生关系使用MOF的观点来描述,是data-metadata的关系,根据对象实例化的方法的不同,把它们分为①②
2类,将在"js对象实例化"讨论这两类实例化的方式;
① : A is a
meta dat of B , 该"实例化"过程是在js implementation中;数据是predefined的;
使用symbol①描述;
//Function 即是数据,又同时是数据类型:
//Function是meta-data of Object, meta-data of 声明的function, meta data of Array等built-in O
Object instanceof Function //
(function(){}) instanceof Function //
(funciton(){}) instanceof O //
Array instanceof Object //true
Array instanceof Function //
② : A is a
meta-data of B, 这类实例化过程是js keyword "new", new是在js program中;
使用symbol②描述:
eg:instanceof反映的是原型链的结构
(new Object()) instanceof Object
((new Array()) instanceof Array) && ([] instanceof Object) && alert("true") //
function Rectangle(){};
function PositionRectangle(l,t){this.left=l;this.top=t;};
var o = new Rectangle();
PositionRectangle.prototype =
o.constructor = PositionR
var p = new PositionRectangle(1,2);
(o instanceof Rectangle) && (o instanceof Object) && alert("true"); //true
(p instanceof PositionRectangle) && (p instanceof Rectangle) && (p instanceof Object) && alert(true); //true
//note:
o instanceof Function //
[] instanceof Function //
这根本上是由于对象原型链和prototype object的设计。
2.prototype object / 对象属性查找机制-原型链(__proto__)
原型链 prototype
chain:
在js对象中设置的internal reference(__proto__),
__proto__指向当前对象的父类对象的原型对象(prototype object);
原型对象(prototype
js中的对象,除object,都有各自对应的原型对象;原型对象的设计目的是为所属的那个对象提供类型的信息。对象的名字,只是个现象,原型对象的内容(具有什么方法,属性)才是这个对象成为这个对象的本质;和C++/Java等语言不同,
js是通过为对象设定一个另一个对象(prototype
object)来表达对象的有关类型的信息,并通过指向原型对象的原型链的查找行为来完成模拟经典OOP语言的类-实例这种对象继承层次关系的;这种原型继承的关系(原型对象/原型链查找)在所有js对象上都是一致的,而不是仅仅在Object-object/Costructor-object对象关系上;
原型链的设置 /
系统中的原型链:
经过了许多测试,我描述出了Big
picture中__proto__链,注意Object.prototype的__proto__是指向null,是原型链的根;
两类object对象的原型链
var o = new Object();
o.__proto__ -& Object. Object.prototype.__proto__ -&
var T = function(){};
var p = new T();
p.__proto__ -&T. T.prototype.__proto__ -&Object. Object.prototype.__proto__ -&
Function.__proto__ -&Function. Function.prototype.__proto__ -&Object.Object.prototype.__proto__ -&
function T(){};
T.__proto__ -&Function.prototype,后面一致;
原型链的设置是以下的结构:__proto__指向父类对象的prototype属性,父类对象的prototype属性引用着原型对象;prototype引用可以被赋值指向其他对象作为父类对象对应的原型对象;
*--&#----------------#
*----------------*
#----------------#
#----------------#
B.prototype
*-+--&| prototype
| *---| __proto__
#----------------#
#----------------#
#----------------#
*-----| __proto__
#----------------#
原型链的特殊性:
Object.prototype对象的原型链是指向null的;Function的原型链和Function.prototype指向同一个对象;
原型对象和子类对象的关系可以用isPrototypeOf判断,父类对象和子类对象关系可以用instanceof判断,本质上它们都是反映着原型链的关系:
eg: instanceof / isPrototypeOf
Function instanceof Function //true, Function.__proto__ == Function.protoype 1
Function instanceof Object // 2
Object instanceof Function //
{} instanceof Object
(new T()) instanceof T && (new T() instanceof Object) //
instanceof:
A instanceof B,是用A的__proto__原型链指向的对象和B.prototype对比(注意prototype
object表示这个所属对象的类型信息),说是则返回true
否则沿原型链所指的对象上溯,直到Object.prototype.__proto__-&null,若无匹配,则返回
这就是上例1,2,3的原因;
原型对象-&元类型的对象?
/ js对象系统中元类型对象的结构
原型对象的方法是这个对象作为这个类型应具备的行为和属性;因此原型对象更像是元类型对象用于定义对象的类型。js数据空间中存在若干个独立的object对象,它们作为诸如Function,Object等对象的原型对象;上图Big
picture中包括3类这种独立的对象:
Object.prototype,这个对象表达js面向对象式特性的有关信息;
Function.prototype,表达函数式特征的有关信息;Function.prototype的定义函数就是一个空函数,并且这个对象还有一个原型对象
Function.prototype.prototype,这个对象是object.同时注意Constructor(eg:T)都对应着T.prototype对象,每个
Constructor(function)都有自己的prototype对象,它们的关系是非clone,2者似乎没有关系,Function.prototype.prototype的目的
似乎仅是为了定义Function.prototype应具备的类型信息;
Constructor(eg
Rectangle)的原型对象(eg:Rectangle.prototype),这个对象的原型链是指向Object.prototype,它是一个object,对
Constructor new出来的object沿着原型链寻址,会比Object
new出来的object多一个层次,Constructor的prototype object中恰是为了
放置属于这个Constructor type的行为,同时它又是一个O
因此系统中这些原型对象,作为元类型对象它们之间也有一点简单的层次关系,metadata-data的关系,也是通过原型链描述的:
picture:元类型对象的结构:
[object Object]
#------------------#&------------------------------------*
*--&|Object.prototype
|__proto__-&(null) |
#------------------#
function(){}
[object Object]
[object Object]
#-------------------# | #-----------------------------#
#-------------------#
|Function.prototype | | |Function.prototype.prototype |
|T.prototype
*---| __proto__
| *-| __proto__
*--| __proto__
#-------------------#
#-----------------------------#
#-------------------#
通常override Constructor toString来
按自己的要求输出;
没有原型对象的对象:
object对象是没有prototype属性的,它是final的数据对象;js系统就没有提供类型信息的必要(设置prototype
object),object对象的含义只是实例;
Object.prototype对象也没有prototype属性,它本身是定义Object对象的类型信息的,它是个元类型。
&& 原型链的特殊性:
Object.prototype对象的原型链是指向null的;
Function的原型链和Function.prototype指向同一个对象;
js对象变量存取规则:
aObject: in
aObject-&aObject.__proto__,直到Object.prototype(Object.prototype.__proto__-&null)
aFunc : callobject -&parent
callobject ....
3.instanceof / typeof / hasOwnProperty / isPrototypeOf
instanceof
o instanceof C 的含义是:
把C.prototype对象和o.__proto__引用着的对象相比较,相等则返回true( -&C
is a instance of C), otherwise,
沿o.__proto__链上溯,直到__proto__引用为null(注意big picture中的prototype
chain的末端以及2当中的例子),在上溯过程中,若o的__proto__链上的某一个对象和C.prototype
相等,则返回true,否则直到o.__proto__链的末端
typeof:
对所有data,返回6类结果,包括 区分object/function.
4.对象的属性/方法,模拟OOP的类-实例的对象关系
原型对象的及原型链的设计/js对象存取规则,使得js可以模仿类-实例的对象间关系.但这不是仅仅局限于Object-object/Constructor-object原型链和js对象存取规则应用在全部js对象上,是更一般的规律;
jsdef5上分类instance property/Method|class
property/method对于对象来说都是一样的对象属性和方法。
picture: instance member/ class member /
privilege member postion:
*-------------------------------------&#######################
# Function.prototype
# __proto__
#######################
Constructor1
#-----------------------#&---+-*
| function Rectangle
|(Function typed)
|-----------------------|
function's prototype object
| ~prototype
|----+-+------&######################
Object.prototype
| ~__proto__
* -----&###########################
#(Object typed)
| @getUNIT
#--------------------#
# (Object-typed)
*-------# *$constructor
#-------------------------#
| ^privatemember
# ~__proto__
# costructor(ref)
inner function
# *$area()
# __proto__ (-&null)
#-----------------------#
# *$toString()
# toString()
# *superclass
# hasOwnProperty()
*--------------+----------------*
######################
# propertyIsEnumerable()
*----------------|-----------*
# ........
Constructor2
###########################
#-----------------------#
*--+----------+----&#--object r1-----------#
#--object r2-----------#
|PositionRectangle
|&--+--+------*
|(Function typed)
|(Rectangle typed)
|(Rectangle typed)
|-----------------------|
|----------------------|
|----------------------|
| ~prototype
*---+-----|constructor(inherited)|
|constructor(inherited)|
| ~__proto__
|~__proto__
| ~__proto__
| @getUNIT
| *left(r1 instance p) |
*--|%%service()
| ^privatemember
| *top(r2 instance p)
#----------------------#
inner function
*-----| %%service()
#-----------------------#
| *superclass
#----------------------#
* : instance property | instance method / public method
@ : class property / class method
%%: instance method | privilege method
*$: inherited property | public member | instance property /method
~ :internal property
^ : private member
综合了一下,把它们分为:instance member / class member /
note privilege method/instance
method,当某一个object作为另一个Constructor的原型对象时(原型继承),可以作为另一个子类
object的instance method(public method),怎么看待取决于相对位置; 注意,不是Class
property/method,Class member只能通过所属的Constructor的引用来调用;
instance member(property/method) 包括3类:
public member:
定义在Constructor的原型对象中,所有的object实例共享一份member,this用于区分具体的对象;
member:在Constructor中用this.priv_member形式定义,包括privilege
property/method, 特别是method,引用Constructor 的inner
存在privilege method定义的Constructor的new实例化过程,导致Constructor
callobject不被GC掉,并且object 的多个属性引用着相同的Co
privilege method对Constructor private member可以存取;
属于单个对象的instance member.引用着的function属于
Class member:
定义在Constructor上的属性/方法引用;Class member中不使用this指代window
global对象;
private member:
private member是Constructor的局部变量/局部函数,当private member被privilege
member引用时,则new object时会产生多个有关 private inner function
instance都共享引用着Constructor的callobject,当这些private
method通过外部引用被调用则产生多个 闭包共享引用着Costuctor callobject.
对象,作为name- 作为value,private
member的内存位置是位于Costructor的callobject中,instance member的value
位置对应在Global对象上;
function Outer(){
function inner(){
if (count&3) alert("ok")
else alert("& 3");
var that =
var count = 0;
this.p1 = function(){inner();} //can visit inner. "pivileged method"!
Outer.prototype.p2 = function(){inner();}; //Error,cant visit inner
//pulic member的变量访问作用域连中不包括Outer callobject
var o = new Outer();
catch(e){
5.js对象实例化
js中创建对象有4种手段:
object直接量;{a:1,b:"test",c:[1,"2",{"x":1}]};
内置函数:document.createE ActiveXObject();
function调用(callobject:一个无prototype的空函数对象,然后用Arguments对象初始化);
会设置被创建的对象的__proto__,指向父类的原型对象;
执行Constructor的过程,创建在Constructor中定义的对象属性;
月影给出的解释非常精辟:
new的过程等价于范式:new C &=& TC =
function(){}, TC.prototype =
C.prototype, o= new TC, C.apply(o, arguments);
用文字和伪代码解释,与构造器C构造过程等价的函数调用序列为:
1) 建立一个空的function模板TC var TC =
function(){}
2) 设这个模板TC的原型设为构造器C的原型 TC.prototype = C.prototype
3) 无参数构造TC的对象o var o = new TC();
4) 以o为this执行C的构造器 C.apply(o, arguments);
5) 得到的o和直接构造C的过程完全等价 o &=& new
step 2: 给TC的原型对象赋值为C的prototype
object,由于object表达某个对象的类型,含义即为,把TC设置为和C一样类型的对象;
step3: 设置o的原型链指向TC
function的而注意,new不会设置TC.prototype对象中的constructor,由与step2中已经设置
的C.prototype对象中constructor属性正确的指向了C,因此new
TC出的对象后,o.constructor仍是正确的指向C;
step4:
C.apply(o,arguments),执行Constructor定义的内容,诸如设置instance member等;
runtime时刻对象结构:
hash table(对象) + Costructor function callobject(optional);
对象的方法调用可以产生多个关于对象方法的闭包;
runtime js jsobject sturcture logic
*-----------------------*
*---------------------*
|jsobject(eg: object)
|Constructor Closure
| name-values hash table|
*-----------------------*
*---------------------*
*---object r+--------------*
*---call object-------*
*---|internal ref(__proto)--&
| private member:
w,h,local vars
| function Refs:
|name-value pairs:
*---------------------*
|width : 10;
|height : 20;
*--------------------------*
*---------*
*---------------*
*--&|prototype|
| object ||
*---------*
|[[scope chain]]|----*
*---------------*
quote:Winter's
flanagan在Jsdef5中的提出了原型继承和borrow某个类的method的方法。当一个对象具备了另一对像的属性和行为时,即可认为对象具备了另一个对象的本质。但是不支持js
的instanceof的判断。borrow方法实际上和winter的"类抄写/类冒充"基本一致。
6.1 引用型原型继承
function Parent(xa){
this.y = 10;
function Child(xa,za){
Parent.apply(this,arguments);
Child.prototype.super = P
Child.prototype = new Parent();
Child.prototype.constructor = C
var childobj = new Child(1,2);
alert(childobj instanceof Parent);
alert(childobj.x);
alert(childobj.hasOwnProperty("x"));
6.2 复制型原型继承 (by winter)
function Parent(){
this.x = 10;
function Child(){
var private_a = 15;
var ret = new Parent();
ret.y = 20;
ret.f1 = function(){aler(private_a);};
var childobj = new Child();
alert(childobj instanceof Parent);
alert(childobj instanceof Child);
alert(childobj);
alert(childobj.__proto__ == Child.prototype);
alert(childobj.__proto__ == Parent.prototype);
alert(Child.prototype.isPrototypeOf(childobj));
alert(Parent.prototype.isPrototypeOf(childobj));
alert(childobj.x + "," + childobj.y)
obj1 = new (function(){})();
Child.apply(obj1);
alert(obj1.f1.toString()); //error, see 元类继承eg2 for details
new Child()出来的object,用instanceof,是parent的实例,而不是instanceof Cnew
Child()的对Child() 函数的调用返回了private ret,Parent对象,使得var
childobj引用实际上是一个P因此childobj.__proto__
指向Parent.
6.3 类抄写 | 类冒充 |
function Parent(){
this.x = 10;
function Child(){
this.parent = new Parent(); //注意我们不在这里用Parent.prototype那个原型对象,因为原型对象的属性只是pulic member,
//不包括在父类Constructor用this.xxx创建的privilege member和第三类
for (var name in this.parent){
this[name] = this.parent[name];
delete this.
//既然是类抄写,就不做prototype object chaining的设置了,否则和普通原型继承几乎一样了,除了在Child Constructor中
//调用父类的Constructor(Constructor chaining)
//Child.prototype = new P
//Child.prototype.constructor = C
但是抄写无法让instanceof来正确汇报类与实例之间的关系,david
flanagan介绍的borrow方法可以判断一个Constructor
new的是否borrow了另一个对象的方法,如果一个object,a
borrow了另一个对象b的全部方法,那么可以认为a是b的子类对象,david提出这个更像java中是a实现了b的接口;有所不同的是,java的interface中不可有方法的实现,而js中随意,b中可以有具体方法的实现甚至可以出现专为实现某类通用方法的mixin
class(see jsdef5 chapter 9.7, GenericToString)
//david's provides method to check whether a object provides the same set of properties/function as certain Constructor
//provides
//return true if obj provides the C
provides(obj,constructor){
if (obj instanceof constructor)
if (typeof obj == "function") obj = obj. //如果出现比较两个Constructor的情形;
if (constructor == Array || constructor == Boolean || constructor == Date || constructor == Error ||
constructor == Function || constructor == Number || constructor == RegExp || constructor == String)
var proto = constructor.
for (var name in proto){
//check methods only
if (typeof proto[name] != "function")
if (!(name in obj))
//注意,在name in proto中循环比较obj[name]且name in obj,已经确定了两个函数的名称是一样的;
if (typeof obj[name] != "function")
if (obj[name].length != proto[name].length) //两个函数的参数定义不同;
这个provide方法就想instanceof方法一样,在类抄写中判断object和Constructor的关系;是否实现了某个Constructor的所有方法;
eg: 即引用型继承Circle,又抄写Comparable类的方法;
function Comparable( ) {}
pareTo = function(that) {
throw "pareTo( ) is abstract.
Don't invoke it!";
function Circle(r){
this.radius =
function ColoredCircle(r,c){
//抄写Comparable的方法;
this.interface1 = new Comparable();
for (var p in this.interface1){
if (typeof this.interface1[p] == "function") this[p] = this.interface1[p];
delete this.interface1;
this.superclass(r);
this.color =
ColoredCircle.prototype = new Circle();
ColoredCircle.prototype.constructor = ColoredC
var c1 = new ColoredCircle(2,"green");
var c2 = new ColoredCircle(5,"gray");
//compare 2 objects:
if ((c1.constructor == c2.constructor)&&(provides(c1,Comparable)))
c1.compareTo(c2);
Winter的类抄写/类冒充在david flanagan的讲述中基本按同一类,它们的分别只是是否在子类的Constructor
"类冒充"调用父类过程导致父类设置的对象属性在子类对象中被创建,"类抄写"本身则抄写了父类对象属性,而不去constructor
6.4 "元类继承"(by winter)
function Parent(string){
var child = new Function("this.x = 10;" + string);
var Child = new Parent("this.y = 20;");
var childobj = new Child();
alert(childobj.y);
元类继承:Parent中定义了部分子类的函数的内容,new
Parent(""),创建子类时添加子类对象的内容;new
Parent("...")返回了被动态构造出的(添加了子类的对象的内容)的Child function, 再一次的调用new
Child()则创建了Child Constructor的 这种模式下,实际上不存在"直接的""传统的"Parent
Constructor的定义,Parent这个函数只是返回一个子类Constructor的函数定义,并且在允许在子类Constructor被创建时(调用Parent
Constructor时)动态的添加子类对象的内容,所以Parent
constructor的作用更像一个类厂来返回真正的子类定义,子类对象的创建,则再次new Child()得到;注意new
Function的作用域链是戳向global window的;
和复制型原型继承相似,Constructor返回了函数内部的结构,又和new纠缠在一起;结合前面分析的new的过程,用下面的测试例子详细分析一下复制型原型继承和元类继承的情况;
返回/外部引用 /new
先分析复制型原型继承的情况:
function Parent(){
this.x = 10;
function Child(){
var a = 11;
var b = new Parent();
b.f1 = function(){alert(a);};
var childobj = new Child();
alert(childobj.f1.toString);
由于Constructor return一个private member(Parent-typed
object),childobj实际上是引用着这个单独的、在Child函数中被添加了一些实例属性的Parent typed
object对象;回顾new的范式,这里范式过程有了一点点改变,可以从下例反映出来;
function Parent(){ this.x = 10;}
function Child(){var a =11; var b = new P b.y = 20;
b.f1 = function(){alert(a)};
function T(){};
T.prototype = Child.
var childobj = new T();
//Child.apply(childobj); //①
childobj = Child.apply(childobj);
alert("x" in childobj);
alert(childobj.f1.toString());
如果按①处执行,在接下来alert测试中会发现,childobj没有x,f1等属性;虽然这和月影所说的范式过程一致,最后一步把
childobj当做Child的this传入apply方法,但是结果并没有得到正确的childobj.其原因因为:
T.prototype虽然指向着Child函数的那个prototype
但是和引用型原型继承不同的是,Child.prototype并没有连到一个 Paret对象object实例,new
T()得到childobj之后,当访问childobj的属性,对象属性查找机制找到T.prototype对象(即Child.prototype),
这只是一个普通的任何一个function被声明后都对应的默认的prototype object,从Big
picture上看,这个prototype object 只是an object of
Object,该对象的原型链指向Object.prototype.当然无法从childobj访问原属于Parent的那些instance
Child.apply(childobj),虽然在Child函数的调用时把childobj
object作为this的值,但是Child的内部并没有对this的操作,即 没有创建privilege
member(privilege
method/property),实际上这个childobj传入是没有实际作用的,仍旧执行了Child函数过程,
由于执行后没有外部引用,Child callobject可以被GC。
因此按①处的执行,childobj引用的只是一个T()生成的prototype
object为Child.prototype的空对象,没有Parent的那些属性和方法;
稍作一点改变,把Child.apply(childobj),执行后赋给childobj,这样childobj引用着在一个添加了实例属性的Parent
object,后面的 alert测试是正确的;
从这个例子的分析,发现一个问题, new创造一个object(hash name-value
pair),一个变量引用着这个hash结构的对象;Constructor的返回也可以把函数的内部结构返回给一个外部变量来引用,两者会否产生冲突?
答案是返回的函数内部结构会赋给外部引用,而不是hash结构的
1.function Meta(string){
var ins_Template = new Function("this.x;"+ string);
return ins_T
6.var func_ins = new Meta("this.y = 20; var a = 30; var inner = function(){alert(a)};");
7.var obj = new func_ins();
8.alert(typeof obj);
9.alert(obj.toString());
这儿obj是一个对inner
function的引用,而不是对新创建的object的引用,新创建的object,至少,按这种方式没法访问到了,可以被
GC.从这个例子也可以看出元类继承的灵活性,即子类对象的Constructor的内容,可以被动态添加,造成各个子类对象实例的不同;
动态?极限?
可不可以在line8处生成func_ins的function instance(系统中存在Meta
callobject,并且该callobject中存在function instance结构被
func_ins引用),是否可以在程序中修改该function
instance的内容,例如,new一个obj1是带有return的,引用着一个内部结构,
new第二个obj2是只带有this.xxx的privilege
member的,引用着一个思考了一下,这个问题实质是要在修改运行时刻才存在的 function
instance的表达函数内容的scriptObject或者source(反正是这么类似的一个结构,see 闭包 reference0
aimingoo),即需要在运行时刻修改函数的内容;这在至少在目前我所知的语言中还是不能实现的功能,这个是不能被允许的;
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 javascript中alert 的文章

 

随机推荐