什么是面向对象
面向对象是一种编程思想,我们要通过类和对象的语法,实现面向对象编程。
使用面向对象思想编程后,具有继承、封装、多态的特点。
还是讲到了构造函数
来看代码
//创建人的构造函数
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.showName = function(){
alert("我叫" + this.name);
}
Person.prototype.showSex = function(){
alert("我是" + this.sex + '的');
}
// 创建一个白领类 继承Person所有属性和方法
function Worker(name, sex, job){
//继承属性 构造函数的伪装
Person.call(this, name, sex);//在这里继承到了Person的属性
this.job = job;
}
//继承方法 原型链
for(var i in Person.prototype){//通过for in去遍历数组
Worker.prototype[i] = Person.prototype[i];//给Woeler添加Person的内容
}
Worker.prototype.showJob = function(){//给Woeler添加showJob方法
alert("我是做" + this.job + "的");
}
//最后输出下结果
var w1 = new Worker("blue", '男', "程序员");
w1.showName();
w1.showSex();
w1.showJob();
var p1 = new Person("red", '女');
p1.showName();
p1.showSex();
alert(p1.showJob);
这里有个问题是对象是引用数据类型
引用数据类型的问题是我们拿到的是地址,实际数据存储在数据存储端。
直接改数据会有问题。
var obj1 = {
a: 10,
b: 20,
c: 30
}
var obj2 = obj1;
obj2.d = 40;
console.log(obj1);
上面的输出结果两个都被改了
var obj1 = {
a: 10,
b: 20,
c: 30
}
var obj2 = {};
for(var i in obj1){
obj2[i] = obj1[i];
}
obj2.d = 40;
console.log(obj1);
但这个样子吧数据一个一个附进去
obj1就没有改变,依然是10.20.30
现在我们谈一谈多态
如果子一级构造函数,重写父一级继承下来的方法,这个方法只在子一级生效,父一级不受影响的。
同一件事情两个侧重:
继承:更加侧重于,从父级继承下来的属性和方法。
多态:更加侧重于,在子级拓展或重写的属性和方法。
function Father(name, sex){
this.name = name;
this.sex = sex;
}
Father.prototype.run = function(){//通过prototype给Father添加run
alert("跑的特别快,年轻的时候做过邮递员");
}
function Son(name, sex){//下面的三种方法皆可以给Son继承Father的元素
// Father.call(this, name, sex);
Father.apply(this, [name, sex]);
// Father.bind(this)(name, sex);
}
//原型链
for(var i in Father.prototype){
Son.prototype[i] = Father.prototype[i];
}
//重写父一级继承的方法
Son.prototype.run = function(){//多态,重写
alert("很能跑,去了田径队,拿了全国冠军");
}
var s1 = new Son("小明", '男');
s1.run();//很能跑,去了田径队,拿了全国冠军
var f1 = new Father("大明", '男');
f1.run();//跑的特别快,年轻的时候做过邮递员
ECMA6类
还有新的问题
上篇文章说到ECMA6之前我们一直用上述方法去做类
那么ECMA6出了类我们应该怎么做呢
先之前的代码
//声明
function Iphone(color, size){
this.color = color;
this.size = size;
}
//添加show
Iphone.prototype.show = function(){
alert(`你选择了${this.color}颜色的,存储大小为${this.size}GB Iphone手机`);
}
//new
var iphone8 = new Iphone("玫瑰金", 128);
iphone8.show();
ECMA6 类的语法
//声明
class Iphone{//class
constructor(color, size){//constructor元素
this.color = color;
this.size = size;
}
show(){//方法
alert(`你选择了${this.color}颜色的,存储大小为${this.size}GB Iphone手机`);
}
}
var iphone8 = new Iphone("玫瑰金", 128);
iphone8.show();
看起来确实是煎蛋了不少,但明显的兼容问题。
那么我们继续说继承的问题
class Iphone{
constructor(color, size){
this.color = color;
this.size = size;
}
show(){
alert(`你选择了${this.color}颜色的,存储大小为${this.size}GB Iphone手机`);
}
}
class IphoneX extends Iphone{//IphoneX继承Iphone
constructor(color, size, type){
super(color, size);
this.type = type;
}
showSelf(){
alert(`我选择是是${this.type}的手机`);
this.show();
}
}
var iphone8 = new Iphone("玫瑰金", 128);
iphone8.show();//你选择了玫瑰金颜色的,存储大小为128GB Iphone手机
var iphoneXsMax = new IphoneX("黑色", 256, "xsMax");
iphoneXsMax.showSelf();//我选择是是xsMax的手机//你选择了黑色颜色的,存储大小为256GB Iphone手机
还有关于这套代码有很多细节拓展知识,进阶看这里,注释有详细解释:
三个继承方法
_ _ proto _ _(注意两边是两个杠,但因为这个浏览器编辑器里两个杠是标签,所以我加了空格。)
//创建人的构造函数
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.showName = function(){
alert("我叫" + this.name);
}
Person.prototype.showSex = function(){
alert("我是" + this.sex + '的');
}
// 创建一个白领类 继承Person所有属性和方法
function Worker(name, sex, job){
//继承属性 构造函数的伪装
Person.call(this, name, sex);
this.job = job;
}
//三种继承的地方法 (原型链/new/Object.create)
//1、继承方法 原型链
//for(var i in Person.prototype){
// Worker.prototype[i] = Person.prototype[i];
//}
//2、直接通过调用构造函数继承
// Worker.prototype = new Person();
//3、通过Object.create继承
Worker.prototype = Object.create(Person.prototype);
Worker.prototype.showJob = function(){
alert("我是做" + this.job + "的");
}
// 【注】通过构造函数,构造出来的对象,有一个叫做__proto__的属性。
// 这个属性,指向,构造出来这个对象的构造函数的prototype。
var w1 = new Worker("blue", '男', "程序员");
/*w1.showName();
w1.showSex();
w1.showJob();*/
alert(w1.__proto__.showJob === Worker.prototype.showJob);
var p1 = new Person("red", '女');
/*p1.showName();
p1.showSex();
alert(p1.showJob);*/
alert(w1.__proto__ === p1.__proto__);