最近准备在一个项目上使用Node.js,摸索了一段时间之后基本能够运用起来。由于自己一直做的是JavaEE开发,所以比较习惯于使用面向对象的方式进行开发。而接触前端的第一个框架是Dojo,同样提供了面向对象编程的机制。所以就想着是否在后台node.js上通过加载Dojo库的一些纯javascript的模块来进行面向对象开发。google了之后的确发现了几篇介绍在Node上运行Dojo的文章,先贴在这里:一个是我们公司的Dojo部门的同事写的在 Node.js 上使用 Dojo,还有一篇是一个比较完整的介绍node.js和dojo结合的方案:node.js与dojo完美的融合-开发完全面向对象化。还有一个外国的哥们用dojo写了一个框架,支持在node.js上的web应用开发,叫dojos,有兴趣的同学可以到github上把代码下clone下来看看:https://github.com/supnate/dojos。
既然别人都已经写好了,那么我在这里说什么呢?。。。哈哈,所谓教学相长,把学会的东西讲清楚其实也是巩固知识的过程。并且这段时间的摸索下来,我对这种开发方式也有一些自己的看法。
面向对象
首先谈谈面向对象,最大的三个特点,封装、继承、多态,相信很多使用过面向对象开发方式的同学肯定已经习惯与这种方式了。尽管面向对象并不是javascript这种脚本语言的主旨所在,但是能够以这种方式吸引更多的程序员来接受和更快上手javascript,这对与js的发展是有好处的。况且,使用这种方式编程的时候并不会让你丢失掉javascript本身的特点,你依然可以使用函数式编程,使用闭包的特性,可以动态地给对象添加属性,可以使用javascript的反射机制。只是在处理一些复杂的层次结构和业务逻辑的时候使用面向对象的方式,能够使得整个程序更加结构化,以及有更好的可重用性。同时很多设计模式也可以在项目中使用,这是意见多么美好的事情,何乐而不为呢。
javascript原型继承
熟悉javascript的同学都知道js是基于原型继承的对象语言。想要一个对象继承自另一个对象,要将这个构造函数的prototype属性指向父类的对象。对js的原型和继承还有疑惑的同学可以多找几篇文章或者书本看看。这里推荐一篇我经常拿出来翻的js原理介绍的比较全面的文章:使用面向对象的技术创建高级 Web 应用程序,还有一本@lexlian大牛推荐我看的js经典书《JavaScript The Good Parts》,由于封面上印着一只蝴蝶,所以也被称为蝴蝶书。 不过总的来说,要使用javascript的原型继承,是一种相对比较麻烦的方式。
dojo面向对象
那么我们就来看看dojo是如何支持面向对象的。
declare
declare是dojo提供的定义类的函数,基本用法如下:
[superClass1, superClass2], // 父类们
// 要加入新定义类的原型的所有属性及方法
{
messageX: null,
constructor: function(msgX) {
this.messageX = msgX;
},
sayMessageX: function() {
this.inhereted(arguments);
alert("hi, this is " + this.messageX);
}
});
从上面的代码中可以看出,dojo定义类以及继承父类的方式还是比较方便的,并且dojo还支持多继承,想想如果要用prototype来写多继承该是多么麻烦的事情啊。
大家可以看到这个类里面有个constructor函数,没错就是这个类的构造函数,dojo的子类在被实例化的时候,会自动调用所有父类的构造函数。所以在设置一些属性的时候,只需要基础父类中调用lang.mix(),就可以很方便的将所有传进来的属性融入新的对象中,而不需要一个个属性逐个设置。这就是我之前说的,可以在面向对象的方式中继续使用脚本语言的灵活性和动态性。
在子类的方法中,调用this.inhereted(arguments),即可以随时随地的调用父类的同名方法。这比java的super()只能在方法开始的时候调用灵活多了。
加载模块
Node.js和Dojo的模块加载机制在 Node.js 上使用 Dojo这篇文章中介绍的很详细了。这里就直接引用了:
Node.js 和 Dojo 都遵循 CommonJS 的模块相关规范。Node.js 支持的是 Module1.0 规范,而 Dojo 支持的是 AMD(Asynchronous Module Definition,即异步模块定义)规范。虽然是两个规范,但它们都是描述了模块的定义和加载机制,有很多共同点。这就为 Dojo 运行于 Node 提供了天然的基础。在规范中,JavaScript 文件和模块是一一对应的关系,每个文件就是一个模块,模块之间可以通过相对路径来引用。
对于 Node.js,要使用一个模块非常简单,直接用 Module1.0 规范中定义的 require 函数即可,例如:
var content = fs.readFileSync('filePath' ,' utf8' );
但对于 Dojo 支持的 AMD 规范,则定义的是一个异步载入机制,稍微复杂。因为这个规范强调的是异步,就需要通过一个回调函数来使用模块,这个回调函数会在依赖的模块载入完成之后被调用,例如:
var zone = date.isLeapYear(new Date());// 获取当前是否闰年
});
在 CommonJS 规范的基础上,Node.js 和 Dojo 还都另外引入了类似的包(package)的概念。所谓一个包就是一个文件夹,在 Node.js 下可以直接 require('packageIdentifer' ),而 Dojo 则是通过 define(['packageIdentifier' ], callback) 来使用一个包。这时 Node.js 会寻找文件夹下的 index.js 或者 index.node 模块,而 Dojo 则寻找的是 main.js 模块。同样,因为应用是运行于 Dojo 框架之下,包的概念以 Dojo 的实现为准。
如果把模块的加载理解为 Java 中的 ClassLoader,那么 Dojo 就是实现了自己的 ClassLoader,来取代 Node.js 自身的行为。因此,要在 Node.js 上运行一个基于 Dojo 的应用,用的是类似下面的命令:
这个命令告诉了 Node.js 应该执行 dojo.js 这个模块,从而启动了 Dojo 框架。而后面的参数 load=xxx 则是告诉 Dojo 应该执行 xxx 这个包(package)。这里的 xxx 就是您的应用程序的入口位置。因为 Dojo 已经接管了模块的管理,所以这里运行的就是 xxx 这个包下的 main.js 模块。
以上斜体部分为引用。
下面我稍微极少一下dojo的require和define函数。其实两者在写法上是一样的,但是在用法和概念上却有着完全不同的。require是用来加载已经定义过的模块的,而define是用来定义模块的。他们实际上是相辅相成的两个函数。取一个简单的例子:
var User = declare('User', [Base], {
name: "",
printName: function() {
console.log(this.name);
}
});
每天收获一点,慢慢地就多了。
今天开始正式学习javascript,虽然以前都有一些涉及,但是没有好好的系统的学上一编,趁这段寒假,多学一点总是好的,坚持就是胜利,废话不多说了。
1. 数据类型:
简单(基本)数据类型:Boolean, Number,String,Undefined,Null。
复杂数据类型:Array,Object等。
2.区分undefined 和 null
Null:
(1) null 意味着没有值,即缺少数据。
(2)包含 null 的变量包含“无值”或“无对象”。换句话说,该变量没有保存有效的数、字符串、boolean、数组或对象。可以通过给一个变量赋 null 值来清除变量 的内容。
(3) Null类型只有一个值的数据类型,这个特殊的值是null。从逻辑角度来看,null值表示一个空对象指针,而这也正是使用typeof操作符检测null时会返回"object"的原因(null是一种特殊的object)
Undefined:
(1) undefined常量用于尚未初始化的变量或未初始化的动态对象属性的特殊值(未定义的值和定义未赋值的为undefined)
(2) Undefined类型只有一个值,即特殊的undefined(注意大小写,用的时候也不用加引号,人家不是string)。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined
实际上,undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true,但是使用全等运算符(===)对null和undefined进行比较时,比较结果为不相等。
3. 区分等于(==)和全等于(===)
重点:等于(==)的情况下只要值相同就返回True;
而全等(===)的时候需要值和类型都要匹配才能返回True.具体看堆栈的区别及逻辑等和逻辑全等
4.变量的声明:
4.1 变量的声明必须使用var。
这仅仅是给全局对象创建了一个新属性(但它不是变量)。“不是变量”并不是说它不能被改变,而是指它不符合ECMAScript规范中的变量概念,所以它“不是变量”,这个也是我的盲区,我是参考了汤姆大叔的博客才知道的。详细分析参考深入理解JavaScript系列(12):变量对象(Variable Object)
4.2 变量声明提升
这个比较好理解,执行器会将所有的变量声明移到语句的顶部,如果是在函数的内部声明局部变量,那么就会将变量声明提升到函数体内的最顶部。这个只是针对声明语句。
4.3 变量的传值和传址
传值:
var j = i; //输出 10
alert(i);
i = 30;
alert(j); //输出10
function sqrt(x){
return x*x;
}
var inValue = 3;
var outResult = sqrt(inValue);
alert(outResult); //输出 9
alert(inValue); //输出 3
传址:
var newArray = myArray;
alert(newArray[1]); //输出dick
myArray[1] = "jack";
alert(newArray[1]); //输出jack
4.4 内存使用规则-堆和栈
堆:为复杂数据类型分配空间,例如数组,Object对象,运行时动态的分配内存,速度慢。
栈:基本类型的变量和对象的引用,速度快,可以共享(这边数据共享还有些不理解。)’
总而言之,javascript堆不需要程序代码显式地释放,会有自动的垃圾回收机制。但是为了提高程序性能,还是可以自己释放的,最常用的方法就是对其赋值为null。
注意点:
var str = "abc"; //栈中存放值“abc”和对值的引用
//推荐使用第二种创建方法
堆栈的区别及逻辑等和逻辑全等
var str1 = "abc";
var str2 = "abc";
alert(str1 == str2); //true
alert(str1 ===str2); //true
//实际比较的是堆中的内容,不管是逻辑等于还是逻辑全等于运算都返回false、可以看出str1,str2指向的不是同一个对象。
var str1 = new String("abc");
var str2 = new String("abc");
alert(str1 == str2); //false
alert(str1 === str2); //false
//比较堆中和栈中的值,进行逻辑等于运算的时候,会首先将变量转成相同的数据类型,然后进行对比,所以返回true,但是逻辑全等于会对数据类型进行比较,看是否引用了同一个数据,返回false
var str1 = new String("abc");
var str2 = "abc";
alert(str1 == str2); //true
alert(str1 === str2); //false
今天先写这么多吧,
一般都是自己创建元素然后append到页面的
但是如果是页面本身有的元素append到另一个页面元素呢?
貌似是:
元素的确成为了另一个元素的子元素
而元素本身没有了。
也就是说,消失了。而不是复制
这一点,的确是这样的,但我觉的这个机制很奇怪
就不能是复制么,即1成为了2的子元素,然后1仍然在那里。
不是说需求一般是这样。恰恰相反,需求的确一般都是要删除原来的,比如这个案例
但是从逻辑上想想都是:先是append了,然后我们自己去删除掉原来的1元素
现在倒好,append还有自带有remove功能。
要注意。
本文链接