Javascript OOP之面向对象
程序员文章站
2022-06-13 10:49:40
面向对象程序设计(object-oriented programming,oop)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本...
面向对象程序设计(object-oriented programming,oop)是一种程序设计范型,同时也是一种程序开发的方法。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。——*
一般面向对象包含:继承,封装,多态,抽象
对象形式的继承
浅拷贝
var person = { name: 'allin', age: 18, address: { home: 'home', office: 'office', } sclools: ['x','z'], }; var programer = { language: 'js', }; function extend(p, c){ var c = c || {}; for( var prop in p){ c[prop] = p[prop]; } } extend(person, programer); programer.name; // allin programer.address.home; // home programer.address.home = 'house'; //house person.address.home; // house
从上面的结果看出,浅拷贝的缺陷在于修改了子对象中引用类型的值,会影响到父对象中的值,因为在浅拷贝中对引用类型的拷贝只是拷贝了地址,指向了内存中同一个副本。
深拷贝
function extenddeeply(p, c){ var c = c || {}; for (var prop in p){ if(typeof p[prop] === "object"){ c[prop] = (p[prop].constructor === array)?[]:{}; extenddeeply(p[prop], c[prop]); }else{ c[prop] = p[prop]; } } }
利用递归进行深拷贝,这样子对象的修改就不会影响到父对象。
extenddeeply(person, programer); programer.address.home = 'allin'; person.address.home; // home 利用call和apply继承 function parent(){ this.name = "abc"; this.address = {home: "home"}; } function child(){ parent.call(this); this.language = "js"; } es5中的object.create() var p = { name : 'allin'}; var obj = object.create(o); obj.name; // allin
object.create()作为new操作符的替代方案是es5之后才出来的。我们也可以自己模拟该方法:
//模拟object.create()方法 function mycreate(o){ function f(){}; f.prototype = o; o = new f(); return o; } var p = { name : 'allin'}; var obj = mycreate(o); obj.name; // allin
目前,各大浏览器的最新版本(包括ie9)都部署了这个方法。如果遇到老式浏览器,可以用下面的代码自行部署。
if (!object.create) { object.create = function (o) { function f() {} f.prototype = o; return new f(); }; }
类的继承
object.create() function person(name, age){} person.prototype.headcount = 1; person.prototype.eat = function(){ console.log('eating...'); } function programmer(name, age, title){} programmer.prototype = object.create(person.prototype); //建立继承关系 programmer.prototype.constructor = programmer; // 修改constructor的指向
调用父类方法
function person(name, age){ this.name = name; this.age = age; } person.prototype.headcount = 1; person.prototype.eat = function(){ console.log('eating...'); } function programmer(name, age, title){ person.apply(this, arguments); // 调用父类的构造器 } programmer.prototype = object.create(person.prototype); programmer.prototype.constructor = programmer; programmer.prototype.language = "js"; programmer.prototype.work = function(){ console.log('i am working code in '+ this.language); person.prototype.eat.apply(this, arguments); // 调用父类上的方法 }
封装
命名空间
js是没有命名空间的,因此可以用对象模拟。
var app = {}; // 命名空间app //模块1 app.module1 = { name: 'allin', f: function(){ console.log('hi robot'); } }; app.module1.name; // "allin" app.module1.f(); // hi robot
静态成员
function person(name){ var age = 100; this.name = name; } //静态成员 person.walk = function(){ console.log('static'); }; person.walk(); // static
私有与公有
function person(id){ // 私有属性与方法 var name = 'allin'; var work = function(){ console.log(this.id); }; //公有属性与方法 this.id = id; this.say = function(){ console.log('say hello'); work.call(this); }; }; var p1 = new person(123); p1.name; // undefined p1.id; // 123 p1.say(); // say hello 123
模块化
var modulea; modulea = function() { var prop = 1; function func() {} return { func: func, prop: prop }; }(); // 立即执行匿名函数
prop,func 不会被泄露到全局作用域。或者另一种写法,使用 new
modulea = new function() { var prop = 1; function func() {} this.func = func; this.prop = prop; }
多态
模拟方法重载
arguments属性可以取得函数调用的实参个数,可以利用这一点模拟方法的重载。
function demo(a, b ){ console.log(demo.length); // 得到形参个数 console.log(arguments.length); //得到实参个数 console.log(arguments[0]); // 第一个实参 4 console.log(arguments[1]); // 第二个实参 5 } demo(4, 5, 6); //实现可变长度实参的相加 function add(){ var total = 0; for( var i = arguments.length - 1; i >= 0; i--){ total += arguments[i]; } return total; } console.log(add(1)); // 1 console.log(add(1, 2, 3)); // 7 // 参数不同的情况 function fontsize(){ var ele = document.getelementbyid('js'); if(arguments.length == 0){ return ele.style.fontsize; }else{ ele.style.fontsize = arguments[0]; } } fontsize(18); console.log(fontsize()); // 类型不同的情况 function setting(){ var ele = document.getelementbyid('js'); if(typeof arguments[0] === "object"){ for(var p in arguments[0]){ ele.style[p] = arguments[0][p]; } }else{ ele.style.fontsize = arguments[0]; ele.style.backgroundcolor = arguments[1]; } } setting(18, 'red'); setting({fontsize:20, backgroundcolor: 'green'});
方法重写
function f(){} var f = new f(); f.prototype.run = function(){ console.log('f'); } f.run(); // f f.run = function(){ console.log('fff'); } f.run(); // fff
抽象类
在构造器中 throw new error(''); 抛异常。这样防止这个类被直接调用。
function detectorbase() { throw new error('abstract class can not be invoked directly!'); } detectorbase.prototype.detect = function() { console.log('detection starting...'); }; detectorbase.prototype.stop = function() { console.log('detection stopped.'); }; detectorbase.prototype.init = function() { throw new error('error'); }; // var d = new detectorbase();// uncaught error: abstract class can not be invoked directly! function linkdetector() {} linkdetector.prototype = object.create(detectorbase.prototype); linkdetector.prototype.constructor = linkdetector; var l = new linkdetector(); console.log(l); //linkdetector {}__proto__: linkdetector l.detect(); //detection starting... l.init(); //uncaught error: error
上一篇: 跟爸爸还是跟妈妈
下一篇: 2015年车联网汽车后市场将有更多机会