完全理解面向对象的Javascript(来自IBM)

今天,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语言是通过面向对象的程序设计来实现的,称为原型,然后讨论了基于类(基于类)、面向对象和基于原型的两种构建目标世界的方法之间的差异。

基于对象和原型的基于类的面向对象比较

在基于类的面向对象的方法,一个对象(object)是由类产生的(类)。在一个基于原型的面向对象方法中,对象(客体)是通过使用构造函数构造(构造函数)使用原型(原型)。对客观世界的一个例子来说明在认知的两方法的差异。例如,一辆汽车是在一个工厂。另一方面,工人必须按图纸指定的汽车应。这里是语言类的工程图纸(类),而汽车是用类一致(类)制成的;另一方面,工人和机器(相当于构造函数)使用各种部件如发动机、轮胎、转向轮(性能相当于原型)将被构造出来的车。

事实上,在这两种方式中,谁更明确地表达了面向对象的思想,目前仍存在争论,但我认为原型对象导向是一种更为彻底的面向对象的方法,其原因如下:

首先,客观世界中物体的产生是其他物体的结果,抽象的图纸不能产生汽车。也就是说,类是抽象概念而不是实体,对象的生成是实体的生成。

其次,根据事物中最基本的面向对象原理的对象,类(类)本身不是一个对象,而是构造函数(构造函数)和(原型)中的原型,原型本身是由其他对象构造成对象类型的。

再次,在面向对象语言中的类,对象的状态(状态)的对象实例(实例)认为,行为对象的方法(方法)是由对象的类声明举行的结构,只有对象的方法可以继承;并在原型对象语言对象的行为和状态,属于对象本身,并可以继承在一起(参见参考资料),这是更接近客观实际。

最后,类如java的面向对象语言,为了弥补全局函数和变量在面向过程语言的使用不便,让静态的静态属性和静态方法是在类中声明的。事实上,在客观世界中没有所谓的静态的概念,因为一切都是对象的。原型的面向对象语言,没有全局对象、方法或属性,或静态的概念,只有建立在对象。所有的语言元素(原始)必须依赖于对象的存在。然而,由于函数式语言的特性,在运行时上下文的变化而变化,是依赖于语言元素对象(背景),这是体现在这个指针的变化中,这个特征更接近于所有事物,宇宙是所有事物的基本存在的自然观点。在程序清单1中,窗口类似于宇宙的概念。

清单1的上下文相关性。对象

复制代码代码如下所示:

我是一个字符串对象,我在这里声明,但我不是独立的!
var obj = {德:我是一个对象,我在此声明,我不是独立存在的。};
var =函数(){()
console.log(我是一个函数对象!谁叫我,我属于谁:
};

obj.fun =乐趣;

console.log(=窗口); / /印真
console.log(window.str = str); / /印真
console.log(window.obj = obj); / /印真
console.log(window.fun =乐趣); / /印真
(有趣);打印i是一个函数对象!谁叫我,我属于谁
(obj。有趣); / /打印我的是一个函数对象!谁叫我,谁做我属于:obj
Fun.apply(STR); / /打印我的是一个函数对象!谁叫我,我属于谁




接受事实是这样的原型基于面向对象后,我们可以进一步探讨如何构建自己的语言ECMAscript这样。

最基本的面向对象

ECMAscript是一个完整的面向对象的编程语言(参考资源),Javascript是一个变种(变种),它提供了6种基本的数据类型,即布尔,数字,字符串,空的,不确定的对象。为了实现面向对象,ECMAscript设计了一个非常成功的数据结构——JSON(Javascript对象符号),这已经能够成为一种广泛应用的数据交互格式(参考资源)从语言。

应该说,基本的数据类型和JSON的构造函数语法ECMAscript基本上能实现面向对象编程,开发人员可以使用的文字样式表(文字符号)来构造一个对象,属性和直接分配上不存在,或使用删除属性删除(注:在JS关键词删除是删除对象的属性,常常被误认为是C++中删除,后者是用来释放对象不再使用的程序,如清单2所示)。

表2。字面(字面符号)对象声明

复制代码代码如下所示:
var
姓名:Zhang three,
年龄:26岁,
性别:男人,
吃:函数({){
警惕(我吃+东西);
}
};
person.height = 176;
删除人{ };


在实际开发过程中,大多数初学者或者JS的应用程序不要求很高的开发商,基本上只使用ECMAscript定义部分的内容,基本能满足发展的需要。然而,这样的代码的可重用性很弱。与其他类型的面向对象的语言相比,如继承、派生、多态性等,这是相当枯燥的,不能满足复杂的js应用发展的需要。所以ECMAscript介绍原型解决继承问题。


使用函数构造函数构造对象

除了字面上的声明(文字符号)模式,ECMAscript允许对象的创建通过构造函数(构造函数)。每个构造函数是一个函数(函数)的函数对象,对象包含一个原型属性来实现基于原型的继承和共享属性(共享性)。对象可以通过new关键字构造函数的调用创建的,如程序清单3:

清单3。使用构造函数(构造函数)创建对象

复制代码代码如下所示:
构造函数本身是一个函数对象。
功能人(){
在这里做一些初始化工作
}
它有一个名为原型的属性
person.prototype = { {
姓名:Zhang three,
年龄:26岁,
性别:男人,
吃:函数({){
警报(我吃+的东西);
}
}
新关键字用于构造对象
新的人();


由于Javascript为早期发明家使语言和著名的java连接(虽然我们知道是雷锋和雷锋塔之间的关系),使用新的关键字来定义构造函数调用和创建对象,使其在创建对象的java语法的样子。然而,需要指出的是,这两种语言的新的意义无关,因为对象结构的机制是完全不同的。也正是因为这里的语法是类似的,许多习惯于面向对象语言创建程序的类型,深入了解JS对象原型是一种方式构造,因为他们总是不在js语言中,函数名可以用作类名,本质上,JS只是借用关键字new。也就是说,换句话说,ECMAscript可以使用其他非new表达式调用构造函数创建对象。

对原型链(原型链)的透彻理解

在ECMAscript,每一个对象的构造函数创建具有构造函数的原型属性值隐式引用(隐式引用)。这个引用称为原型(原型),而且每个原型都可以隐式地引用它自己的原型,原型就是原型。如果这种情况持续下去,这就是所谓的原型链。在具体语言的实现,每一个对象都有实现原型的隐式引用__proto__属性。程序清单4说明了这。

的__proto__属性和隐式引用列表4。对象

复制代码代码如下所示:
功能人(名称){
this.name =名称;
}
新的人();
对原型属性构造函数的隐式对象引用,所以在这里打印true
console.log(p.__proto__ =人。原型);

原型本身是一个对象,所以他的隐式引用点。
对象/原型属性构造函数,并打印true
console.log(人。原型。__proto__ =对象。原型);

构造函数是一个函数对象,所以在这里打印true
console.log(人。__proto__ =函数原型);


一个原型链,所谓的属性隐藏机制可以被定义和继承通过这mechanism.ecmascript提供,如果属性分配给一个对象,解释器会包含在原型链中的第一个对象的属性。注:原型本身是一个对象,与原型链是一组对象链。在对象的原型链的第一个对象是对象本身)指定一个值。相反的,如果你想获得一个对象的属性值,译员自然返回对象的属性,首先在对象的原型链属性的值。图1描述了隐藏机制:


图1原型链中的属性隐藏机制。


在图1中,prototype1 object1 -> -> prototype2形式发生对象的原型链。根据以上属性隐藏机制,我们可以清楚地看到,在prototype1对象和对象不prototype2属性产权属性是隐藏的。理解原型链,这将是了解基于原型继承的实现原理在JS很容易。清单5是使用原型链实现继承的一个简单示例。

清单5。用原型链马>哺乳动物>动物进行继承。

复制代码代码如下所示:
动物对象构造函数语句
函数动物(){
}
对象的原型动物属性,
可以理解为指定的动物/对象原型。
animal.prototype = { {
名称:动物
重量:0,
函数(){
警惕(动物正在进食)!);
}
}
哺乳动物对象构造函数语句
哺乳动物(){
this.name =哺乳动物;
}
动物对象的指定哺乳动物对象/原型。
事实上,这是在哺乳动物对象和动物对象之间的原型链中创建的。
mammal.prototype =新的动物();

马对象构造器语句
功能马(身高,体重){
this.name =马;
this.height =高度;
this.weight =重量;
}
指定对象 / /马的原型为Mamal构建马和哺乳动物之间的原型链
Horse.prototype =新的哺乳动物();

重新指定吃法,这个方法将覆盖从动物原型中继承的吃法。
horse.prototype.eat =函数(){
警惕(马在吃草)!);
}
对原型链进行验证和理解
新马(100, 300);
console.log(马。__proto__ =马。原型);
console.log(马的原型。__proto__ =哺乳动物。原型);
console.log(哺乳动物的原型。__proto__ =动物。原型);


理解对象的原型继承逻辑清单5中的实现的关键是Horse.prototype =新的哺乳动物()和mammal.prototype =新的动物()。首先,对方程右边的结果是建立一个临时对象,然后分配对象对方程左边对象的原型属性也就是说对新的对象作为左对象的原型。读者可以用清单5的代码对应的程序的最后两行方程代替两方程。


javascript类继承的实现

从清单5中的代码显示在继承基础上的原型,虽然实现代码的重用,但文松散不光滑,可以读,不利于扩展的源代码和有效的组织和管理。我必须承认类继承的方式在语言实现更强大,并建立可重用的代码和组织程序优势明显。这允许程序员寻找一个方法的代码在一个类继承方式在Javascript。从抽象的角度,从继承和继承原型式的设计来实现面向对象的语言,和他们的计算能力实现载体是等价(因为lambda和演算图灵机的计算能力是等价的),那么你可以找到一个转换。语言类型通过转换继承了原型类型继承编码。

目前,一些主流js框架提供了这种转化机制,这是类的声明,如dojo.declare()、Ext.entend(),等等。使用这些框架,用户可以方便地组织自己的JS代码。事实上,在很多框架出现,Javascript大师道格拉斯克罗克福德首先用三个功能扩展函数对象,实现转型。它的实现细节可以被称为资源,也有著名的base.js(参考资源)实现了由Dean Edwards。值得一提的是,jQuery的父亲,John Resig,有了自己的简单的继承与人群的头后的代码不超过30行。这是很简单的声明类的使用扩展方法提供的清单6的程序是使用简单的遗传库实现的类声明的例子,打印输出语句的最后一句话是简单的继承实现类继承的最好描述。

清单6。使用简单继承实现类继承

复制代码代码如下所示:
{类}人
无功的人= class.extend({
_issleeping:真,
init:函数(名称){
这_name =名称;
},
睡懒觉:函数(){
这_issleeping返回;
}
});
类程序员和继承人
VaR的程序员= person.extend({
初始化:功能(名称、睡懒觉){
调用父类构造函数
This._super (name);
设置自己的状态
这_issleeping =睡懒觉;
}
});
var人=新的人(张三);
var迪奥=新的程序员(张江南
打印
console.log(person.issleeping());
打印假
console.log(diors.issleeping());
这是真的,打印的
console.log(人是人类的实例)
迪奥是程序员
迪奥的迪奥是人类的实例);



如果你已充分了解原型,函数生成器,基于这一语境封闭,不了解简单的继承的实现原理非常困难。在本质上,无功的人= class.extend(…)在这份声明中,左边的人实际上是一个构造函数的类调用返回的扩展方法,是的,函数对象的引用。随着这一理念,我们将继续介绍如何简单继承这样做,然后实现了从原型继承类继承的转换。图2是简单的继承及其伴随的注释来源。为理解方便,代码是中国的代码添加。

图2简单继承源代码分析


除了代码的第二部分,整体的一致性的第一和第三部分会发现根本目的的扩展功能是构建新的原型属性新的构造函数,我们不禁感叹John Resig的主人和其对JS语言本质的理解程度。至于John Resig,我们怎么能想到这样一个美妙的实现方法感兴趣的读者可以阅读本文(参考资料),包括对简单继承初始设计的思考过程的详细介绍。

Javascript私有成员实现

到目前为止,如果你仍然怀疑Javascript的面向对象,这个疑问必须Javascript没有实现信息隐藏在面向对象,即私人和公共的对象是明确的私有成员不同的其他类型,这是对信息隐藏Javascript闭包的实现。看节目表7:

清单7。使用闭包实现信息隐藏

复制代码代码如下所示:
用户构造函数语句
功能的用户(PWD){
定义私有属性
VaR的密码=密码;
定义私有方法
功能GetPassword(){
关闭密码返回
返回密码;
}
其他公共方法的对象的特权函数声明可以通过特权方法访问私有成员。
this.passwordservice =函数(){
GetPassword()返回;
}
}
公共成员声明
user.prototype.checkpassword =功能(PWD){
(这一回。passwordservice)=密码;
};
验证/隐藏
新用户(123456);
打印
console.log(u.checkpassword(123456 ));
打印未定义
console.log(u.password);
打印
console.log(typeof u.gepassword =未定义);


Javascript必须依靠闭包实现信息隐藏,这是由它的功能性语言的特点决定的。本文将不讨论这两个话题的语言功能关闭,你知道在过去,你明白这种基于Javascript上下文。信息隐藏在Javascript中,道格拉斯克罗克福德有更多的权威和详细的Javascript在私有成员介绍(参考资料)。

结语

Javascript被认为是世界上最容易被误解的编程语言,因为它属于C语言家族,但它显示了Lisp语言的功能语言特性。无类,它实现了完全面向对象的。如果我们想要全面了解这门语言,我们必须把它的C语言的外套从新功能规划的角度,并摒弃原有的面向对象的概念去理解它。随着Web应用和近年来JS语言发展迅速的普及,特别是背景的JS引擎的出现,如基于NodeJS的V8引擎,可以预见的是,原来的JS作为玩具页准备的结果会得到更大的发展。这种发展趋势也提高了JS程序员的更高的要求。只有彻底理解的语言可以在一个大的J发挥她的力量的项目。