JavaScript基础13——面向对象
什么是面向对象?
面向对象(Object Oriented,OO)是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统,交互式界面,应用结构,应用平台,分布式系统,网络管理结构,CAD技术,人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后到产物,是一种高级的编程思想。
面向对象就是一种新的编程模式。
面向对象的特点
封装:不考虑内部实现,只考虑功能实现
继承:从已有对象上,继承出新对象
多态:多种形态,一个功能的不同的应用场景
对象的组成
方法(有归属)----函数(自由的)
属性(有归属)----变量(自由的)
OOA和OOD
OOA面向对象分析:
面向对象分析:将大问题拆分成小问题,并试图用分工协作来完成的思维方式。
OOD面向对象设计:
1.分析模块后,确定职责
大哥招小弟--端茶倒水,点烟捶背捏脚
2.确定耦合关系
确定通信关系,如何交流,暗号
弊端:当耦合达到一定程度时,如果换了一个助理,需要重新耦合,资源消耗太大
高内聚低耦合
3.为OOP做准备
分析角色特性:
我当老师----技术过硬
----讲课技能(口才)
我当销售----沟通技巧(口才)
找到角色共同特性----继承
大量信息的处理和加工困难,打包之后,将内容包含在其中。信息传递速度更快,效率更高
面向对象和面向过程的区别
面向对象--先实现功能,再运行。分工协作,同时发生,解决问题。
面向过程--一边实现,一边运行。效率低下。
面向对象并不是程序员发明的。在程序中我们叫面向对象(OO),在生活中叫分工协作。
构造函数
function CreatPeople(name,age,like){ this.name = name; this.age = age; this.like = like; this.show = function(){ alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like); } } var obj = new CreatPeople("ABC",20,"PHP"); var obj2 = new CreatPeople("QWE",32,"Python"); obj.show(); obj2.show();
构造函数和对象的关系
面向对象----对一个对象进行编程
构造函数----提供一个对象供你编程
通过构造函数,实现面向对象编程
使用Json创建对象
var obj = { name:"admin", age:23, like:"LOL", show:function(){ alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like) } } obj.show()
使用构造函数创建对象
function CreatPeople(name,age,like){ this.name = name; this.age = age; this.like = like; this.show = function(){ alert("我叫"+this.name+",今年"+this.age+"岁,喜欢"+this.like); } } var obj = new CreatPeople("ABC",20,"PHP"); var obj2 = new CreatPeople("QWE",32,"Python"); obj.show(); obj2.show();
原型的概念
在对象中,两个新创建的函数,是不相等的: var obj1 = { fn:function(){ alert(1); } } var obj2 = { fn:function(){ alert(1); } } console.log(obj1.fn == obj2.fn); //false 在构造函数中,同样属于两个新创建的函数,也是不相等的 function Fn(name){ this.name = name; this.show = function(){ alert(this.name); } } var obj1 = new Fn("AAA"); var obj2 = new Fn("BBB"); console.log(obj1.show==obj2.show); //false 此时可以看出构造函数的多次创建会产生多个同名函数,造成冗余太多。 利用原型prototype解决。 function Fn(){} console.log(Fn.prototype); //constructor表示当前的函数属于谁 //__proto__ == [[prototype]],书面用语,表示原型链 var fn1 = new Object(); var fn2 = new Object(); Object.prototype.show = function(){ alert(1); } console.log(fn1.show==fn2.show); //ture
此时,任何一个对象的原型上都有了show方法,由此得出,Object.prototype身上的添加的方法,相当于添加到了所有的Object身上。
为了解决构造函数的冗余问题,我们将属性写在构造函数内,方法写在原型中。这是面向对象的编程格式之一。
面向对象的编程格式之一:
1.属性写在构造函数内;
2.方法写在原型中
3.构造函数中的this指向当前new出来的对象
4.原型方法中的this指向当前原型所属的函数被new出来的对象
在代码中再次看看区别
// 1.创建对象:构造函数 // function Fn(){ // this.xxx = xxxx; // } // var f = new Fn() // 模型,构造器 function Fn(n){ this.name = n; this.show(); } Fn.prototype.show = function(){ console.log(this.name) } var f1 = new Fn("admin"); var f2 = new Fn("root"); // new出来的实例 console.log(f1); console.log(f2); console.log(f2 == f1); console.log(f2.__proto__ == f1.__proto__); console.log(f2.__proto__.show == f1.__proto__.show); f1.show(); f2.show(); // console.dir(Fn); // console.log(Fn.length) // console.log(Fn.name) // console.log(Fn.prototype) // console.log(f1.__proto__) // console.log(f1.__proto__ === Fn.prototype) // // 抽象 // // 具象 // f1.show(); // f2.show(); // console.log(f1.show == f2.show); console.log(f1.abc); // var arr1 = new Array("hello","world"); // var arr2 = new Array("hello","html"); // console.log(arr1); // console.log(arr2); // console.log(arr2 == arr1); // console.log(arr1.length); // console.log(arr2.length); // arr1.push("hello"); // arr2.push("hello"); // console.log(arr1.push == arr2.push); // Array.prototype.hahaha = function(){} // var arr = new Array(); // arr.norepeat() // 为什么要相等?节省内存,减少方法的冗余 // 怎么做?写成公共方法 // 怎么实现? // ↓↓↓↓↓↓↓↓↓ // __proto__:原型链(隐示原型),作用:与自身类型的父级建立连接 // prototype:原型对象(显示原型),只有函数(除了箭头函数)才有,作用:为了给自身被new之后创建出来的实例做父级使用 // 此属性对于函数自身来说,没有用 // 但是这个属性是给函数被new执行创建出的实例,当爸的 // new的原理: // 1.自动创建一个新对象 // 2.改变了函数内部的this,为第一步的新对象 // 3.将第一步创建的新对象的父级,改成new执行函数的prototype // 4.检测函数是否主动返回对象,没有,就返回第一步创建的新对象 // 对象读取属性或方法的原则: // 就近原则:当对象查找自身的属性或方法时,如果自身有,直接使用;如果自身没有,顺着__proto__向上找父级,找到了就使用,没找到,继续向上;直到顶部,还没找到,就抛出undefined;在这个过程中,只要找到了,就停止向上查找。 // 构造函数身上的原型对象身上的方法中的this,依然指向将来构造函数被new出来的实例
面向对象案例——烟火
<!DOCTYPE html> <html> <head> <meta charset = "utf-8"> <title></title> <style> .box {width: 800px;height: 600px;background-color: black;margin: 0 auto;position: relative;} .fire1 {width: 15px;height: 15px;border-radius: 50%;position: absolute;bottom: 0;} .fire2 {width: 10px;height: 10px;border-radius: 50%;position: absolute;} </style> </head> <body> <div class="box"></div> </body> <script> function Fire(obj){ this.x = obj.x; this.y = obj.y; this.cont = obj.parent; this.onoff = obj.onoff; this.start(); } Fire.prototype.start = function(){ // 1.创建烟花给样式 this.div = document.createElement("div"); this.div.className = "fire1"; this.div.style.background = randomColor(); this.div.style.left = this.x + "px"; this.cont.appendChild(this.div); // 开始运动this.transition(); this.transition(); } Fire.prototype.transition = function(){ move(this.div,{top:this.y},()=>{ // 运动,结束后删除 this.div.remove(); // 3创建小烟花this.boom(); this.onoff = this.onoff == 1 ? this.boom1() : this.boom2(); //选择烟花样式 }) } Fire.prototype.boom1 = function(){ // 4.小烟花运动,消失 var num = random(2,3); for(var i = 0;i < num;i++){ let star = document.createElement("div"); star.className = "fire2"; star.style.background = randomColor(); star.style.left = this.x + "px"; star.style.top = this.y + "px"; this.cont.appendChild(star); var l = random(0,this.cont.offsetWidth-star.offsetWidth); var t = random(0,this.cont.offsetHeight-star.offsetHeight); move(star,{left:l,top:t},function(){ star.remove(); }) } } Fire.prototype.boom2 = function(){ // 4.小烟花运动,消失 var num = random(20,35); var r = random(100,200); for(var i = 0;i < num;i++){ let star = document.createElement("div"); star.className = "fire2"; star.style.background = randomColor(); star.style.left = this.x + "px"; star.style.top = this.y + "px"; this.cont.appendChild(star); var l = parseInt(Math.cos(Math.PI/180*(360/num*i))*r)+this.x; var t = parseInt(Math.sin(Math.PI/180*(360/num*i))*r)+this.y; move(star,{left:l,top:t},function(){ star.remove(); }) } } var obox = document.querySelector(".box"); addEvent(obox,"mousemove",function(eve){ var e = eve || window.event; new Fire({ x:e.offsetX, y:e.offsetY, parent:this, onoff:1 }); }) addEvent(obox,"contextmenu",function(eve){ var e = eve || window.event; e.preventDefault(); new Fire({ x:e.offsetX, y:e.offsetY, parent:this, onoff:0 }); }) // 运动 function move(ele,obj,fn){ clearInterval(ele.t); ele.t = setInterval(() => { var onoff = true; for(var i in obj){ var pos = parseInt(getComputedStyle(ele,false)[i]); var speed = (obj[i]-pos)/10; speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); if(pos != obj[i]){ onoff = false; } ele.style[i] = pos + speed + "px"; if(onoff == true){ clearInterval(ele.t); fn && fn(); } } }, 30); } // 范围随机数 function random(max,min){ return Math.round(Math.random()*(max-min)+min); } // 随机颜色 function randomColor(){ return "rgb("+random(0,255)+","+random(0,255)+","+random(0,255)+")"; } // 监听式绑定: function addEvent(ele,eve,cb){ if(ele.addEventListener){ ele.addEventListener(eve,cb); }else if(ele.attachEvent){ ele.attachEvent("on"+eve,cb); //ie }else{ ele["on"+eve] = cb; } } </script> </html>