一起来了解JavaScript面向对象
目录
- JavaScript原型链
- Object的原型
- 顶层原型
- 创建Object对象的内存图
- Object是所有类的父类
- 原型链实现继承
- 借用构造函数实现继承
- 总结
JavaScript原型链 每一个对象都有原型,指向另一个对象,另一个对象也有自己的原型,就这样由原型的原型构成的链条就叫原型链。
文章图片
原型链的尽头
如果一个原型链是,没用尽头的,那么在查找一原型链上不存在的属性时,就会一直查找下去,存在死循环了。显然不是这样的,那么原型链的尽头是什么?
Object的原型
顶层原型
看代码~
// obj字面量创建方法类似于 new Object()// 那么 obj对象就是Object的一个实例,也就是说obj.__proto__ === Object.prototypevar obj = {name: "fzb",}; // 那么obj.__proto__ 或者 Oject.prototype 的__proto__ 是什么? 答案是: nullconsole.log(obj.__proto__); // [Object: null prototype] {}console.log(obj.__proto__.__proto__); // null
[Object: null prototype] {}
的特殊之处:1、该对象存在原型属性,只是原型指向了
null
,就是已经是顶层原型了。2、该对象上还存在许多其他的方法,只是不可枚举,看不到。
创建Object对象的内存图
文章图片
上方例子的内存图
文章图片
Object是所有类的父类 原型链最顶层的原型对象就是Object的原型对象
例子:
function Student(sno, name) {this.sno = sno; this.name = name; }const stu = new Student(201801, "fzb"); console.log(stu); // Student { sno: 201801, name: 'fzb' }console.log(stu.__proto__); // {}console.log(stu.__proto__.__proto__); // [Object: null prototype] {}console.log(Student.__proto__); // {}/* ***************后面将具体讲解注释内容*************** * 为什么不是 Student.__proto__ = [Object: null prototype] {} * 是因为 Student.__proto__ = Function.prototype * Function.prototype.__proto__ = Object.prototype = [Object: null prototype] {} * ***************后面将具体讲解注释内容*************** */console.log(Student.__proto__.__proto__); // [Object: null prototype] {}
内存图:
文章图片
原型链实现继承 继承可以重复利用代码,子类可以使用
例子:
function Person() {this.name = "fzb"; }Person.prototype.running = function () {console.log(this.name + "正在跑步~"); }; function Student(sno) {this.sno = sno; }Student.prototype = new Person(); // 重写整个原型对象之后,要重新配置 constructorObject.defineProperty(Student.prototype, "constructor", {configurable: true,enumerable: false,writable: true,value: Student,}); Student.prototype.studying = function () {console.log(this.name + "正在学习"); }; const stu = new Student(201801); stu.running(); // fzb正在跑步~stu.studying(); // fzb正在学习
内存图:
文章图片
缺陷
1> 在打印子类对象时,有些属性本应该打印出来的,但是因为在父类上,无法打印出来。
2> 多个子类对象在进行某些操作时,会出现相互影响。
// 在上方例子上,加一点点代码,function Person() {this.name = "fzb"; this.friends = []; // 增加一个属性}const stu1 = new Student(201801); stu1.friends.push("zzw"); const stu2 = new Student(201801); console.log(stu2.friends); // [ 'zzw' ]// stu2上取到了stu1的friends属性,这是不可以的
3> 无法传递参数,有些属性存在父类构造函数内,子类实例化时,初始化参数无法传入到父类。
借用构造函数实现继承 在子类构造函数内,调用构造函数。使改变父类构造函数内的this指向,然后父类在this上添加的属性就会在子类实例化的对象上。
function Person(name) {this.name = name; this.friends = []; }Person.prototype.running = function () {console.log(this.name + "正在跑步~"); }; function Student(sno, name) {Person.call(this, name); // 添加代码this.sno = sno; }Student.prototype = new Person(); // 重写整个原型对象之后,要重新配置 constructorObject.defineProperty(Student.prototype, "constructor", {configurable: true,enumerable: false,writable: true,value: Student,}); Student.prototype.studying = function () {console.log(this.name + "正在学习"); }; const stu1 = new Student(201801,"stu1"); stu1.friends.push("zzw"); const stu2 = new Student(201802,"stu2"); console.log(stu2.friends); // []
这时原型链实现继承的三个弊端,就解决的。但是又出现了新的缺陷。
缺陷
1> 父类构造函数至少执行了两次以上
2> 子类构造函数的原型对象是父类的实例对象,那么个对象上的属性将会是undefined
文章图片
总结 【一起来了解JavaScript面向对象】本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!
推荐阅读
- 一个人的旅行,三亚
- 一个小故事,我的思考。
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 开学第一天(下)
- 一个人的碎碎念
- 2018年11月19日|2018年11月19日 星期一 亲子日记第144篇
- 遇到一哭二闹三打滚的孩子,怎么办┃山伯教育
- 第326天
- Y房东的后半生14
- 奔向你的城市