- 浏览: 221190 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (144)
- Python (6)
- Java (15)
- Project management (2)
- DB (11)
- Spring (1)
- Mobile (3)
- 互联网 (10)
- Maven (2)
- SCM (5)
- linux (24)
- Mac (14)
- UCD / UED (6)
- Tools (1)
- Test (1)
- iPhone (1)
- 新产品&新工具 (8)
- OAuth (4)
- Java Script (5)
- HTML5 (2)
- Lucene / Solr (7)
- nginx (1)
- Product Manager (1)
- Design (1)
- Office (1)
- RegExp (0)
- 性能调优 (2)
- 读书笔记 (2)
- NodeJs (2)
最新评论
-
410163269:
看不清楚 蛋疼
基于 OAuth 安全协议的 Java 应用编程 -
xufun:
路过,拜读学习了。谢谢!
未来的授权标准 -- OAuth 2.0 -
xufun:
好文!路过拜读了,谢谢!
NoSQL - CouchDB入门 -
mimicom:
牛b......
最牛B的 Linux Shell 命令(三) -
as3291363:
你有一些 中文資料嗎????
Java Script 代码生成器: CoffeeScript
本文首先对 JavaScript 的机制进行讲解,并结合当前流行的开源 JavaScript 框架讲解如何在 JavaScript 中实现面向对象和继承机制;之后本文将对面向对象 JavaScript 编程中容易引起误解和 Scope 的几个问题做详细阐述;最后针对面向对象的 JavaScript 编程中的 Scope 问题给出几点建议。 JavaScript 是一种弱类型解释运行的脚本语言,就语言本身来讲它不是一门面向对象语言。但是我们可以利用一些语言的特性来模拟面向对象编程和继承机制,这所有的一切都需要从 JavaScript 中的 function 说起。 Function 是一个定义一次但可以调用或执行无数次的 JavaScript 代码片段。Function 可以有零个或者多个输入参数和一个返回值,它通常被用来完成一些计算或者事务处理等任务。通常我们这样定义一个 function: 在 JavaScript 中,function 不仅是是一种语法结构,它还可以被作为数据。这意味着它可以被赋值给变量,在对象或数组中的元素的属性存储,或者作为函数参数传递等等。例如: 在 JavaScript 中,对象的创建通常是通过 当上面这条创建语句被执行时,首先会创建一个空的对象赋给前面的变量,然后再调用后面紧跟的 function,并将这个空的对象作为隐含参数传入到 function 内部。这样在 function 内部就可以通过 讲到这里我们已经有了对象、函数、作为数据的函数、对象方法和构造函数,于是我们可以使用这些 JavaScript 的特性模拟写出类似于 java 风格面向对象的代码。例如: 上面的代码似乎十分完美,但是看起来似乎还是缺少一些东西。面向对象的精髓是对事物的抽象和继承,以到达代码重用的目的。然而在 JavaScript 中如何做到这一点呢? 在 JavaScript 中每一个 object 都有一个 prototype 属性,这个属性引用了另一个 object 对象。当你需要读取一个 object 中的某个属性 p 时,JavaScript 引擎首先会查找这个 object 中是否存在属性 p。如果该属性存在则返回该属性值,如果该属性不存在则会在这个 object 的 prototype 对象中查找是否存在属性 p。这样做会有两点好处:第一,在每个类中可以抽象出来一些共有的属性和方法定义在 prototype 对象中。当使用构造函数创建多个类的实例时,多个实例使用同一 prototype 对象,这样大大减小了对内存的占用量。第二,新创建的对象的属性是在对象创建时,由 prototype 对象带来的,这样就可以实现属性和方法的继承了。 在前面对 function 的介绍中,我们曾提到当 讲到这里我们对如何在 JavaScript 中模拟面向对象编程有了清楚的了解。我们可以通过将一些共有的属性和方法定义在构造方法来实现属性的继承,例如, 另外如果需要继承另一个类并且重写和添加一些方法的时候,你可能就需要拷贝这个类的构造方法的 prototype 对象中的属性和方法,然后再根据需要重写和添加一些方法和属性了。 在前面一节中我们介绍了一些 JavaScript 基本的特性和如何利用这些特性模拟实现面向对象和继承。目前开源社区有众多流行的 JavaScript 类库,如 jQuery、Extjs、Dojo 等,他们各自也都对面向对象编程和继承等机制有着不同的支持。那么这些开源 JavaScript 是如何实现面向对象和继承机制的呢?接下来我们介绍一下这些开源框架是如何实现这些机制的。 通过上面的声明,可以得到一个名为“com.test.MyClass”的 Dojo 类,它继承自“com.ibm.MySuperClassOne”和“com.ibm.MySuperClassTwo”两个类。类型声明后,就可用如下代码获得一个类的实例。其与前文所述的创建对象的方式是一致的。 在 ExtJS 中,类型间的继承关系式通过 extend 这个函数来实现的,下面给出了 ExtJS 中声明类之间继承关系的方式。 或者 对于第二中继承声明方式,除了 SuperClass 事先已定义好之外,MyClass 也需要事先定义,而第一种则是由 extend 函数直接构造出类型,即是在声明类的同时建立了继承关系。由此可见,这两种 extend 的调用方式的使用场景是不同的。 那么 Dojo、ExtJS 等 JavaScript 库中的这种面向对象的继承是如何实现的呢?这就需要用到前文中提到的 JavaScript 语法中比较特殊的 prototype 的机制。由前文可知,prototye 是一个函数的内置属性,这个属性指向另一个对象的引用,在这个对象中定义的属性和方法将被这个函数经过 new 操作得到的对象共享。如果某个函数被视作 JavaScript 中的类型定义,那么这个函数的 prototype 对象的属性和方法将会被这个函数所代表的类的实例共享,也就是说 prototype 对象是这个类的的代表和载体。因此,利用 prototype 的特性,Dojo、ExtJS 等 JavaScript 类库模拟了面向对象的语言机制。而 Dojo 和 ExtJS 中的面向对象继承功能有一个很大的不同,就是 ExtJS 实现的是单继承,即一个子类只有一个父类,而 Dojo 实现了多继承,即一个子类可以有多个父类,这从上面给出的代码示例中可以看出。 在实现上,ExtJS 中每声明一个类,都会将这个类的方法、属性放到这个类的 prototype 中去,然后将这个类的 ptototype 对象的类型的 prototype 指向父类的 prototype 对象,如下图所示。 在上图中,可以清楚地看到 MyClass 的 prototype 的对象是一个临时生成的函数(类)实例化生成的,而这个临时的类的 prototype 指向了 SuperClass 的 prototpye 对象,于是根据 JavaScript 中 prototype 的传递特性,MyClass 的实例可以调用 MyClass 的 prototype 对象的方法,进而可以调用 MyClass 的 prototype 对象的类即图中的临时类的 prototype 对象中的方法,也是 SuperClass 的 prototype 对象的方法。这样便实现了 MyClass 与 SuperClass 之间的继承关系。 上面解释了 MyClass 和 SuperClass 的继承关系的,这是单继承的实现方式,若是有多个类之间的单继承,则可以通过上面的方式串成一个继承链,如下图所示。 ExtJS 只支持单继承,即一个子类最多有一个父类。而由于 Dojo 支持多继承,所以一个子类是允许有多个父类的。Dojo 首先会将多继承的关系通过某种算法转换为单继承链,在利用上面描述的 prototype 链的方式将单继承链实现。如下图所示。 Dojo 中使用的多继承转换算法叫做 C3 Method Resolution Order 是一种比较通用的算法。 除了实现继承关系,ExtJS、Dojo 等 JavaScript 库还为面向对象实现了一些其他的功能和机制,比如构造函数、父类函数调用等等,这在后续的相关文章中将会详细论述。 在面向对象的 JavaScript 编程中,我们包装继承了大量的对象,同时对象之间还有很多复杂的引用关系,这就使得很多时候我们在 function 调用时的 Scope 不是我们想要的 Scope。产生这些问题的原因最终都源于我们没有深入的了解 JavaScript 的机制。在下面的一节我们将就这些容易产生 Scope 问题的机制做一个简单的介绍,并给出一些如何避免 Scope 问题的建议。 很多程序员在使用 JavaScript 的时候都会对 function 的 Scope 运行范围和 Closure 闭包的使用很困惑,这都源于他们对 JavaScript 原理的不了解。 在 JavaScript 中 function 是作用于词法范围而不是动态运行范围。也就是说 function 的作用范围是它声明的范围,而不是它在执行时的范围。简单的来说,一个 function 执行时的上下文环境 Context 是在其定义的时候就固定下来了,就是它定义的时的作用范围。这点是我们需要注意的,很多时候我们动态的将某个方法注入到一个对象内部,然而在运行时总是得不到想要的上下文环境,这就是因为没有正确理解 JavaScript 的 Scope。 当一个 function 被 JavaScript 引擎调用执行时,这个 function 的 Scope 才起作用被加到 Scope 链中。然后将一个叫做 Call Object 调用对象或者运行对象加到 Scope 的最前面。这个调用对象初始化时会加入一个 arguments 属性,用来引用 function 调用时的参数。如果这个 function 显示的定义了调用参数的话,这些参数也会被加入到这个对象中。之后再这个函数运行中所有的局部变量也都将包含在这个对象中。这也就是在 function 体内部既可以通过 arguments 数组,又可以直接通过显示定义参数名来引用调用时传入参数的原因。需要注意的是,这个调用对象和通过 在 JavaScript 中允许定义匿名 function 和在 function 中嵌套定义另一个 function,由于 Scope 链的作用,function 的内部总是可以访问到外部的变量而外部不能访问到内部的变量。另外由于 Call Object 的机制,使得我们可以使用 function 嵌套定义和调用来做很多事情。在 JavaScript 中这样的调用被称为 Closure 闭包。 在 JavaScript 中提供了两个非常有意思的方法 call 和 apply,它使得你可以将一个 function 作为另一个 object 的对象方法来调用。也就是说你可以选择 function 调用时,传入给 这两个方法在面向对象的 JavaScript 编程中非常有用,有时你希望给某个对象添加一个事件监听,然而回调方法的 context 却不一定是你需要的。这时你就需要 call 或者 apply 方法了。 eval 方法用于执行某个字符串中的 JavaScript 脚本,并反回执行结果。它能够允许动态生成的变量、表达式、函数调用、语句段得到执行,使得 JavaScript 的程序的设计更为灵活,比如通过 Ajax 方式从服务器端获得代表 JavaScript 脚本的字符串,然后就可以用这发方法在浏览器端来执行这段脚本。因为传统的 Ajax 通讯设计更多的是在服务器端与浏览器端交换数据,但在这个方法的支持下就可以在两者之间交换逻辑(在 JDK1.6 支持在 JVM 中运行 JavaScript 脚本),所以这是一种很有趣很神奇的事情。 eval 用法很灵活也比较简单,调用时将要执行的 JavaScript 脚本字符串作为参数传给这个方法。比较常用的就是将服务器端发送过来的 json 字符串在浏览器端转化为 json 对象,如下面这个例子。 在上面的代码中,在 json 字符串又加上了一对括号,这样做可以迫使 eval 函数在评估 JavaScript 代码时强制将原最外层括号内的内容作为表达式来执行从而得到 json 对象,而非作为语句来执行。所以只有用新的小括号将原来的 json 字符串包起来才能够转换出所需的 json 对象。 对于执行一般的包含在字符串中的 JavaScript 语句,自然就不需要像上面那样再次添加括号,如下例所示。 上面的函数会在弹出的提示对话框中输出变量 m 的值。eval 函数的里面的语句只是一个简单的赋值,但有一个问题是值得注意的,就是 eval 中的语句是在什么样的 scope 中执行,为了更好的说明问题,执行下例中所示的代码。 可以得到,变量 m 所在的 scope 是在 testStatement 函数内,从 eval 调用的位置来看这个执行结果是合理的。接下来用 window.eval 替换清单 3 中的 eval 后,在 Firefox 上执行(注意是 Firefox),从执行后的结果中可以发现,这时的 m 的作用域变成了 window,也就是说 m 变成了一个全局变量。那么在 IE 下会如何呢,经测试发现,使用 window.eval 和使用 eval 在 IE 浏览器上是相同的结果,即 m 的作用域在 testStatement 函数中。但是 IE 浏览器提供了另外的一个方法 execScript,它会将输入的 JavaScript 脚本字符串放到全局作用域下执行。所以总结一下就是:eval 方法是将输入的代码在局部作用域下执行,若要实现 JavaScript 字符串中代码的全局作用域下执行的效果,或者把 eval 放到全作用域下调用,或者在 Firefox 下使用 window.eval,在 IE 下使用 execScript。 最后需要提醒的是,因为 eval 的执行效率较低,所以一般在程序中最好不要频繁使用。 本文首先介绍了 JavaScript 语言的一些特性并如何利用这些特性实现面向对象和继承机制;随后我们结合目前流行的开源 JavaScript 类库,讲解他们是如何实现面向对象和继承机制等特性的;之后我们对 JavaScript 面向对象编程中几个容易引起误解和 Scope 问题的要点,包括闭包、call 函数、apply 函数,eval 函数等做了详细的讲解;最后根据作者的开发经验给出几个如何处理 Scope 问题的建议供大家参考,希望对大家以后的开发工作有一定的帮助。 学习面向对象的 JavaScript 编程及其 Scope 处理
清单 1. Function 定义示例
function distance(x1, y1, x2, y2) {
var dx = x2 - x1;
var dy = y2 - y1;
return Math.sqrt(dx*dx + dy*dy);
}
清单 2. Function 作为数据示例
var d = distance;
d(1,1,2,2);
当在一个
object 中定义和调用一个 function 时,这个 function 被称作该 object 的一个方法。需要注意的是当这个 function 被调用时,这个 object 会以隐含参数的形式传入到 function 里,function 内部可以通过 this
关键字来引用这个 object 的属性。例如下面这个例子运行结果 calculator.result
的值为 2。
清单 3. This 关键字示例
var calculator = {
operand1: 1,
operand2: 1,
compute: function () {
this .result = this .operand1 + this .operand2;
}
};
calculator.compute();
alert(calculator.result);
new
运算符来完成的。new
关键字后面必须是一个可执行的 function。例如:
清单 4. New 关键字示例
var array = new Array(10);
var today = new Date( );
this
关键字引用该对象,做一些对象初始化工作。这样的一个 function 通常被称为构造方法或者简单构造方法。例如:
清单 5. 构造方法示例
function Rectangle(w, h) {
this .width = w;
this .height = h;
}
var rect1 = new Rectangle(2, 4);
清单 6. 模拟面向对象示例
function Rectangle(w, h) {
this .width = w;
this .height = h;
this .area = function (){
return
this .width*this .height;
};
}
var rect1 = new Rectangle(2, 4);
rect1.area();
new
操作符被调用时,它会创建一个空的对象赋给变量并且调用后面的构造函数。实际上在 new
操作符创建一个空对象后,它还会为这个对象设置它的 prototype
属性,这个属性值等于它的构造函数的 prototype 属性值
。所有的函数在其定义时就已经自动创建和初始化好了 prototype 属性。这个初始化好的 prototype 属性指向一个只包含一个 constructor
属性的对象,并且这个 constructor 属性指向这个 function 自己。这就解释了为什么每一个 object 都会有一个 constructor 属性。如果你运行下面的代码,打印出一个名为 Object 的 function。
清单 7. Constructor 属性示例
var obj = new Object();
alert(obj.constructor);
清单 8. 模拟继承示例
function Rectangle(w, h) {
this .width = w;
this .height = h;
}
Rectangle.prototype.area = function () {
return
this .width * this .height;
};
清单 9. 在 Dojo 中声明一个类
dojo.declare('com.test.MyClass',[com.test.MySuperClassOne,com.test.MySuperClassTwo],{
myName: 'Shao Yu',
myMethod: function(){
return "I am Shao Yu";
}
});
清单 10. 获得 Dojo 类的实例
var myObj = new com.test.myClass();
清单 11. ExtJS 中的 extend 函数的使用
MyClass = Ext.extend(SuperClass, {/* 新加入的属性方法 */});
Ext.extend(MyClass, SuperClass, {/* 新加入的属性方法 */});
图 1. ExtJS 中类的 prototype 的结构关系
图 2. ExtJS 中的继承链
图 3. 多继承关系转换为单继承链
this
关键字引用的对象是两个概念。调用对象是 function 在运行时的 Scope,其中包含了 function 在运行时的全部参数和局部变量。通过 this
关键字引用的对象,是当 function 作为一个这个对象的方法运行时对这个对象的引用。如果这个 function 没有被定义在一个对象中时,传入给 this
的对象是全局对象,因此在这个 function 内部通过this
取到的变量就是全局定义的变量。例如下面代码运行结果应该弹出"Hello,I am Qin Jian":
清单 12. 闭包定义示例
var hello = "Hello,I am Shao Yu!";
function sayHello(){
var hello = "Hello, I am Qin Jian."
function anotherFun(){
alert(this .hello);
}
anotherFun();
}
sayHello();
清单 13. 用闭包生成唯一 ID
uniqueID = (function () {
var id = 0;
return
function () { return id++; };
})();
alert(uniqueID());// 显示结果 0
alert(uniqueID());// 显示结果 1
alert(uniqueID());// 显示结果 2
上面这段代码很清楚的说明了闭包做了件什么事情。当外层的
function被执行时,它的
Scope被加入到
Scope chain上,然后为它创建
call object 加入到 scope 中。之后又创建了局部变量 id 将它保存在该 function 的 call object 中。如果没有“return
function
() {
return
id++; };
”
这条语句的话,外层的 function 将要运行结束退出,同时他的 call object 会被释放,scope 会从 Scope chain 上移除。由于“return
function
() {
return
id++; };
”
这条语句创建了一个内部的 function,并将其引用返回给一个变量。这样内部 function 的 scope 会被添加到之前外部 function 的 scope 之下,使得在外部 function 运行结束后他的 scope 不能被撤销和释放。这样就是用外部 function 的 call object 保存了变量 id,并且除了内部的 function 以为没有别的程序能访问到这个变量。虽然看起来有些复杂和拗口,但是闭包确实是以项非常有用的功能,经常用来保存变量控制访问域等用途。例如下面这个例子:
清单 14. 利用 call object 和闭包保存数据
function makefunc(x) {
return
function () { return x; }
}
var a = [makefunc("I am Qin Jian"), makefunc("I am shao yu"), makefunc("I am xu ming")];
alert(a[0]());// 显示结果 I am Qin Jian
alert(a[1]());// 显示结果 I am shao yu
alert(a[2]());// 显示结果 I am xu ming
this
关键字的对象。这两个方法第一个参数是相同的,为你想要传入给 this
关键字的对象。不同之处是,call 方法直接将 function 参数列在后面,而 apply 方法是将所有 function 参数以一个数组的形式传入。例如下面这个例子:
清单 15. call apply 方法示例
Var fun = function (arg1,arg2){
//do anything you want here
}
fun.call(object, arg1, arg2);
fun.apply(object, [arg1, arg2]);
清单 16. eval 方法将 json 字符串转换为对象
var jsonString = "{'name':{'qinjian':'I am qinjian','shaoyu':'I am shaoyu'}}";
var jsonObject = eval("(" + jsonString + ")");
alert(jsonObject.name.qinjian)
清单 17. eval 方法执行包含在字符串中的 json 语句
function testStatement() {
eval("var m = 1");
alert(m);
}
testStatement();
清单 18. 测试 eval 中的 JavaScript 语句执行的 scope
function testStatement() {
eval("var m = 1");
alert(m);
}
testStatement();
alert(typeof m);
清单 19. 处理闭包中 scope 问题示例
...
switchAds : function (index){
var _this = this ;
dojo.fadeOut({
node : _this.adBack,
duration : 500,
onEnd:function (){
dojo.fadeIn({
node : _this.adBack,
duration : 500,
onEnd:function (){
_this.currentAd = index;
}
}).play();
}
}).play();
},
...
清单 20.Dojo 中传递 Scope 示例
dojo.connect(node, "onclick", this , this ._collapse);
发表评论
-
8个优秀的高质量图标搜索引擎
2011-04-13 14:56 691对于每个网站开发 ... -
HTTPS的七个误解(译文)
2011-02-16 13:15 876HTTPS的七个误解(译文 ... -
[转] 浅谈Heatmap
2011-01-10 10:53 934在自然界之中,蛇的眼睛有夜视功能,即便是茫茫黑夜,它也能轻而易 ... -
推荐一个在线集成IM - ebuddy
2010-08-19 15:48 1243这是一个集合 MSN,Yahoo 以及 AIM(AOL)的网络 ... -
推荐一个好用的UI草图设计工具 Balsamiq Mockups
2010-08-09 17:06 1971推荐一个好用的UI草图设计工具 Balsamiq Mockup ... -
如何使用Firefox打开QQ 空间和一些其他的顽固软件
2010-08-01 13:07 1572安装Firefox后,即使在软件或系统里确认Firefox为默 ... -
浅析HTTP协议
2009-10-20 16:44 793浅析 HTTP协议 HTTP协议是什么? 简单 ... -
SNS
2008-12-11 15:54 1901SNS 目录 第一章 什么 ... -
集成搜索引擎与元搜索引擎
2008-12-11 10:59 1739搜索引擎是开启网络知识殿堂的钥匙,获取知识信息的工具。随着网络 ...
相关推荐
### 面向对象的JavaScript编程及其Scope处理 #### 一、JavaScript的面向对象特性 JavaScript作为一种弱类型的脚本语言,虽然本质上不是一种面向对象的语言,但我们可以通过巧妙地利用其特性来实现面向对象编程...
javascript面向对象编程指南 2nd英文版,英文名:Object-Oriented JavaScript。 What you will learn from this book The basics of object-oriented programming, and how to apply it in the JavaScript ...
JavaScript的对象基础特性使其天生适合于实现面向对象编程,其中对象可以是字面量、数组、日期、数字、字符串等。 JavaScript提供了一系列内置对象,如Number、String、Boolean、Function、Object、Array等,这些...
面向对象编程(Object-Oriented Programming,OOP)是一种流行的编程范式,JavaScript作为一门面向对象的脚本语言,...通过这些基础知识,可以构建复杂的对象和构造函数,进一步学习和应用更高级的JavaScript编程技巧。
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现 深入理解JavaScript系列(19):求值策略 深入理解JavaScript系列(20):《你真懂JavaScript吗?》答案详解 深入理解JavaScript系列(21):S.O.L....
6. 面向对象编程(Chapter 6: Object-Oriented Programming):涵盖了JavaScript中的面向对象概念,包括对象创建、继承、原型链等。 7. 函数表达式(Chapter 7: Function Expressions):着重介绍了函数作为表达式...
深入理解JavaScript系列(18):面向对象编程之ECMAScript实现 深入理解JavaScript系列(19):求值策略 深入理解JavaScript系列(20):《你真懂JavaScript吗 》答案详解 深入理解JavaScript系列(21):S O L I...
接着,教程深入JavaScript的高级特性,如闭包(closures)、面向对象编程中的类(class)和继承(inheritance)、迭代器(iterable)和生成器(generator)、以及作用域(scope)。掌握这些概念对于深入理解...
less objects)、多态(Polymorphism)、布局表格(Laying out a table)、获取器和设置器(Getters and setters)、继承(Inheritance)、instanceof操作符(The instanceof operator)等面向对象编程的概念。...
从基本的数据类型到面向对象编程,再到异步处理,JavaScript提供了一套完整的工具集,让开发者能够构建功能强大的Web应用程序。对于初学者来说,理解这些基础知识并熟练掌握,是进入JavaScript世界的关键步骤。
介绍了JavaScript中的面向对象编程思想及实现方法。 - **封装**:通过对象来组织数据和行为。 - **继承**:使用原型链或ES6类实现继承。 - **多态**:不同对象对同一消息作出响应的能力。 #### 七、函数表达式...
函数在JS中扮演着非常重要的角色,它可以被视为面向对象编程中的“类”,用来创建对象实例。 #### 二、内置数据类型 内置数据类型是指由JS语言本身提供的预定义类型,这些类型提供了对基本数据类型的封装和扩展...
尽管JavaScript是基于原型的,但ES6引入了类的语法糖,使得面向对象编程更加直观。类、继承、构造函数和方法等概念是理解OOP的关键。 7. **箭头函数(Arrow Functions)** 箭头函数提供了一种更简洁的函数定义...
此外,还有对象(objects)和原型链(prototype chain),它们是JavaScript的核心特性,用于实现面向对象编程。 JavaScript API,全称为Application Programming Interface,是一组预定义的函数、对象和常量,让...
EMTP-RV软件包使用面向对象的编程模式,由EMTP-RV 核心数据处理引擎、EMTPWorks图形化编辑界面和ScopeView可视化数据处理程序三部分组成。 EMTP-RV的工程文件(Design)由支持无限嵌套层次的子电路(Subcircuit)...