肥城网站建设推广,vpsputty做网站,phpcms v9企业网站模板:蓝色电子科技公司网站模板,帝国后台网站如何设置自动刷新首写在前面既然是浅谈#xff0c;就不会从原理上深度分析#xff0c;只是帮助我们更好地理解...面向对象与面向过程面向对象和面向过程是两种不同的编程思想#xff0c;刚开始接触编程的时候#xff0c;我们大都是从面向过程起步的#xff0c;毕竟像我一样#xff0c;大家接…写在前面既然是浅谈就不会从原理上深度分析只是帮助我们更好地理解...面向对象与面向过程面向对象和面向过程是两种不同的编程思想刚开始接触编程的时候我们大都是从面向过程起步的毕竟像我一样大家接触的第一门计算机语言大概率都是C语言C语言就是一门典型的面向过程的计算机语言。面向过程主要是以动词为主解决问题的方式是按照顺序一步一步调用不同的函数。面向对象是以名词为主将问题抽象出具体的对象而这个对象有自己的属性和方法在解决问题的时候是将不同的对象组合在一起使用。//面向过程装大象1.开(冰箱)2.(大象)装进(冰箱)3.关(冰箱)//面向对象装大象1. 冰箱.开门()2. 冰箱.装进(大象)3. 冰箱.关门()从这个例子可以看出面向对象是以主谓为主将主谓堪称一个一个的对象然后对象有自己的属性和方法。面向对象是以功能来划分问题的而不是步骤。功能上的统一保证了面向对象设计的可扩展性解决了代码重用性的问题。这也是在漫长的程序设计的发展过程中得到的验证结果面向对象的编程思想较之于面向过程较好一点封装面向对象有封装、继承和多态三大特性。封装就是把事物封装成类隐藏事物的属性和方法的实现细节仅对外公开接口。在ES5中并没有class的概念但是由于js的函数级作用域(函数内部的变量函数外访问不到)。所以我们可以模拟class。在es5中类其实就是保存了一个函数的变量这个函数有自己的属性和方法。将属性和方法组成一个类的过程就是封装。1.通过构造函数添加JavaScript提供了一个构造函数(Constructor)模式用来在创建对象时初始化对象。构造函数其实就是普通的函数只不过有以下的特点①首字母大写(建议构造函数首字母大写即使用大驼峰命名非构造函数首字母小写)②内部使用this③使用new生成实例通过构造函数添加属性和方法实际上也就是通过this添加的属性和方法。因为this总是指向当前对象的所以通过this添加的属性和方法只在当前对象上添加是该对象自身拥有的。所以我们实例化一个新对象的时候this指向的属性和方法都会得到相应的创建也就是会在内存中复制一份这样就造成了内存的浪费。function Cat(name,color){this.name name;this.color color;this.eat (() {console.log(fish!)})}//生成实例var cat1 new Cat(tom, gray)通过this定义的属性和方法我们实例化对象的时候斗湖重新复制一份2.通过原型prototype封装在类上通过this的方式添加属性和方法会导致内存浪费的现象有什么办法可以让实例化的类所使用的属性和方法 直接使用指针 指向同一个属性和方法。这就是原型的方法JavaScript规定每一个构造函数都有一个prototype属性指向另一个对象。这个对象的所有属性和方法都会被构造函数的实例继承。也就是说对于那些不变的属性和方法我们可以直接将其添加在类的prototype对象上。function Cat(name,color){this.name name;this.color color;}Cat.prototype.type 英短;Cat.prototype.eat ( () {alert(fish!)} )//生成实例var cat1 new Cat(Tom, gray);var cat2 new Cat(Kobe, purple);console.log(cat1.type); //英短cat2.eat(); //fish!这时所有实例的type属性和eat()方法其实都是同一个内存地址指向prototype对象因此就提高了运行效率。但是这样做也有弊端因为实例化的对象的原型都是指向同一内存地址改动其中一个对象的属性可能会影响到其他的对象es6中的类和封装es6声明一个类①构造器构造器内创建自有属性②方法声明类实例具有的方法class Cat {//等价于Cat构造器constructor(name) {this.name name;}//更加简单的声明类的内部函数//等价于 Cat.prototype.eateat() {console.log(fish!);}}//生成实例var cat1 new Cat(tom);cat1.eat(); //fish!console.log(cat1 instanceof Cat); //trueconsole.log(cat1 instanceof Object); //trueconsole.log(typeof Cat); //functionconsole.log(typeof Cat.prototype.eat); //function从上面class声明的Cat为例Cat类是一个具有构造函数行为的函数其中内部方法eat实际上就是Cat.prototype.eat()所以说es6的class封装类本质上是es5实现方式的语法糖最主要的区别在于class类的属性是不可重新赋值和不可枚举的Cat.prototype就是一个只读属性class和自定义类型的区别(1)class的声明不会提升与let类似(2)class的声明自动运行于严格模式之下(3)class声明的方法不可枚举(4)class的内部方法没有 constructor 属性无法new(5)调用class的构造函数必须new(6)class内部方法不能同名class类的使用class作为js中的一级公民可以被当作值来直接使用//1.类名作为参数传入函数function createObj (ClassName) {return new ClassName()}//2.立即执行实现单例模式let cat1 new class{constructor (name) {this.name name}eat() {console.log(fish!)}}(tom”)cat1.eat() //fish!继承继承就是子类可以使用父类的所有功能并且对这些功能进行扩展。继承的过程就是从一般到特殊的过程。1.类式继承所谓的类式继承就是使用的原型的方式将方法添加在父类的原型上然后子类的原型是父类的一个实例化对象。//声明父类var SuperClass function(){let id 1;this.name [java];this.superValue function() {console.log(this is superValue!)}}//为父类添加共有方法SuperClass.prototype.getSuperValue function () {return this.superValue();};//声明子类var SubClass function() {this.subValue (() {console.log(this is subValue!)})}//继承父类SubClass.prototype new SuperClass();//为子类添加共有方法SubClass.prototype.getSubValue function() {return this.subValue()}//生成实例var sub1 new SubClass();var sub2 new SubClass();sub1.getSuperValue(); //this is superValue!sub1.getSubValue(); //this is subValue!console.log(sub1.id); //undefinedconsole.log(sub1.name); //[java]sub1.name.push(php);console.log(sub1.name); //[java, php]console.log(sub2.name); //[java, php]其中最核心的是SubClass.prototype new SuperClass();类的原型对象prototype对象的作用就是为类的原型添加共有的方法的但是类不能直接访问这些方法只有将类实例化之后新创建的对象复制了父类构造函数的属性和方法并将原型 proto 指向了父类的原型对象。这样子类就可以访问父类的属性和方法同时父类中定义的属性和方法不会被子类继承。but使用类继承的方法如果父类的构造函数中有引用数据类型就会在子类中被所有实例共用因此一个子类的实例如果更改了这个引用数据类型就会影响到其他子类的实例。构造函数继承为了克服类继承的缺点才有了构造函数继承构造函数继承的核心思想就是SuperClass.call(this, id),直接改变this的指向使通过this创建的属性和方法在子类中复制一份因为是单独复制的所以各个实例化的子类互不影响。but会造成内存浪费的问题//构造函数继承//声明父类var SuperClass function(id){var name javathis.languages [java, php, ruby];this.id id}//声明子类var SubClass function(id){SuperClass.call(this, id)}//生成实例var sub1 new SubClass(1);var sub2 new SubClass(2);console.log(sub2.id); // 2console.log(sub1.name); //undefinedsub1.languages.push(python);console.log(sub1.languages); // [java, php, ruby, python]console.log(sub2.languages); // [java, php, ruby]组合式继承组合式继承是汲取了两者的优点既避免了内存浪费又使得每个实例化的子类互不影响。//组合式继承//声明父类var SuperClass function(name){this.languages [java, php, ruby];this.name name;}//声明父类原型方法SuperClass.prototype.showLangs function () {console.log(this.languages);}//声明子类var SubClass function(name){SuperClass.call(this, name)}//子类继承父类(链式继承)SubClass.prototype new SuperClass();//生成实例var sub1 new SubClass(python);var sub2 new SubClass(go);sub2.showLangs(); //[java, php, ruby]sub1.languages.push(sub1.name);console.log(sub1.languages);//[java, php, ruby, python]console.log(sub2.languages);//[java, php, ruby]but警告组合式继承方法固然好但是会导致一个问题父类的构造函数会被创建两次(call()的时候一遍new的时候又一遍)寄生组合继承组合式继承的缺点的关键是 父类的构造函数在类继承和构造函数继承的组合形式被创建了两边但是在类继承中我们并不需要创建父类的构造函数我们只要子类继承父类的原型即可。所以我们先给父类的原型创建一个副本然后修改子类的 constructor 属性最后在设置子类的原型就可以了//原型式继承//原型式继承其实就是类式继承的封装实现的功能返回一个实例该实例的原型继承了传入的o对象function inheritObject(o) {//声明一个过渡函数function F() {}//过渡对象的原型链继承父对象F.prototype o;//返回一个过渡对象的实例该实例的原型继承了父对象return new F();}//寄生式继承//寄生式继承就是对原型继承的第二次封装使得子类的原型等于父类的原型。并且在第二次封装的过程中对继承的对象进行了扩展function inheritPrototype(subClass, superClass){//复制一份父类的原型保存在变量中使得p的原型等于父类的原型var p inheritObject(superClass.prototype);//修正因为重写子类原型导致子类constructor属性被修改p.constructor subClass;//设置子类的原型subClass.prototype p;}//定义父类var SuperClass function(name) {this.name name;this.languages [java, php, python]}//定义父类原型方法SuperClass.prototype.showLangs function() {console.log(this.languages);}//定义子类var SubClass function(name) {SuperClass.call(this,name)}inheritPrototype(SubClass, SuperClass);var sub1 new SubClass(go);es6中的继承class SuperClass {constructor(name) {this.name namethis.languages [java, php, go];}showLangs() {console.log(this.languages);}}class SubClass extends SuperClass {constructor(name) {super(name)}//重写父类中的方法showLangs() {this.languages.push(this.name)console.log(this.languages);}}//生成实例var sub new SubClass(韩二虎);console.log(sub.name); //韩二虎sub.showLangs(); //[java, php, go, 韩二虎]多态多态实际上是不同对象作用与同一操作产生不同的效果。多态的思想实际上是把 “想做什么” 和 “谁去做” 分开。多态的好处在于你不必再向对象询问“你是什么类型”后根据得到的答案再去调用对象的某个行为。你尽管去调用这个行为就是了其他的一切可以由多态来负责。规范来说多态最根本的作用就是通过吧过程化的条件语句转化为对象的多态性从而消除这些条件分支语句。由于JavaScript中提到的关于多态的详细介绍并不多这里简单的通过一个例子来介绍就好//非多态var hobby function(animal){if(animal cat){cat.eat()}else if(animal dog){dog.eat()}}var cat {eat: function() {alert(fish!)}}var dog {eat: function() {alert(meat!)}}console.log(123);hobby(cat); //fish!hobby(dog); //meat!从上面的例子能看到虽然 hobby 函数目前保持了一定的弹性但这种弹性很脆弱的一旦需要替换或者增加成其他的animal必须改动hobby函数继续往里面堆砌条件分支语句。我们把程序中相同的部分抽象出来那就是吃某个东西。然后再重新编程。//多态var hobby function(animal){if(animal.eat instanceof Function){animal.eat();}}var cat {eat: function() {alert(fish!)}}var dog {eat: function() {alert(meat!)}}现在来看这段代码中的多态性。当我们向两种 animal 发出 eat 的消息时会分别调用他们的 eat 方法就会产生不同的执行结果。对象的多态性提示我们“做什么” 和 “怎么去做”是可以分开的这样代码的弹性就增强了很多。即使以后增加了其他的animalhobby函数仍旧不会做任何改变。//多态var hobby function(animal){if(animal.eat instanceof Function){animal.eat();}}var cat {eat: function() {alert(fish!)}}var dog {eat: function() {alert(meat!)}}var aoteman {eat: function(){alert(lil-monster!)}}hobby(cat); //fish!hobby(dog); //meat!hobby(aoteman); //lil-monster!快乐面向对象