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

首先我们都知道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函数,这样有什么用呢?看下面的代码,注意变量 i 的作用域

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

这样声明的 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"; //prototype的变量
    _proto.publicFunc = function(){ //prototype的方法
        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字符串。

采用闭包的方式跟ES6的class有什么不一样?
● ES6的class不存在私有成员,内部通过this访问变量或函数,外部通过"."方式访问。
● 采用闭包方式可以拥有私有成员,公共成员跟ES6访问方式一样,访问私有成员因为作用域的关系,只要直接调用就好了。
● ES6的使用比闭包方式要简单,可以根据自己的情况选择使用。

链接:https://www.jianshu.com/p/77e5840fc514

原文地址:https://www.cnblogs.com/porter/p/12152455.html

时间: 2025-01-16 22:40:24

javaScript闭包实现类与继承(非ES6)的相关文章

JavaScript里的类和继承

JavaScript与大部分客户端语言有几点明显的不同: JS是 动态解释性语言,没有编译过程,它在程序运行过程中被逐行解释执行 JS是 弱类型语言,它的变量没有严格类型限制 JS是面向对象语言,但 没有明确的类的概念(虽然有class关键字,然而目前并没有什么卵用) JS虽然没有类,但可以通过一些方法来模拟类以及实现类的继承. 一切皆对象,还先从对象说起. 1.对象(Object) ECMA-262对对象的定义是:无序属性的集合,其属性可以包含基本值.对象或者函数. 直观点描述,就是由多个键值

How Javascript works (Javascript工作原理) (十五) 类和继承及 Babel 和 TypeScript 代码转换探秘

个人总结:读完这篇文章需要15分钟,文章主要讲解了Babel和TypeScript的工作原理,(例如对es6 类的转换,是将原始es6代码转换为es5代码,这些代码中包含着类似于 _classCallCheck 和 _createClass这样的函数,而这些函数已经在Babel和TypeScript的标准库中预先定义好了,然后进行处理). 顺便温习了Object.create这个方法,  比如有一个obj:{name:'是ho',f:function(){alert(1)}} var a = O

详谈Javascript类与继承

本文将从以下几方面介绍类与继承 类的声明与实例化 如何实现继承 继承的几种方式 类的声明与实例化 类的声明一般有两种方式 //类的声明 var Animal = function () { this.name = 'Animal'; }; //ES6中类的声明 class Animal2 { constructor () { this.name = 'Animal2'; } } 实例化就比较简单,直接用new运算符 new Animall() new Animal2() 这些比较简单,简单介绍一

JavaScript是如何工作的:深入类和继承内部原理 + Babel和TypeScript之间转换

现在构建任何类型的软件项目最流行的方法这是使用类.在这篇文章中,探讨用 JavaScript 实现类的不同方法,以及如何构建类的结构.首先从深入研究原型工作原理,并分析在流行库中模拟基于类的继承的方法. 接下来是讲如何将新的语法转制为浏览器识别的语法,以及在 Babel 和 TypeScript 中使用它来引入ECMAScript 2015类的支持.最后,将以一些在 V8 中如何本机实现类的示例来结束本文. 概述 在 JavaScript 中,没有基本类型,创建的所有东西都是对象.例如,创建一个

javascript“类”与继承总结和回顾-韩烨

Javascipt语法不支持"类"(class)[es6已经支持],但是有模拟类的方法.今天我主要谈谈Javascipt中模拟"类"的方法及js中继承的总结和回顾. js中实现"类"与继承,既是重点,又是难点.很多同学可能都对js中"类"与继承都有所了解,但是深入剖析的时候,感觉力不从心.模棱两可. 下面我们一起来总结一下,巩固提高一下js的基础知识.关于js的基础知识,我在之前写过一个关于js老生常谈之this,constr

JavaScript面向对象轻松入门之继承(demo by ES5、ES6)

继承是面向对象很重要的一个概念,分为接口继承和实现继承,接口继承即为继承某个对象的方法,实现继承即为继承某个对象的属性.JavvaScript通过原型链来实现接口继承.call()或apply()来实现实现继承. 接口继承的实现在ES5中是比较麻烦,在其它OOP语言中一个extends关键字就可以实现,但在ES5中要通过原型链去模拟,非常难理解,对初学者很不友好,并且有好几种接口继承的方式.本文为了对初学者更友好,并不打算让读者了解接口继承的原理,而是直接把接口继承实现方法封装成一个函数,大家只

javascript类式继承

javascript中是没有类这个概念的,但是javascript有它自己的原型机制,我们可以通过原型机制(prototype,constructor)来伪一个类出来,俗称“伪类”. 新函数对象被创建时,会被赋予一个prototype属性,它的值是一个包括constructor属性,且属性值为该新函数的对象,用代码来解释就是: Cat.prototype.constructor = Cat 介绍javascript原型机制的文章博客园有很多,可以自己找来看看哦. 构建伪类的第一步是定义一个构造器

JavaScript 闭包环境很奇特 - 相当于类与实例的关系?!

太阳火神的美丽人生 (http://blog.csdn.net/opengl_es) 本文遵循"署名-非商业用途-保持一致"创作公用协议 转载请保留此句:太阳火神的美丽人生 -  本博客专注于 敏捷开发及移动和物联设备研究:iOS.Android.Html5.Arduino.pcDuino,否则,出自本博客的文章拒绝转载或再转载,谢谢合作. 又一个疑问贴! 不过我相信,问题并不是难在如何解决,最终就是个能解决与不能解决,这很容易! 但当你无法决断是否能否解决,与如何解决的时侯,这才是最

精读JavaScript模式(八),JS类式继承

一.前言 这篇开始主要介绍代码复用模式(原书中的第六章),任何一位有理想的开发者都不愿意将同样的逻辑代码重写多次,复用也是提升自己开发能力中重要的一环,所以本篇也将从“继承”开始,聊聊开发中的各种代码复用模式. 其实在上一章,我感觉这本书后面很多东西是我不太理解的,但我还是想坚持读完,在以后知识逐渐积累,我会回头来完善这些概念,算是给以前的自己答疑解惑. 二.类式继承VS现代继承模式 1.什么是类式继承 谈到类式继承或者类classical,大家都有所耳闻,例如在java中,每个对象都是一个指定