美文网首页编程
javaScript闭包实现类与继承(非ES6)

javaScript闭包实现类与继承(非ES6)

作者: 有头发的搬砖员 | 来源:发表于2019-07-31 17:02 被阅读3次

首先我们都知道js的一个函数定义是这样的

function func(){ //声明一个普通的函数
  //省略代码
}

而没有名字的函数叫匿名函数是这样的

function(){ //声明一个匿名函数,这样的方式一般用于回调
  //省略代码
}

或者我们习惯用一个变量保存这个匿名函数,变量就是函数本身

var func = function(){ //匿名函数保存到func变量内
  //省略代码
}

同样,在调用函数的时候是使用函数名或者这个变量名后面加上一个括号,像这样

func(); //调用函数

其实也可以在声明函数的时候直接调用,只要同样加上括号就行了,像这样

(function(){ //即时执行函数
  //省略代码
})();

当然,函数是可以有返回值的,即时执行函数,也是即使可以有返回值。

var func = (function(){ //即时执行函数
   var i = 1;
   return i;
})();

这样写,func就不再是这个匿名函数本身,而是函数的返回结果,func = 1;

----------------------------------------我是分割线-----------------------------------------

现在我们的函数返回的是一个整数,但如果我们的函数返回的是另一个函数,就成了闭包,像这样:

var func = (function(){ //即时执行函数
   var resultFunc = function(){ //要返回的函数
       //省略代码
   }
   return resultFunc;
})();

以上这样写 func就是resultFunc函数,这样有什么用呢?看以下的

var func = (function(){
   var i = 5;   //声明了局部变量
   var resultFunc = function(){ 
        console.log(i);      //返回的函数体内能访问变量 i
       //省略代码
   }
   //作用域内能访问变量 i
   return resultFunc;
})();
//函数体外能不能访问变量 i

这样声明的变量,外部不能访问,是不是很像私有的成员变量?同样,内部方法一样

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //声明了局部变量
        //省略代码
    }
   var resultFunc = function(){ 
        privateFunc();  //调用局部函数
       //省略代码
   }
   return resultFunc;
})();

而实际情况下,我们可以尝试这样写:

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //声明了局部变量
        console.log("执行了privateFunc局部函数");
    }
   var resultFunc = function(j){ 
        console.log("外部变量:"+j);
        console.log("内部变量:"+i);
        privateFunc();  //调用局部函数
       //省略代码
   }
   return resultFunc;
})();

var test = new func(9);
执行结果

这样看,其实 resultFunc 更像是一个构造函数,这个函数在我们new func()的时候,必须且只执行一次,并且这个函数可以接受外部参数。

之后我们可以通过prototype的方式为其添加一些公开函数,而这些函数都是可以访问局部变量及局部函数的:

var func = (function(){
   var i = 5;  
   var privateFunc = function(){  //声明了局部变量
        console.log("执行了privateFunc局部函数");
    }
   var resultFunc = function(j){ 
        console.log("外部变量:"+j);
        console.log("内部变量:"+i);
        privateFunc();  //调用局部函数
       //省略代码
   }
   var _proto = resultFunc.prototype; //取出prototype变量
    _proto.myName = "ken";
    _proto.publicFunc = function(){
        console.log("这个是公共的方法,还有我的名字是"+this.myName);
   }
   return resultFunc;
})();

var test = new func(9);
test.publicFunc();
console.log(test.myName);
运行结果

这个例子说明了能通过"."的方式调用prototype的内容,prototype函数体内通过this.访问自身变量。
就这样,公共及私有成员方法都通过闭包实现出来。

----------------------------------------再次分割线-----------------------------------------

通过以上的例子知道,公共变量及方法都是保存在prototype内,那么其实把prototype取过来继承就可以了,先整理一下父类的代码:

var Super = (function(){
    function _super(){
        console.log("Super constructor");
        this.name = "Super";
    }
    var _proto = _super.prototype;
    _proto.sayHi = function(){
        console.log("hello ! my name is "+this.getMyName());
    }
    _proto.getMyName = function(){
            return this.name;
        }
    return _super;
})();

var s = new Super();
s.sayHi();
父类被new的时候结果

以下是子类的继承方式

var child = (function(){
  var extend = Super;         //定义要继承的父类
  function _child(){          //子类的构造函数
    extend.call(this);        //让父类内部的this替换成子类的this,执行函数
    console.log("child constructor");
    this.name="child";        //覆盖子类的name
  }
  var nullObj = function(){};  //这里建立一个空白对象
  nullObj.prototype = extend.prototype; //空白对象的prototype指向父类的prototype
  _child.prototype = new nullObj();     //新建nullObj(实际上是复制一份)的prototype给_child
  _child.prototype.constructor = _child;//把_child的构造函数放回prototype里,因prototype刚刚已经被覆盖了
  var _proto = _child.prototype;  //取得prototype
  ///这里可以继续添加子类的方法
  return _child;
})();

注意:nullObj.prototype = extend.prototype; 这里nullObj.prototype是引用,不能直接修改nullObj.prototype内容,不然会影响父类的代码,只能通过new nullObj 复制给 _child.prototype

调用测试

var c = new child();
c.sayHi();
console.log(c.name);
运行结果

可以看到这里首先是调用了父类的构造函数,再调用子类的构造函数,而后sayHi方法被子类继承过来,而name内容变成了子类的child字符串。

本人学艺不精,欢迎吐槽~~

相关文章

  • javaScript闭包实现类与继承(非ES6)

    首先我们都知道js的一个函数定义是这样的 而没有名字的函数叫匿名函数是这样的 或者我们习惯用一个变量保存这个匿名函...

  • Python闭包

    闭包 = 环境变量 + 函数 调用闭包内部的环境变量 闭包的经典误区 闭包与非闭包实现人类走路 非闭包 闭包

  • 面向对象类

    类与实例 类的声明 ES5 ES6 生成实例 类与继承 如何实现继承 继承的几种方式 原型链是实现继承的主要方法 ...

  • TypeScript进阶(类)

    类 传统方法中,JavaScript 通过构造函数实现类的概念,通过原型链实现继承。而在 ES6 中,我们终于迎来...

  • ES6中类与类的继承

    ES6以前,javascript中类的继承可以使用function和原型prototype来模拟类class来实现...

  • 作用域链与闭包(一)

    JavaScript中有两个“链”,即原型链与作用域链,前者关于实现继承,prototype。而后者对于理解闭包至...

  • Javascript的继承与多态

    本文先对es6发布之前javascript各种继承实现方式进行深入的分析比较,然后再介绍es6中对类继承的支持以及...

  • JavaScript中的复用和抽象

    复用、抽象 JavaScript实现方式 模拟Java中的类有new、this,但是缺少继承等关键特性,ES6开始...

  • javascript中ES6的class写法

    在ES6中,javascript实现类定义、类继承及类中定义变量,构造方法,一般方法,静态方法 代码中均有注释

  • TypeScript系列(四)类的初体验

    类的介绍 ES6之前Javascript是使用函数和基于原型的继承来实现类的概念。而在Typescript中则可以...

网友评论

    本文标题:javaScript闭包实现类与继承(非ES6)

    本文链接:https://www.haomeiwen.com/subject/snttdctx.html