面向对象
通过函数模拟对象的继承
// 定义一个基类函数
function Person(name, age) {
this.name = name;
this.age = age;
}
// 一般将方法写在原型中可以降低内存的占用率
Person.prototype.info = function () {
console.log("姓名:" + this.name + "年龄:" + this.age);
};
// 定义一个学生类函数
function Student(name, age, stuNo) {
Person.call(this, name, age); // 这里指定作用域的 this 是继承的关键
this.stuNo = stuNo; // 自有属性
}
// 定义一个老师类函数
function Teachers(name, age, major) {
Person.call(this, name, age);
this.major = major; //自有属性
}
// 原型重新赋值,实现继承关系(但是实际上这种写法是存在隐患的,
Student.prototype = Person.prototype;
Teachers.prototype = Person.prototype;
/*这里只针对 Student 的原型做了更改*/
// 因为 Student 和 Person 用的都是同一个prototype,当子类Student 重写方法的时候,父类同时也会被改写)
Student.prototype.info = function () {
console.log("学生信息方法的重写");
};
// 实例化
let p1 = new Student("张三", 16, "x1002");
let t1 = new Teachers("老张", 26, "数学");
/*结果可以发现, Teachers 的 info 方法也做了更改*/
console.log(p1.stuNo); // x1002
p1.info(); // 学生信息方法的重写
t1.info(); // 学生信息方法的重写
console.log(Student.info === Person.info); // true
针对上述问题的一些改进
组合继承
// 定义一个基类函数
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.info = function () {
console.log("姓名:" + this.name + "年龄:" + this.age);
};
// 定义一个学生类函数
function Student(name, age, stuNo) {
Person.call(this, name, age); // 这里指定作用域的 this 是继承的关键
this.stuNo = stuNo; // 自有属性
}
// 定义一个老师类函数
function Teachers(name, age, major) {
Person.call(this, name, age);
this.major = major; //自有属性
}
// 这可以算是一个过渡函数
let F = function () {};
F.prototype = Person.prototype;
// 通过这个 new 已经重新开辟了一段内存,这样就断开了原型链上面的联系,同时保留了 父类函数原型上的方法
Student.prototype = new F();
Teachers.prototype = new F();
// 这里让我们的 constructor 重新指向 Student、Teachers
Student.prototype.constructor = Student;
Teachers.prototype.constructor = Teachers;
/*这里只改写Student 上面的info*/
Student.prototype.info = function () {
console.log("学生信息方法的重写");
};
let s1 = new Student("小明", 16, "x22201");
let t1 = new Teachers("老张", 28, "数学");
// 显然这是改写之后的结果
s1.info(); //学生信息方法的重写
// 这是原来的味道
t1.info(); //姓名:老张年龄:28
先来手写一段深拷贝代码
function deepCopy(obj) {
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === "object" && obj[key] != null) {
newObj[key] = deepCopy(obj[key]);
} else {
newObj[key] = obj[key];
}
}
}
return newObj;
}
也完全可以采用深拷贝的方式,完成继承
/*
先说说 序列化出现的一些问题
let obj = { age: 20, test: undefined, fn: function () {} };
// 通过序列化实现深拷贝,但是会丢失 undefined 的值 还有 函数
let obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj)
console.log(obj2)
*/
F.prototype = Person.prototype;
Student.prototype = deepCopy(Person.prototype);
Teachers.prototype = deepCopy(Person.prototype);
Student.prototype.constructor = Student;
Teachers.prototype.constructor = Teachers;
class 语法
class Person {
// 静态 属性不会被实例化继承(但是我们可以通过 Person.eyes 来使用)
static eyes = 2;
constructor(name) {
this.name = name;
}
// 针对 class 语法糖, 方法会自动放置到 prototype 上
info() {
console.log("this person name is " + this.name);
}
}
let p1 = new Person("小敏");
console.log(p1);