对象与继承

创建一个对象的几种方式
  1. new Object()或者字面量{},或者__proto__;
let obj = {name: 'obj',sayName: function () {console.log(this.name)}
}
// obj ---> Object.prototype ---> null// 可以通过 __proto__ 字面量属性将新创建对象的[[Prototype]] 指向另一个对象。
const p = { b: 2, __proto__: o };
// p ---> o ---> Object.prototype ---> null
  • 优点 被所有的现代引擎所支持。将 proto 属性指向非对象的值只会被忽略,而非抛出异常。与 Object.prototype.proto setter 相反,对象字面量初始化器中的 proto 是标准化,被优化的。甚至可以比 Object.create 更高效。在创建对象时声明额外的自有属性比 Object.create 更符合习惯。

  • 缺点 不支持 IE10 及以下的版本。对于不了解其与 Object.prototype.proto 访问器差异的人可能会将两者混淆。

  1. Object.create(proto,propertiesObject);
// 参数1:原型对象,参数2:可枚举的自有属性
// 参数1不是null或对象,则抛出TypeError异常
// 参数2不是指定结构也会报TypeError错
let obj1 = Object.create(obj, {name: {value: 'obj1Name', // 默认为undefinedwritable: true, // 默认为falseconfigurable: true, // 默认为falseenumerable: false,writable:false}
})
obj1.__proto__.__proto__ === obj.__proto__;
obj1.__proto__.__proto__ === Object.prototype;
// 扩展,查看一个对象的原型上是否有某个属性
Object.prototype.hasOwnProperty.call(obj1,'sayName'); //false name为true
// 可模仿new 构造函数
  • 优点 被所有现代引擎所支持。允许在创建时直接设置对象的 [[Prototype]],这允许运行时进一步优化对象。还允许使用 Object.create(null) 创建没有原型的对象。
  • 缺点 不支持 IE8 及以下版本。但是,由于微软已经停止了对运行 IE8 及以下版本的系统的扩展支持,这对大多数应用程序而言应该不是问题。此外,如果使用了第二个参数,慢对象的初始化可能会成为性能瓶颈,因为每个对象描述符属性都有自己单独的描述符对象。当处理上万个对象描述符时,这种延时可能会成为一个严重的问题。
  1. new 构造函数创建;
function Person(name) {// 判断是否用new 创建对象if (new.target === void 0) {return {}}this.name = name;this.sayName = function () {console.log(this.name)}
}const xiaoming = new Person('xiaoming');
  • 优点 所有引擎都支持——一直到 IE 5.5。此外,其速度很快、非常标准,且极易被 JIT 优化。
  • 缺点

1.要使用这个方法,必须初始化该函数。在初始化过程中,构造函数可能会存储每一个对象都必须生成的唯一信息。这些唯一信息只会生成一次,可能会导致问题。
2.构造函数的初始化过程可能会将不需要的方法放到对象上。

  1. 使用类class
class Obj {constructor(height, width) {this.height = height;this.width = width;}
}
const obj = new Obj(2, 3);
// obj ---> Obj.prototype ---> Object.prototype ---> null
  • 优点 被所有现代引擎所支持。非常高的可读性和可维护性。私有属性是原型继承中没有简单替代方案的特性。
  • 缺点 类,尤其是带有私有属性的类,比传统的类的性能要差(尽管引擎实现者正在努力改进这一点)。不支持旧环境,通常需要转译器才能在生产中使用类。
new 都干了什么
1. 创建了一个空的对象{}
2. 为步骤1创建的对象增加属性__proto__,将该属性链接至构造函数的原型对象
3. 将步骤1创建的对象作为this的上下文
4. 如果该函数没有返回对象,则返回this如果返回的是一个非对象,则返回this如果返回的是一个对象,则返回该对象
模拟实现一个new函数
function NewFn(Fn) {if (typeof Fn !== 'function') {throw new Error('Fn must be a function')}const newObj = Object.create(Fn.prototype);const result = Fn.apply(newObj, Array.prototype.slice.call(arguments, 1))if (result && typeof result === 'object') {return result;} else {return newObj;}
}
模拟实现Object.create
function inherit(p,properties) {if (p == null) throw TypeError();if (Object.create) {return Object.create(p)}const t = typeof p;if (t !== 'object' && t !== 'function') throw TypeError();// - 返回了一个对象;// - 这个对象的原型,指向了这个函数 Function 的 prototype;function F() {};F.prototype = p;if(properties) {Object.defineProperties(F, properties);}return new F();
}
new Object()和直接{}的区别

从创建对象的过程来讲,这两者底层实现基本是没有区别的。但是new Object()本质上是方法(只不过这个方法是内置的)调用, 既然是方法调用,就涉及到在proto链中遍历该方法,当找到该方法后,又会生产方法调用必须的堆栈信息,方法调用结束后,还要释放该堆栈。
所以,相比来说,更推荐直接字面量创建,更简洁,更高效

Object.create(null)和直接{}的区别

Object.create(null)创建了一个空对象,无Object原型对象的任何属性,可以自己写对应的方法等,不会污染全局Object

  • Object.create(null)使用
  1. 在我们使用for…in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了
  2. 你需要一个非常干净且高度可定制的对象当做数据字典的时候
  3. 减少hasOwnProperty造成的性能损失并且可以偷懒少些一点代码的时候
继承
  • 子类的原型对象——类继承
// 声明父类
function FatherClass() {this.children = [];
}
// 为父类添加共有方法
FatherClass.prototype.sayName = function () {console.log('I am father');
}
// 声明子类
function ChildClass() {this.hasFather = true;
}
// 继承父类
ChildClass.prototype = new FatherClass();
// 为子类添加共有方法
ChildClass.prototype.sayName = function () {console.log('I am children');
}const child1 = new ChildClass();
const child2 = new ChildClass();
child2.children.push(12);
console.log(child1.children, child2.children); // 都为[12]
/*** 问题* 1. 传参* 2. 如果属性是引用属性,一旦某个实例修改了这个属性,那么都会被修改掉*/
  • 构造函数继承
// 声明父类
function FatherClass() {this.children = [];
}
// 为父类添加共有方法
FatherClass.prototype.sayName = function () {console.log('I am father');
}
// 声明子类
function ChildClass(arg) {this.hasFather = true;FatherClass.call(this, Array.prototype.slice.call(arguments, 1))
}
// 为子类添加共有方法
ChildClass.prototype.sayName = function () {console.log('I am children');
}const child1 = new ChildClass('');
const child2 = new ChildClass('');
child2.children.push(12);
console.log(child1.children, child2.children); // [],[12]
/*** 问题* 1. 这种类型的继承没有涉及原型prototype,所以父类的原型属性或者方法不能被继承,想要被继承的话,只能在构造函数中定义,违背了代码复用原则* 2. 如果方法在构造函数中定义,每次都会被创建。*/
  • 组合继承
// 声明父类
function FatherClass() {this.children = [];
}
// 为父类添加共有方法
FatherClass.prototype.sayName = function () {console.log('I am father');
}
// 声明子类
function ChildClass(arg) {this.hasFather = true;FatherClass.call(this, Array.prototype.slice.call(arguments, 1))
}
// 只是想要一个原型链,又调用了一遍父类构造函数
ChildClass.prototype = new FatherClass();
// 为子类添加共有方法
ChildClass.prototype.sayName = function () {console.log('I am children');
}const child1 = new ChildClass('');
const child2 = new ChildClass('');
child2.children.push(12);
console.log(child1.children, child2.children); // [],[12]
  • 原型式继承
function inheritObj(obj){if(p == null) throw TypeError();if(Object.create) {return Object.create(p)}var t = typeof p;if(t !== 'object' && t !== 'function') throw TypeError();// 声明一个过渡函数对象function Fn(){};// 过渡对象原型继承父类对象Fn.prototype = obj;// 返回该过渡对象实例,该实例的原型链继承了父对象return new Fn();
}
  • 寄生组合式继承

function inheritPrototype(parentClass, childClass) {// 复制一根父类的原型副本保存在变量中const p = inheritObj(parentClass.prototype);// 修正因为重写导致子类的constructor属性被修改p.constructor = childClass;// 设置子类的原型childClass.prototype = p;
}// 声明父类
function FatherClass() {this.children = [];
}
// 为父类添加共有方法
FatherClass.prototype.sayName = function () {console.log('I am father');
}
// 声明子类
function ChildClass(arg) {this.hasFather = true;FatherClass.call(this, Array.prototype.slice.call(arguments, 1))
}
inheritPrototype(FatherClass, ChildClass);
// 为子类添加共有方法
ChildClass.prototype.sayName = function () {console.log('I am children');
}const child1 = new ChildClass('');
const child2 = new ChildClass('');
child2.children.push(12);
console.log(child1.children, child2.children); // [],[12]
  • Class继承(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes/extends)
/// class 继承中做的,而狭义上,组合寄生式继承,没有做的 //
for(var k in Person) {if(Person.hasOwnProperty(k) && !(k in Teacher)) {Teacher[k] = Person[k]}
}
//
// - class 继承,会继承静态属性
// - 子类中,必须在 constructor 调用 super, 因为子类自己的 this 对象,必须先通过 父类的构造函数完成。
POP面向过程编程Procedure-Oriented Programming

分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。

OPP面向对象编程Object Oriented Programming

把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

AOP面向切面编程Aspect Of Programming

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/764684.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分库分表实战

先了解分库分表的一些概念,参考:【MySQL】MySQL分库分表详解[通俗易懂]-腾讯云开发者社区-腾讯云 然后觉得哔哩哔哩里讲的挺好的,要试一下:1、海量数据冲击下的MySQL优化方案_哔哩哔哩_bilibili 看到了P5 还有博客:…

基于springboot的mysql实现读写分离

前言: 首先思考一个问题:在高并发的场景中,关于数据库都有哪些优化的手段?常用的有以下的实现方法:读写分离、加缓存、主从架构集群、分库分表等,在互联网应用中,大部分都是读多写少的场景,设置两个库,主库和读库,主库的职能是负责写,从库主要是负责读…

在存在代理的主机上,为docker容器配置代理

1、配置Firefox的代理 (只配置域名或者ip,前面不加http://) 2、为容器中的Git配置代理 git config --global http.proxy http://qingteng:8080 3、Git下载时忽略证书校验 env GIT_SSL_NO_VERIFYtrue git clone https://github.com/nginx/nginx.git 4、docker的…

IDEA | 资源文件中文乱码问题解决

问题 IDEA打开资源文件,显示乱码问题。 解决方案 1、电脑是mac,点击IDEA->【Preferences】->【Editor】->【File Encodings】 2、选择【Properties Files】中的UTF-8,并勾选Transparent native-to-ascii conversion。 3、最后点击…

创龙教仪基于瑞芯微3568的ARM Cortex A-55教学实验箱 适用于人工智能 传感器 物联网等领域

适用课程 Cortex-A55 ARM嵌入式实验箱主要用于《ARM 系统开发》、《ARM 应用开发》《物联网通信技术》、《嵌入式系统设计》、《移动互联网技术》、《无线传感器网络》、《物联网设计方法与应用》、《人工智能》等课程。 适用专业 Cortex-A55 ARM嵌入式实验箱主要面向电子信…

微服务day05(中) -- ES索引库操作

索引库就类似数据库表,mapping映射就类似表的结构。 我们要向es中存储数据,必须先创建“库”和“表”。 2.1.mapping映射属性 mapping是对索引库中文档的约束,常见的mapping属性包括: type:字段数据类型,…

深入理解 C#和Unity中的Null

作者简介: 高科,先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢…

Qt教程 — 3.7 深入了解Qt 控件: Layouts部件

目录 2 如何使用Layouts部件 2.1 QBoxLayout组件-垂直或水平布局 2.2 QGridLayout组件-网格布局 2.3 QFormLayout组件-表单布局 在Qt中,布局管理器(Layouts)是用来管理窗口中控件位置和大小的重要工具。布局管理器可以确保窗口中的控件在…

使用阿里CICD流水线打包Vue项目到阿里的docker镜像私仓,并自动部署到服务器启动服务

文章目录 使用阿里CICD流水线打包Vue项目到阿里的docker镜像私仓,并自动部署到服务器启动服务1、功能实现原理大家可以看我之前的两篇文章2、打包vue项目和打包咱们的Java项目过程差不多相同,大家可以看着上面的Java打包过程进行实验,下面是v…

解决VM重新打开后找不到共享文件夹的问题

我的问题是之前按照网上的文档设置了vm的共享文件夹,能成功使用,但是问题是下一次打开之后就找不到了,虚拟机设置里共享文件夹是启用的,文件夹也完成了映射网络驱动器,但是就是找不到共享文件夹 解决方法:…

GraphQL入门之变更输入类型

前一篇文章介绍了变更操作,在创建 User 对象的时候,只传递了 name 和 email 参数,但是如果属性太多或者创建对象的时候只需要部分必选参数,直接把属性都当成参数就不合适了,这里 GraphQL 提供了 Input Type 参数来解决…

关于在vue中有时候表格的位置不对是怎么个情况

今天在写代码的时候多了一个<div>标签&#xff0c;导致表格的位置大小不对 <template><div><tr><td><input type"checkbox" checked"true" /></td><td>xxxxx</td><td><button class"…

搜索二维矩阵

题目链接 搜索二维矩阵 题目描述 注意点 每行中的整数从左到右按非严格递增顺序排列每行的第一个整数大于前一行的最后一个整数1 < matrix.length, matrix[0].length < 100 解答思路 先二分查找找到target所处的行&#xff0c;找到行后再二分查找找到target所处的列…

C语言预编译#pragma宏的作用

在嵌入式编程中&#xff0c;#pragma 指令具有非常重要的作用&#xff0c;因为它允许开发者在不同的编译器之间传达特定的编译指令。由于嵌入式编程通常与硬件紧密相关&#xff0c;且资源有限&#xff0c;这些指令可以帮助开发者更有效地利用可用资源&#xff0c;优化程序&#…

【Canvas与艺术】绘制动态太极图

【图例】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>绘制旋转太极图</title><style type"text/css"&g…

Rust 语言中 as 关键字用法

一、Rust 语言中 as 关键字的基本用法 在Rust编程语言中&#xff0c;"as"关键字有几种不同的用法&#xff0c;主要用于类型转换和引入模块或别名。 类型转换&#xff1a;在Rust中&#xff0c;当需要将一个类型转换为另一个类型时&#xff0c;可以使用"as"…

Flutter中自定义Dialog

Dialog在不同的平台&#xff0c;都是一种重要的交互方式&#xff0c;在Flutter中&#xff0c;Dialog也是有很多种&#xff0c;但大多数场景的交互&#xff0c;都需要根据项目的主题或一些特定的交互去实现自定义的Dialog。 为满足不同的诉求和兼容性&#xff0c;封装实现了两种…

html5cssjs代码 039 元素尺寸

html5&css&js代码 039 元素尺寸 一、代码二、解释 使用CSS来定义HTML元素的尺寸&#xff0c;并通过不同的计量单位来设置元素的大小。 一、代码 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><tit…

从0到1实现RPC | 03 重载方法和参数类型转换

一、存在的问题 1.重载方法在当前的实现中还不支持&#xff0c;调用了会报错。 2.类型转换也还存在问题。 假设定义的接口如下&#xff0c;参数是float类型。 在Provider端接受到的是一个Double类型&#xff0c;这是因为web应用接收的请求后处理的类型。 在反射调用的时候就会…

思腾合力受邀出席文化和旅游虚拟现实应用推广交流活动并作主题演讲

3月21日&#xff0c;由文化和旅游部产业发展司主办&#xff0c;中国信息通信研究院、北京市石景山区文化和旅游局、中国动漫集团有限公司承办的“数字赋能文旅场景建设行动——文化和旅游虚拟现实应用推广交流活动”在北京首钢一高炉SoReal科幻乐园成功举办。 思腾合力CMO徐莉受…