javascript面向对象编程

本文深入探讨JavaScript面向对象编程,包括封装、继承、多态等核心概念,并通过实例讲解如何利用构造函数、原型链等方式实现面向对象编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于javascript要不要使用面向对象编程,每个人都会有自己的看法。如果是在后端使用javascript,那出于多方面的原因都会使用面向对象编程。但如果是作为浏览器的脚本语言,不同的人有不同的看法。
有些人觉得javascript更偏向于一门函数式语言。有些人觉得javascript要对dom进行频繁的操作,不适合面向对象编程。但是不同的公司有不同的语言规范,为了代码可读性,也为了更好的合作,有时候就必须进行面向对象编程。

面向对象的特性

面向对象的三大主要特性就是继承、封装、多态。
由于javascript没有真正意义上的class(类),因此在实现面向对象编程的过程中与其他语言有些不一样(比如我们较为熟悉的java)。

封装

我参考了阮一峰的博文,感兴趣的可以直接看原文:Javascript 面向对象编程(一):封装
在这里还需要先搞清楚几个词语:原型,实例,字面量。

原型

原型是一个对象,其他对象可以通过它实现属性继承。每一个对象都可以成为原型。
可以参考这篇文章:理解JavaScript原型

实例

在面向对象的编程中,通常把用类创建对象的过程称为实例化,创建出来的就叫实例。当然javascript没有类,却有类似类的存在。

字面量

在JavaScript中,可以通过类的实例化来创建对象,也可以使用 对象字面量 直接创建对象。
比如:

var people={
name:"xiaoming",
age:20
}

就是用对象字面量直接创建了people这个对象。

封装

如上所示,如果用字面量的方法进行封装

var people={
name:"",
age=""

根据people这个作为原型来实例化两个实例

var people1={};
people1.name="xiaoming";
people1.age="22";

var people2={};
people2.name="xiaofang";
people2.age="23";

可以看出这样的方法既浪费代码,实例与原型之间也看不出有什么联系。


接下来我们用构造函数的方法:

function people(name,age){
    this.name=name;
    this.age=age;
}

var people1=new people("小明",22);
var people2=new people("小芳",23);
alert(people1.name);//小明
alert(people2.age);//23

用了构造函数,感觉一切都是那么完美了,但是问题还是存在。

function people(name,age){
    this.name=name;
    this.age=age;
    height=180;
    sex="男";
    ability=function(){alert("花钱")};
}

var people1=new people("小明",22);
var people2=new people("小芳",23);
alert(people1.name);//小明
alert(people2.age);//23
alert(people1.sex);//男
alert(people2.height);//180

可以看出,每次我新建一个实例,这些一样的属性会被重新创建一遍,一次次地开辟新的内存空间,浪费可想而知。
于是乎,javascript发明了一个prototype的属性。
Javascript规定,每一个构造函数都有一个prototype属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
这意味着,我们可以把那些不变的属性和方法,直接定义在prototype对象上。

function people(name,age){
    this.name=name;
    this.age=age;
}
people.prototype.height=180;
people.prototype.sex="男";
var people1=new people("小明",22);
var people2=new people("小芳",23);
alert(people1.name);//小明
alert(people2.age);//23
alert(people1.height);//180
alert(people2.sex);//男

这样子一些一样的属性都是继承而来,而不是重新创建的。
当然具体用哪个还是看情况的。

继承

构造函数继承

function people(){};
people.prototype.say=function(){
    alert("hello");
}
function student(){};
student.prototype=new people();

这样就实现了继承。可以创建实例进行试验。

var s=new student();
s.say();//hello

可以看到实现了继承。
那如果继承的元素拥有好饿被继承的元素一样的属性呢?

function people(){};
people.prototype.say=function(){
    alert("hello");
}
function student(){};
student.prototype=new people();
student.protoype.say=function(){
    alert("world");
var s=new student();
s.say();//world

可以看到实现的是继承者的自有属性。这里其实是重写了父类的方法。
那要使用父类的方法呢?

student.prototype=new people();
var supersay=student.prototype.say;
student.prototype.say=function(){
    supersay.call(this);
    alert("world");
}
var s=new student();
s.say();//hello world

带参数的也是一样。

function people(name){
    this._name=name;
};
people.prototype.say=function(){
    alert("hello"+this._name);
}
function student(name){
    this._name=name;
};
student.prototype=new people();
var supersay=student.prototype.say;
student.prototype.say=function(){
    supersay.call(this);
    alert("world"+this._name);
}
var s=new student("xiaoming");
s.say();//world

非构造函数继承

如果不使用构造函数的话,要实现继承可以使用对象的传递。

function person(){
    var _this={};
    _this.sayhello=function(){
        alert("hello");
    }
    return _this;
}
function student(){
    var _this=person();
    return _this;
}
var s=student();
s.sayhello();

这里的student的_this完全继承了person这个对象,因此拥有person里的属性和方法。
这个方式也可以进行父类的重写。

function person(){
    var _this={};
    _this.sayhello=function(){
        alert("hello");
    }
    return _this;
}
function student(){
    var _this=person();
    _this.sayhello=function(){
        alert("hi");
    }
    return _this;
}
var s=student();
s.sayhello();

要使用父类的方法也是一样的,用call或apply。

function person(){
    var _this={};
    _this.sayhello=function(){
        alert("hello");
    }
    return _this;
}
function student(){
    var _this=person();
    var supersay=_this.sayhello;
    _this.sayhello=function(){
        supersay.call(this);
        alert("hi");
    }
    return _this;
}
var s=student();
s.sayhello();

传参和闭包与构造函数的继承是一样的。

信息的封装(闭包)

闭包的形式:

(function(){
    var n="xiaofang";
    function people(name){
    this._name=name;
};
people.prototype.say=function(){
    alert("hello"+this._name+n);
}
}())

即用个大括号把内容包起来,这个时候定义的n就不能被外界取到。比如:

(function(){
    var n="xiaofang";
    function people(name){
    this._name=name;
};
people.prototype.say=function(){
    alert("hello"+this._name+n);
}
}())
function student(name){
    this._name=name;
};
student.prototype=new people();
var supersay=student.prototype.say;
student.prototype.say=function(){
    supersay.call(this);
    alert("world"+this._name);
}
var s=new student("xiaoming");
s.say();//n值无法取到
(function(){
    var n="xiaofang";
    function people(name){
    this._name=name;
};
people.prototype.say=function(){
    alert("hello"+this._name+n);
}
window.people=people;
}())

把主体赋给顶级的window,就可以执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值