JavaScript面向对象
Posted 还是不会呀
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript面向对象相关的知识,希望对你有一定的参考价值。
javascript面向对象(四)
原型赋值继承
在上篇文章中,借用构造函数方法实现继承还是存在弊端:父构造函数多次调用,而且在将父类实例传给子类原型对象时,里面的变量是会额外存在一份的。
那么可以这样:
function Person(name) {
this.name = name;
}
Person.prototype.sleeping = function () {
console.log(this.name + "在睡觉~");
};
function Student(sno, name) {
Person.call(this, name);
this.sno = sno;
}
// 直接子类的原型对象指向父类的原型对象
Student.prototype = Person.prototype;
Object.defineProperty(Student.prototype, "constructor", {
configurable: true,
enumerable: false,
writable: true,
value: Student,
});
Student.prototype.studying = function () {
console.log(this.name + "在学习~");
};
var stu = new Student(2021, "fzb");
console.log(stu); // Student { name: 'fzb', sno: 2021 }
stu.sleeping(); // fzb在睡觉~
stu.studying(); // fzb在学习~
表面上看上去没用问题,但是如果许多子类继承自同一个父类,那么在子类原型上加的方法或属性,将会被其他子类所共享,这样父类的原型对象会越来越大,这样也显然是不可以的。
那接着往下看~~~
寄生组合式继承
原理就是子类的原型指向另一个新的对象,但是这个对象的原型指向的是父类的原型对象
,这样子类以后再其原型上加方法,继承自相同父类的子类,是无法共享这个方法的。
在得出最终的方案之前,先来认识一下 原型式继承和寄生式寂继承
原型式继承
这个方法由道格拉斯提出并推广。
创建一个新的对象,使这个对象的原型指向指定的对象。
道格拉斯提出的原始方案:
var obj = {
name: "fzb",
age: 21,
};
// 问题: info是一个对象,但是这个对象的原型要指向obj
function createObjectrue(o) {
function Foo() {}
Foo.prototype = o;
return new Foo();
}
var info = createObjectrue(obj);
console.log(info.age); // 21
随着JS发展,有了更加直接的操作方法:
Object.setPrototypeOf
function createObjectrue(o) {
var newObj = {};
Object.setPrototypeOf(newObj, o);
return newObj;
}
Object.create
function createObjectrue(o) {
var newObj = Object.create(o);
return newObj;
}
寄生式继承
也是由道格拉斯提出,寄生式继承融合了原型式继承和工厂模式。
因为由原型式继承创造出来的对象,若想给创建出来的对象,批量添加方法或者属性,那是非常麻烦的,能不能再创建时就给加上去呢?
function createObject(o) {
function Foo() {}
Foo.prototype = o;
return new Foo();
}
// 批量创建对象时,加入studying方法
function createStudent(o) {
var newObj = createObject(o);
newObj.studying = function () {
console.log("在学习~");
};
return newObj;
}
缺陷:因为具有工厂模式,也就有着工厂模式的缺点。
- 创建出来的对象是不知道具体的类型的
- 批量创建的对象,添加的方法是在每个对象本身上的,创建对象过多,会大量消耗内存
原型式继承和寄生式继承是在对象层面的,借用其中的思想,拓展到类上。
寄生组合式继承的实现
例子
function Person(name) {
this.name = name;
}
Person.prototype.sleeping = function () {
console.log("在睡觉~");
};
// 子类构造函数的prototype指向创建的新对象,新对象的隐式原型指向父构造函数的原型对象
// 一个子类继承父类就调用次方法,使子类在原型对象上添加方法不会相互共享
function inhertPrototype(subType, supType) {
// 也可以用文章上方提到的方法,这里我直接使用 Object.create 了
subType.prototype = Object.create(supType);
Object.defineProperty(subType.prototype, "constructor", {
configurable: true,
enumerable: false,
writable: true,
value: subType,
});
}
function Teacher(subject, name) {
Person.call(this, name);
this.subject = subject;
}
inhertPrototype(Teacher, Person);
Teacher.prototype.teaching = function () {
console.log("在教书~");
};
function Student(sno, name) {
Person.call(this, name);
this.sno = sno;
}
inhertPrototype(Student, Person);
Student.prototype.studying = function () {
console.log("在学习~");
};
// 测试
const teacher = new Teacher("前端", "teacher");
const student = new Student(2021, "fzb");
teacher.teaching();
student.studying();
console.log(teacher.__proto__ === student.__proto__); // false
console.log(teacher.__proto__.__proto__ === student.__proto__.__proto__); // true
// student.teaching(); // 报错
// teacher.studying(); // 报错
内存图
简便方法
但是思想却是一样的,
Object.setPrototypeOf(Teacher.prototype, Person.prototype);
Object.setPrototypeOf(Student.prototype, Person.prototype);
利用原本的原型对象,手动改掉原型对象上隐式原型的指向,也可以。
原型判断方法补充
hasOwnProperty
判断一个属性是否在对象本身上。
var info = {
age: 21,
};
// obj.hasOwnProperty("address") true
var obj = {
address: "长沙",
};
// obj.hasOwnProperty("score") true
Object.defineProperty(obj, "score", {
configurable: true,
enumerable: false,
writable: false,
value: 100,
});
// obj.hasOwnProperty("age") false
obj.__proto__ = info;
in 操作符
判断键key是否出现在对象所在的原型链上。
var info = {
age: 21,
};
// console.log("address" in obj); true
var obj = {
address: "长沙",
};
// console.log("score" in obj); true
Object.defineProperty(obj, "score", {
configurable: true,
enumerable: false,
writable: false,
value: 100,
});
// console.log("age" in obj); true
obj.__proto__ = info;
instanceof
检测某一个构造函数
的prototype
是否出现在某个对象的原型链上。
function Foo() {}
var foo = new Foo();
var obj = {};
obj.__proto__ = foo;
console.log(obj instanceof Foo); // true
isPrototypeOf
检测某一个对象
是否出现在某个对象的原型链上
var obj = {};
var info = {};
info.__proto__ = {};
info.__proto__.__proto__ = obj;
console.log(obj.isPrototypeOf(info));
以上是关于JavaScript面向对象的主要内容,如果未能解决你的问题,请参考以下文章
VSCode自定义代码片段12——JavaScript的Promise对象
VSCode自定义代码片段12——JavaScript的Promise对象