当前位置:   article > 正文

(四)nodejs循序渐进-函数,类和对象(基础篇)_nodejs 类 函数

nodejs 类 函数

上一篇文章讲到了基本数据类型和运算符,相信大家都能做简单的运算,本篇文章将讲述函数,类,对象。

函数

在nodejs中,一个函数可以作为另一个函数的参数。我们可以先定义一个函数,然后传递,也可以在传递参数的地方直接定义函数。Node.js 中函数的使用与 JavaScript 类似,举例来说,你可以这样做:

  1. function say(word) {
  2. console.log(word);
  3. }
  4. function execute(someFunction, value) {
  5. someFunction(value);
  6. }
  7. execute(say, "Hello");

以上代码中,我们把 say 函数作为 execute 函数的第一个变量进行了传递。这里传递的不是 say 的返回值,而是 say 本身!

这样一来, say 就变成了execute 中的本地变量 someFunction ,execute 可以通过调用 someFunction() (带括号的形式)来使用 say 函数。

当然,因为 say 有一个变量, execute 在调用 someFunction 时可以传递这样一个变量。

匿名函数

很多时候我们的某些函数只在一个地方被引用或者调用,那么我们为这个函数起一个名字就太不值了,没必要,所以我们可以临时写好这个函数,直接让引用它的人引用它,调用它的人调用它。所以函数可以省略函数名。

我们可以把一个函数作为变量传递。但是我们不一定要绕这个"先定义,再传递"的圈子,我们可以直接在另一个函数的括号中定义和传递这个函数:

  1. function execute(someFunction, value) {
  2. someFunction(value);
  3. }
  4. execute(function(word){ console.log(word) }, "Hello");
'
运行

我们在 execute 接受第一个参数的地方直接定义了我们准备传递给 execute 的函数。

用这种方式,我们甚至不用给这个函数起名字,这也是为什么它被叫做匿名函数 。

比如我们有两个版本的输出函数,一个是中文输出,一个是英文输出,那么如果不用匿名函数时候是这么写的:

  1. function zh(a, b, sum) {
  2. console.log(a + " + " + b + " 的值是:" + sum);
  3. }
  4. function en(a, b, sum) {
  5. console.log(a + " plus " + b + " is " + sum);
  6. }
  7. sumab(1, 2, zh);
  8. sumab(3, 4, en);

执行一遍这段代码,输出的结果将会是:

  1. 1 + 2 的值是:3
  2. 3 plus 4 is 7

这样的代码如果采用匿名函数的形式则将会是:

  1. sumab(1, 2, function(a, b, sum) {
  2. console.log(a + " + " + b + " 的值是:" + sum);
  3. });
  4. sumab(3, 4, function(a, b, sum) {
  5. console.log(a + " plus " + b + " is " + sum);
  6. });

这种形式通常使用于回调函数。回调机制算是 nodejs 的精髓。在以后的篇章会做介绍。

JSON对象

json是我们常用的轻量级数据交换结构,它在这里并不是通过类实例化的对象,所以我这里把它单独提出来。

声明一个 JSON对象 非常简单:

  1. var player = {
  2. "user_id" : "1927u893233c2993u429o34",
  3. "user_name" : "高司机",
  4. "gender" : "man",
  5. "age" : 18,
  6. "level" : 2,
  7. "viplevel" : 0,
  8. "exp" : 23933,
  9. "section" : 12,
  10. "achievement" : null,
  11. "resetinfo" : {
  12. "dailyreset_time" : "20201122000000",
  13. "prayreset_time" : "20201122030000",
  14. }
  15. };
  16. console.log("userid:"+player.user_id);
  17. console.log("userid:"+player["user_id"]);
'
运行

有两种方式能得到 JSON对象 中的某个键名的键值,第一种是用点连接,第二种是用中括号.

严格意义上来讲,nodejs的类不能算是类,其实它只是一个函数的集合体,加一些成员变量。它的本质其实是一个函数。

不过为了通俗地讲,我们接下去以及以后都将其称为“类”,实例化的叫“对象”。

因为类有着很多函数的特性,或者说它的本质就是一个函数,这个需要大家和其他C++,java语言要区别开,不要以为只有用class声明的才是类,不信你看下面:

函数的方式定义类

声明类

这里我用函数的特性来声明一个类

  1. function fun() {
  2. console.log("hello world");
  3. }

好了,我们已经写好了一个fun类了。请继续保持怀疑的心态来看这段代码:

var fun1 = new fun();

别看它是一个函数,如果以这样的形式new写出来,它就是这个类的实例化。

而这个所谓的fun()其实就是这个fun()类的构造函数。

成员变量有好两种方法。

第一种就是在类的构造函数或者任何构造函数中使用 this.<变量名> 。你可以在任何时候声明一个成员变量,在外部不影响使用,反正就算在还未声明的时候使用它,也会有一个 undefined 来撑着。所以说这就是第一种方法:

  1. function foo() {
  2. this.hello = "world";
  3. }

注意:只有在加了 this 的时候才是调用类的成员变量,否则只是函数内的一个局部变量而已。要分清楚有没有 this 的时候变量的作用范围。二话不说看代码:

  1. function fun(){
  2. this.data = "this.data";
  3. var data = "local data";
  4. console.log("data:"+this.data);
  5. console.log("data:"+data);
  6. }
  7. var fun1 = new fun();

输出什么内容呢,请思考下再看结果。

第二种方法就是在构造函数或者任何成员函数外部声明,prototype 属性使您有能力向对象添加属性和方法。其格式是 <类名>.prototype.<变量名>: 

  1. function fun() {
  2. }
  3. fun.prototype.print = "member value:this.print";
  4. var fun1 = new fun();
  5. console.log(fun1.print);

 

甚至你可以这么修改这个类:

  1. function fun() {
  2. this.print = "in fun call print";
  3. }
  4. fun.prototype.print = "hello world";
  5. var fun1 = new fun();
  6. console.log(fun1.print);

然后再用上面的代码输出。

但是不如你所愿,你期望输出“hello world”,但是输出的是"in fun call print",不要着急,等看完下面你就会有答案了,如果你还不懂,请在文章下方留言。

构造函数 

我们之前说过了这个fun()实际上是一个构造函数。那么显然我们可以给构造函数传参数,所以就有了下面的代码:

  1. function fun(param) {
  2. if(param === undefined) {
  3. this.print = "hello wolrd";
  4. } else {
  5. this.print = param;
  6. }
  7. }

我们看到上面有一个奇葩的判断 if(hello === undefined),这个判断有什么用呢?第一种可能,就是开发者很蛋疼地特意传进去一个 undefined 进去,这个时候它是 undefined 无可厚非。

还有一种情况。我们一开始就说了 JavaScript 是一门弱类型语言,其实不仅仅是弱类型,它的传参数也非常不严谨。你可以多传或者少传(只要保证你多传或者少传的时候可以保证程序不出错,或者逻辑不出错),原则上都是可以的。多传的参数会被自动忽略,而少传的参数会以 undefined 补足。

看看下面的代码就明白了:

  1. var fun1 = new fun("hello");
  2. console.log(fun1.print);
  3. var fun2 = new fun();
  4. console.log(fun2.print);

输出结果是:

  1. hello
  2. hello wolrd

显而易见,我们的fun2在声明的时候,被解释成 

var fun2 = new fun(undefined);

 成员函数

成员函数的声明跟成员变量的第二种声明方法差不多,即 <类名>.prototype.<函数名> = <函数>;

  1. function fun(param) {
  2. if(param === undefined) {
  3. this.print = "hello wolrd";
  4. } else {
  5. this.print = param;
  6. }
  7. }
  8. function setPrint(param) {
  9. this.print = param;
  10. }
  11. fun.prototype.Print = setPrint;
  12. var fun1 = new fun("hello");
  13. fun1.Print("不好意思,我这里写个BUG");
  14. console.log(fun1.print);

上面这段代码显而易见,我们实现了fun类的Print函数,能通过它修改fun.print的值,所以输出结果为:

不好意思,我这里写个BUG

通常我们声明类的成员函数时候都是用匿名函数来声明的,因为反正那个函数也就是这个类的一个成员函数而已,不会在其它地方被单独引用或者调用,所以就有了下面的代码:

  1. function fun(param) {
  2. if(param === undefined) {
  3. this.print = "hello wolrd";
  4. } else {
  5. this.print = param;
  6. }
  7. }
  8. fun.prototype.Print = function(param) {
  9. this.print = param;
  10. }
  11. var fun1 = new fun("hello");
  12. fun1.Print("不好意思,我这里写个BUG");
  13. console.log(fun1.print);

class传统方式定义类

  1. class Rect {
  2. //构造函数
  3. constructor(w, h) {
  4. this.width = w;
  5. this.height = h;
  6. }
  7. //类成员函数
  8. toString() {
  9. return '(' + this.width + ', ' + this.height + ')';
  10. }
  11. //类静态成员函数
  12. static setParam(name){
  13. //修改类静态成员变量
  14. this.para = name;
  15. return this.para;
  16. }
  17. }
  18. //初始化类静态成员变量
  19. Rect.para = 'hello world';
  20. //新创建Rect对象
  21. var rect = new Rect(1024, 960);
  22. console.log(rect.toString());
  23. console.log(Rect.para);
  24. console.log(Rect.setParam('高司机'));
  25. console.log(Rect.para);

好了,这代码块相信你应该看的懂(如果不懂可以继续给我留言,我将完善尽可能让更多的人没有阅读理解障碍。),类静态成员函数也是通过static来修饰,静态成员也是在类外部进行声明并初始化。构造函数一般是通过constructor来声明。

光会写这块代码,我相信你肯定不满足,那么我们继续根据这个代码做变化,更加熟悉nodejs的类:

1.能不能有多个构造函数呢?

相信你已经跃跃欲试了

  1. class Rect {
  2. constructor(w, h) {
  3. this.width = w;
  4. this.height = h;
  5. }
  6. constructor(w, h, z) {
  7. this.width = w;
  8. this.height = h;
  9. }
  10. Rect(){
  11. console.log("call Rect\n");
  12. }
  13. toString() {
  14. return '(' + this.width + ', ' + this.height + ')';
  15. }
  16. static setParam(name){
  17. this.para = name;
  18. return this.para;
  19. }
  20. }
  21. Rect.para = 'hello world';
  22. var rect = new Rect(1024, 960);
  23. console.log(rect.toString());
  24. console.log(Rect.para);
  25. console.log(Rect.setParam('高司机'));
  26. console.log(Rect.para);

然鹅,实际运行中报错了:

  1. /root/app1.js:7
  2. constructor(w, h, y) {
  3. ^^^^^^^^^^^
  4. SyntaxError: A class may only have one constructor
  5. at createScript (vm.js:56:10)
  6. at Object.runInThisContext (vm.js:97:10)
  7. at Module._compile (module.js:549:28)
  8. at Object.Module._extensions..js (module.js:586:10)
  9. at Module.load (module.js:494:32)
  10. at tryModuleLoad (module.js:453:12)
  11. at Function.Module._load (module.js:445:3)
  12. at Module.runMain (module.js:611:10)
  13. at run (bootstrap_node.js:394:7)
  14. at startup (bootstrap_node.js:160:9)

所以呀nodejs的类只有一个构造函数

 2.能不能像C++一样通过类名这样的方式声明一个构造函数

比如:

  1. class Rect {
  2. Rect(){
  3. console.log("call Rect");
  4. }
  5. toString() {
  6. return '(' + this.width + ', ' + this.height + ')';
  7. }
  8. static setParam(name){
  9. this.para = name;
  10. return this.para;
  11. }
  12. }
  13. Rect.para = 'hello world';
  14. var rect = new Rect();
  15. rect.Rect();

你会发现实际上 var rect = new Rect()并不会调用Rect函数,而只有rect.Rect()才会调用Rect方法。 

3.如果创建对象的时候传入构造函数的参数少呢?

  1. class Rect {
  2. constructor(w, h) {
  3. this.width = w;
  4. this.height = h;
  5. console.log("call constructor\n");
  6. }
  7. Rect(){
  8. console.log("call Rect\n");
  9. }
  10. toString() {
  11. return '(' + this.width + ', ' + this.height + ')';
  12. }
  13. static setParam(name){
  14. this.para = name;
  15. return this.para;
  16. }
  17. }
  18. Rect.para = 'hello world';
  19. var rect = new Rect(1024);
  20. console.log(rect.toString());

输出的结果:

  1. call constructor
  2. (1024, undefined)

类的自由性

所谓类的自由性即你可以在任何地方修改你的类,比如说 String类,有着诸如 length 这样的成员变量,也有 indexOfsubstr 等成员函数。但是万一我们觉得这个 string 有些地方不完善,想加自己的方法,那么可以在你想要的地方给它增加一个函数,比如:

  1. String.prototype.fun = function() {
  2. return "hello world";
  3. };

这个string类的fun函数的意思就是返回hello world。

我们来测试一下:

  1. var str = "高司机又要开始写bug了";
  2. console.log(str.fun());

你将会得到这样的结果:

hello world

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/运维做开发/article/detail/977620
推荐阅读
  

闽ICP备14008679号