您好、欢迎来到现金彩票网!
当前位置:ds视讯 > 封装类 >

什么是javascript封装封装的方法有几种

发布时间:2019-08-02 03:15 来源:未知 编辑:admin

  可选中1个或多个下面的关键词,搜索相关资料。也可直接点“搜索资料”搜索整个问题。

  1【专注:Python+人工智能Java大数据HTML5培训】 2【免费提供名师直播课堂、公开课及视频教程】 3【地址:北京市昌平区三旗百汇物美大卖场2层,微信公众号:yuzhitc】

  JS虽然是一个面向对象的语言,但是不是典型的面向对象语言。Java/C++的面向对象是object - class的关系,而JS是object - object的关系,中间通过原型prototype连接,父类和子类形成一条原型链。本文通过分析JS的对象的封装,再探讨正确实现继承的方式,然后讨论几个问题,最后再对ES6新引入的类class关键字作一个简单的说明。

  JS的类其实是一个函数function,由于不是典型的OOP的类,因此也叫伪类。理解JS的类,需要对JS里的function有一个比较好的认识。首先,function本身就是一个object,可以当作函数的参数,也可以当作返回值,跟普通的object无异。然后function可以当作一个类来使用,例如要实现一个String类

  第一行声明了一个MyString的函数,得到一个MyString类,同时这个函数也是MyString的构造函数。第5行new一个对象,会去执行构造函数,this指向新产生的对象,第2行给这个对象添加一个content的属性,然后将新对象的地址赋值给name。第6行又去新建一object,注意这里的this指向了新的对象,因此新产生的content和前面是不一样的。

  上面的代码在浏览器运行有一点问题,因为这段代码是在全局作用域下运行,定义的name变量也是全局的,因此实际上执行var name = new MyString()等同于= new MyString(),由于name是window已经存在的一个变量,作为window.open的第二个参数,可用来跨域的时候传数据。但由于window.name不支持设置成自定义函数的实例,因此设置无效,还是保持默认值:值为[object Object]的String。解决办法是把代码的运行环境改成局部的,也就是说用一个function包起来:

  所以从此处看到,代码用一个function包起来,不去污染全局作用域,还是挺有必要的。接下来,回到正题。

  JS里的每一个function都有一个prototype属性,这个属性指向一个普通的object,即存放了这个object的地址。这个function new出来的每个实例都会被带上一个指针(通常为__proto__)指向prototype指向的那个object。其过程类似于:

  可以看出在JS里,将类的方法放在function的prototype里面,它的每个实例都将获得类的方法。

  这样就实现了基本的封装——类的属性在构造函数里定义,如MyString的content;而类的方法在函数的prototype里添加,如MyString的toString方法。

  这个时候,考虑一个基础的问题,为什么在原型上添加的方法就可以被类的对象引用到呢?因为JS首先会在该对象上查找该方法,如果没有找到就会去它的原型上查找。例如执行name.toString(),第一步name这个object本身没有toString(只有一个content属性),于是向name的原型对象查找,即__proto__指向的那个object,发现有toString这个属性,因此就找到了。

  MyString的__proto__的指针,指向Function的prototype,通过浏览器的调试功能,可以看到,这个原型就是Object的原型,如下图所示:

  因为Object是JS里面的根类,所有其它的类都继承于它,这个根类提供了toString、valueOf等6个方法。

  注意上面的继承方法是错误的,这样只是简单的将UString的原型指向了MyString的原型,即UString和MyString使用了相同的原型,子类UString增删改原型的方法,MyString也会相应地变化,另外一个继承MyString如AsciiString的类也会相应地变化。依照上文分析,应该是让UString的原型里的的__proto__属性指向MyString的原型,而不是让UString的原型指向MyString。也就是说,得让UString有自己的独立的原型,在它的原型上添加一个指针指向父类的原型:

  因为__proto__不是一个标准的语法,在有些浏览器上是不可见的,如果在Firefox上运行上面这段代码,Firefox会给出警告:

  代码第2行,定义一个临时的function,第3行让这个function的原型指向父类的原型,第4行返回一个实例,这个实例的__proto__就指向了父类的prototype,第7行再把这个实例赋值给子类的prototype。继承的实现到这里基本上就完成了。

  这个constructor的作用就在于,可在原型里面调用构造函数,例如给MyString类增加一个copy拷贝函数:

  所以实现继承后需要加多一步操作,将子类UString原型里的constructor指回它自己:

  第一个是子类构造函数里如何调用父类的构造函数,直接把父类的构造函数当作一个普通的函数用,同时传一个子类的this指针:

  第二个问题是私有属性的实现,在最开始的构造函数里定义的变量,其实例是公有的,可以直接访问,如下:

  但是典型的面向对象编程里,属性应该是私有的,操作属性应该通过类提供的方法/接口进行访问,这样才能达到封装的目的。在JS里面要实现私有,得借助function的作用域:

  但是这样的一个问题是,必须将函数的定义放在构造函数里,而不是之前讨论的原型,导致每生成一个实例,就会给这个实例添加一个一模一样的函数,造成内存空间的浪费。所以这样的实现是内存为代价的。如果产生很多实例,内存空间会大幅增加,这个问题是不可忽略的,因此在JS里面实现属性私有不太现实,即使在ES6的class语法也没有实现。但是可以给类添加静态的私有成员变量,这个私有的变量为类的所有实例所共享,如下面的案例:

  上面的例子使用了类的静态变量,给每个worker产生唯一的id。同时这个id是不允许worker实例直接修改的。

  第三个问题是虚函数,在JS里面讨论虚函数是没有太大的意义的。虚函数的一个很大的作用是实现运行时的动态,这个运行时的动态是根据子类的类型决定的,但是JS是一种弱类型的语言,子类的类型都是var,只要子类有相应的方法,就可以传参“多态”运行了。比强类型的语言如C++/Java作了很大的简化。

  从输出的结果来看,新的class还是没有实现属性私有的功能,见第27行。并且从第26行看出,所谓的class其实就是编译器帮我们实现了上面复杂的过程,其本质是一样的,但是让代码变得更加简化明了。一个不同点是,多了static关键字,直接用类名调用类的函数。ES6的支持度还不高,最新的chrome和safari已经支持class,firefox的支持性还不太好。

  最后,虽然一般的网页的JS很多都是小工程,看似不需要封装、继承这些技术,但是如果如果能够用面向对象的思想编写代码,不管工程大小,只要应用得当,甚至结合一些设计模式的思想,会让代码的可维护性和扩展性更高。所以平时可以尝试着这样写。

http://romanyk.net/fengzhuanglei/778.html
锟斤拷锟斤拷锟斤拷QQ微锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷微锟斤拷
关于我们|联系我们|版权声明|网站地图|
Copyright © 2002-2019 现金彩票 版权所有