标签:
这段时间做项目主要做关于服务器的功能点,因此,逐渐开始学习node.js写服务器,总体下来,觉得node比php更好用,写服务前器的速度更快,处理效率更高。注:node并不是专门写服务器的,其实node的出现,将js从web前端的专用语言,变成了一门通用语言。node中有各样的基础模块:比如fs,path,buffer,http,net等模块,此外,node还有各种各样的三方模块,比如写服务器人常用的express,co,koa,seqlize等著名框架,也就是三方模块。那么,node.js的模块机制究竟是如何的呢?我们应该注意模块机制上的哪些问题呢?
var num=1;
module.exports.num=num;`
a 文件:
`var module1=require("./module1");
var module2=require("./module1");
module1.num=2;
console.log(module2.num);
上述代码运行结果是多少呢?很多人应该都会回答2,答案确实也是2,但是如果下面这种场景呢?
`module1模块:
var num=1;
module.exports.num=num
a 文件:
`var module1=require("./module1");
module1.num=2;`
b 文件:
var module2=require("./module1");
console.log(module2.num)
现在,先运行a文件(注意,a文件运行完成后,node并未结束),然后在运行b文件,请问num是多少?这里很多人都会说,显然是1啊。这是一种惯性思维,其实答案是2,为什么呢?因为模块无论在同一个文件还是在不同的文件中被加载,如果被加载过,都会保留他们的缓存,也就是只是被加载一次。所以,这里在a文件运行后,module1模块的num数值被加载修改为2,在b文件运行的时候,module1模块因为被加载过,因此,num的数值在b文件中,显示为2。
对比下node的required机制和java的import机制?
对node而言,引入模块是使用require命令,而java是import命令。node的require命令的基本功能是,读入并执行一个JavaScript文件,然后返回该模块的exports对象。而java的import是引入一个类文件,然后通过类文件名,来访问文件中的方法或者变量。
由此可以看出,node的require和java的import都有相似的设计思路:
两者不同的之处在于:
函数是js中一个最关键的东东,在java语言中,函数仅仅是传统意义上的函数,执行一个函数,访问对象的代码区,然后为参数分配对象的空间,接下来执行函数就可以了,然后返回值。但是对js而言,函数不单单是函数,函数也可以作为变量,参数,返回值,函数甚至再js中作为一种基本类型,对!函数在js中是一种对象类型,也是就是说,函数在js中一个对象而存在。其实将函数作为一种基本类型,也就说明了函数的灵活性。那么,我们有必要分析下js的函数是如何实现的
js有两种常用的定义函数的方法:
function A(){}`
`var a=function(params){}
上面方法在内存上是怎么实现的呢?其实也很简单,看下面内存分配图就会明白了:
其实,上述的方法中,无论是第一种方法还是第二种方法,在js的解释器中,都会这样执行:
var x=new Object
x.constructor=A; `
`A.prototype=x
这里的x就是上图右边的object。可以看到,js的函数的本质上是指向了一块堆空间(因为已经有原型了:A.prototype=obejct)。这也很好地解释了函数为什么能被作为参数和返回值,因为一个函数名作为参数的时候,代表的就是一块堆空间上的一块地址值了。上述两种方法里面,不同的是第一种方法,name=A,而第二种方法的name=undefined。
所以,现在可以明确一个写node或者js的程序时候的思想了:当我定义一个函数的时候,那么,随即会在堆空间上定义一个对象,然后用函数名代表这个对象的地制值,调用这个函数的时候,即访问这个对象,届时,再分配栈空间,执行代码段,进而执行函数。
作用域:关于js的作用域的问题,详细了解可以看这篇博客:js作用域详解,关于js传统的作用域的问题,这里简单表述下:
我们可以看到,由于js的规定的作用域问题,我们可能会带来一些困扰,比如下面的这个函数:
var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
console.log(foo);
}
bar();
执行的结果是多少呢?很多人会说是1,但是,由于js的函数内部定义的变量优先级比外部的高,加之js的变量提升的原因,因此,上述执行的结果执行为10;
再看这个函数:
function test () {
console.log(value);
var value = ‘something‘;
console.log(value);
}
这样写法在其他有块级作用域中显然是不会编译通过的,但是在js中可以的,也是因为了js的变量提升,可以编译通过,输出结果为undefined和something。
以上的问题,就是js的作用域设计问题带来的不好的效果,比如没有块级作用域以及变量提升等问题,会在编程上带来一些不理想的效果。这些问题,在ES6的规范中,用let代替var后,得到解决。比如上述问题中第一个,可以使用let来代替var:比如这样解决:
var foo = 1;
function bar() {
if (!foo) {
let foo = 10;
}
console.log(foo);
}
bar();
对于js而言,要实例化一个对象有以下几种方法:
1. 书面语句:
var person = {
name: "lbq",
age: 22,
getName: function () {
return this.name;
}
}
console.log(person.getName());
可以看到,这样创建一个object确实很简单,只要一个花括符就可以,这也是js创建对象最方便的一点。
2. 使用函数创建:
function Person(name,age){
this.name=name;
this.age=age;
this.getName=function(){
return this.name;
}
}
var person1=new Person("lbq",23);
var person2=new Person("lzw",22);
console.log(person1.getName());
console.log(person2.getName());
大家可以看到,第二中方法是通过function来构造生成的object,这里可以看到,js在ES6之前,没有类的概念,我们要构造对象,只有通过function来生成。
function Person2(name, age) {
this.name = name;
this.age = age;
}
Person2.prototype.getName = function () {
return this.name;
}
Person2.prototype.getAge = function () {
return this.age;
}
var person3=new Person2("lbq",23);
var person4=new Person2("lzw",22);
console.log(person3.getAge());
console.log(person4.getAge());
在js中,每个函数都是有一个prototype属性,这个属性就是一个指针,指向一个对象,这个对象就是原型对象。我们可以对原型对象进行变量定义和方法定义,然后通过new来实例化一个对象,实例化的对象会有一个——proto—,指向原型对象。关于原型对象的具体可以参考《Javascript高级程序设计》这本书的第六章,有详细介绍。
class Person3{
constructor(name,age){
this.name=name;
this.age=age;
}
getName(){
return this.name;
}
getAge(){
return this.age;
}
}
var person5=new Person3("lbq",23);
var person6=new Person3("lzw",22);
console.log(person5.getName());
console.log(person6.getName());
好的消息是,在ES6中,加入class关键字后,我们可以在js中,像java那样定义类,然后通过类来实例化一个对象了。
this关键在java中也许很好理解,因为js是面向对象的语言,因此,java中的this就是指向当前的对象,我们可以通过this来访问当前对象的成员变量或者方法(无论公有还是私有),但是,js是一门函数式编程的语言,js中的this又怎么理解呢?
关于js的this的理解,可能说的比较复杂,这里我给出我的自己的理解:出现有this关键字的函数,是哪个对象中定义的函数,那么,该对象就是thi指向的对象:
我们来看下示范:
var obj={};
obj.x=100;
obj.y=function (){console.log(this.y)};
obj.y();
这里就很好理解了:显然打印出来的就是100,因为函数y是在obj变量中被调用的,所以thi指向的是obj对象,this.x就是100.
现在我们看一个难一点的示范:
var showthis=function(){
console.log(this.x);
}
var x=”this is a variable of window”;
var obj={};
obj.x=100;
obj.y=function (){console.log(this.x)};
var y2=obj.y;
obj.y();
showthis():
y2():
上述代码中,一共要打印三个console,按照分析,一个肯定还是100,第二个呢?在JavaScript的变量作用域里有一条规则“全局变量都是window对象的属性“。所以,showthis函数变量是在window对象中定义的,因此,showthis打印的是this is a variable of window。那么,y2对象呢?y2对象也是在window对象中定义的,因此,第三个console的结果,也一定是this is a variable of window。
经过上述两个案例,我们可以看到,this就是指向函数所在的对象的,如果函数在全局,那么,this就是指向window对象了。
关于this指向的思考,我是从node构建web项目来理解的,因为在koa中,经常用this.request或者是this.body来指代http的报文请求和应答,所以,有些时候务必要注意程序的中的this指向。如果想改变this的环境,那么,可以使用call或者是apply。
以上就是关于我在初学node.js中的一些关键疑问,比如js的函数如何作为一等公民对待,内存分配长啥样,还有关于初学一门语言都应该掌握的基础:变量类型,作用域,常会犯错的关键字,依赖体系的建立等,不是学习node应该注意,而是学习任何一门语言都应该注意和掌握的
标签:
原文地址:http://blog.csdn.net/zhiweiusetc/article/details/51870358