OOP 之面向对象

发布于 2024-11-06 11:11:36 字数 7193 浏览 4 评论 0

一般面向对象包含:继承,封装,多态,抽象

对象形式的继承


浅拷贝


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
};
}(); // 立即执行匿名函数

多态


模拟方法重载


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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

栀子花开つ

暂无简介

0 文章
0 评论
22 人气
更多

推荐作者

玍銹的英雄夢

文章 0 评论 0

我不会写诗

文章 0 评论 0

十六岁半

文章 0 评论 0

浸婚纱

文章 0 评论 0

qq_kJ6XkX

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文