Javascript 对象深度解析

27、JavaScript 面向对象编程技巧深度解析 本文深入探讨了JavaScript面向对象编程的多种高级技巧,包括为Set原型添加自定义方法、实现对象的相等性与顺序比较、方法的借用与复用、私有状态的封装、构造函数重载与工厂方法的应用、子类的创建与继承机制、组合与继承的对比,以及接口与实现的分离。通过这些技巧,可以编写更加灵活、可维护和可扩展的JavaScript代码。 阅读详情

对象-高程及月影js视频学习笔记

对象的深拷贝和浅拷贝

ES5 浅拷贝

Object.assign({}, conf)

只能拷贝一级,深层的源改变,目标也会跟着改变。

递归 深拷贝

function deepCopy(des, src) {
  for (var key in src) {
    if(typeof src[key] !== 'object') {
      des[key] = src[key];
    } else {
      des[key] = des[key] || {};
      deepCopy(des[key], src[key]);
    }
  }
  return des;
}

创建对象

构造函数模式

new 和 Object.create

首先了解下Object.create的实现方式

Object.create =  function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
};

new操作符会做一下几个事情:

  • 创建一个新对象
  • 将构造函数的作用域赋给新对象
  • 执行构造函数中的代码(为新创建的对象添加属性)
  • 返回新对象

其中被new的函数就叫构造函数。

注意:

function C() {
  this.z = 3;
  this.func = function() {console.log(1)}
}
var c1 = new C();
var c2 = new C();
c1.func === c2.func // false

执行c1.func === c2.func会返回false,这是因为每次实例化的时候都会创造一个新的函数对象,实际上没有必要这么做,首先能想到的是,把要创建的函数放到构造函数外面:

function Person(name, age, job){this.sayName = sayName}
function sayName() {console.log(1)}

var p1 = new Person(1,2,3);
var p2 = new Person(1,2,3);

p1.sayName === p2.sayName // true

但是放在全局中就是去了封装的意义,所以引入了原型的模式。

原型模式

每个函数都有一个prototype(原型)的属性,这个属性指向一个对象,可以存储有特定类型的所有实例共享的属性和方法。

注:箭头函数不包含这个属性。。。

此时,下式依旧成立

function Person() {}
Person.prototype.name = 'aaa';
Person.prototype.sayName = ()=>{console.log(2)};

var p1 = new Person(1,2,3);
var p2 = new Person(1,2,3);

p1.sayName === p2.sayName // true
构造函数与原型对象

Person.prototype就是Person的原型对象,默认情况下,每个函数都存在prototype属性,这个属性存的对象里都默认有一个constructor属性指向该函数(当然还有一个_ proto_继承自Object)。

Person.prototype.constructor 指向 Person。

// _ proto_:显示在具体实例上的一个属性

// prototype:构造函数上的一个属性

isPrototypeOf

A.prototype.isPrototypeOf(B):A是不是B的原型对象

B instanceof A:B是不是A的实例

判断某个对象的[[Prototype]](实例,拥有[[Prototype]]属性的实例对象,通常浏览器的实现是_ proto_)是否指向调用isPrototypeOf()这个方法的对象(原型对象Person.prototype)。

读取某个对象的属性时,会按照实例对象、_ proto_ 对象、 _ proto_ 的 _ proto_等等顺序依次查找,比如上面person的例子,可以找到p1和p2的sayName和name属性。

但是如果直接给p1.name赋值,则无法改变 _ proto_对象中的name值,会在对象实例本身添加这个属性,以后读取p1.name值时,因先从实例找起,所以不会再读到原型上的值。

Person
name: "bbb"
__proto__:{name:"aaa", sayName: ......}

但是通过修改_ proto_ 的name属性,就会同时改变p1和p2的原型的name值 以及 Person的原型对象的name值,因为Person.prototype === p1. _ proto_ ,Person.prototype === p2. _ proto_ 。

使用delete操作符删掉p1.name,则又能访问到原型上的name属性,注意 delete p1.name只能删掉实例上的属性,可以通过delete p1.proto.name删掉原型上的属性,同样的操作原型的话,上述三个都会改变。

hasOwnProperty

可以通过这个方法来判断某属性是来自实例还是来自原型。

p1.hasOwnProperty('name') // false
in

可以判断是否对象实例或原型中有该属性。可以访问到不可枚举的属性,如constructor和_ proto_、prototype。也可以通过in和hasOwnProperty来判断属性是否在原型中。

for-in

只能访问到可枚举的实例和原型属性,constructor和_ proto_、prototype等不可枚举的访问不到。

Object.keys(obj)

对象上所有可枚举的实例属性。返回的是字符串数组 。

Object.getOwnPropertyNames()

对象上所有实例属性。返回的是字符串数组 。

原型的动态性

一般的,想之前提到的一样,每次修改原型对象是,能立即在所有对象实例中反应出来,因为他们之间的连接是一个指针,而给一个副本。

但是,重写原型对象的话,把原型修改为另一个对象,就切断构造函数与最初原型之间的联系。

重写之前的实例中的[[Prototype]]指针仍指向最初的原型。

在重写原型对象之后创建的实例[[Prototype]]指针指向重写的原型。z

// 重写原型对象
function Person() {}

var friend = new Person();

Person.prototype = {
  constructor: Person, // 如果不加这个的话,重写这里会没有constructor,prototype的prototype里会有Object的constructor。但是这种写法也有一个问题,constructor会变成可枚举的,所以也可以向下面那种方式写。
  name: 'aaa'
}
// Object.defineProperty(Person.prototype, 'constructor', {
  // enumerable: false, 
  // value: Person
// });
friend.sayName(); // error
原生对象的原型

原生对象比如Object,Array,String等,比如Array.prototype中有sort()方法。

根据动态性,可以给原生对象的原型上添加方法,比如Array,这样当前环境的所有数组都可以调用到新添加的方法。

PS: 不推荐在产品化的程序中修改原生对象的原型,这样可能会导致明明冲突,而且,也可能会意外的重写原生方法。

如果往数组上添加新方法,因为默认可枚举,所以for-in操作数组时,会把往数组上添加的新特性一起for-in出来。

解决这个问题,可以使用Object.defineProperty来给原型对象添加方法。使用此方法时,默认不可枚举。

原型模式创建对象的优缺点
优点

可以让所有对象实例共享它所包含的属性和方法(直接定义在构造函数中的函数,每个实例都会创造一个新的函数)

缺点
  • 只用原型模式,没有构造函数传递初始化参数这一环节,会导致默认情况下都取得相同的属性值。
  • 由于原型中的属性时被所有实例共享的,方法(function)比较适合这种共享的模式,其余的,改变一个实例的属性时,如果是值类型的,会在实例上创建这个属性,覆盖掉原型中的属性,不会影响到其他的实例;但是如果是引用类型的,比如下面这个例子,就会导致所有实例的该属性都改变,因为此时相当于直接在操作原型,并没有在实例上添加这个属性。
function Person() {}

Person.prototype = {
  constructor: Person,
  name: 'aaa',
  friends: [1, 2, 3]
}

var friend1 = new Person();
var friend2 = new Person();

friend1.friends.push(4);

console.log(friend1.friends) // [1, 2, 3, 4]
console.log(friend2.friends) // [1, 2, 3, 4]

组合使用构造函数模式和原型模式

在构造函数中定义各自特有的属性,在prototype中写共享的方法。

通常都是用这种方式创建自定义类型。

动态原型模式

在构造函数中初始化原型(仅在必要的情况下)

可以通过检查某个应该存在的方法是否有效,来决定是否要初始化原型。

function Person(name) {
  this.name = name;
  // 方法
  if(typeof this.name !== "function") {
    Person.prototype.sayName = function(){console.log(1)}
  }
}

但是只要有一次创建实例时,typeof this.name !== “function”,那么所有实例(之前创建和之后)都会有sayName这个方法。所以不能使用对象字面量来重写原型,这样就会切断之前创建的实例与新原型之间的联系。

寄生构造函数模式

封装创建对象的代码,再返回新创建的对象。

构造函数在不返回值的情况下,默认会返回新对象的实例(new操作符做的事情),寄生模式相当于手动做new操作符的一些事情,可以重写new调用构造函数时返回的值。

function Person(name) {
  var o = new Object();

  o.name = name;

  return o;
}

这种方式有个问题,因为相当于改变了new的默认行为,所以不存在默认的原型,原型就是Object,所以不能使用instanceOf来确定对象类型,所以一般情况下不要使用这种模式。

继承(原型链)

继承包括接口继承和实现继承。

实现继承通过原型链实现,利用原型让一个引用类型继承另一个引用类型的属性和方法。

…prototype = new Object()的方式才能继承,让一个原型对象等于另一个类型的实例。

直接…prototype = …prototype只是一直在修改原型,而不是链式继承。

这种方式有个弊端,在给对象原型赋值的时候,实例化了另一个类型(eg:A.prototype = new B(); ),即调用了类型B的构造函数,通常我们希望在实例化A的时候,再调用B的构造函数,如果B的构造函数有一些方法,或者需要传参的方法,这种传undefined参数的实例化可能会引发一些问题,可以用Object.create()来解决:

A.prototype = Object.create(B.prototype);

前文中提到过,Object.create是创建了一个构造函数为空新对象,赋原型在实例化,所以可以避免可能的构造函数异常执行。

原型链的问题

  • 之前原型模式创建对象的缺点中提到过,包含引用类性值的原型造成的问题。(不单独使用原型链,放到构造函数中)
  • 创建子类型实例时,不能向父类型(子类型继承父类型)中传参。(ES6中可以使用super([arguments]),比如react中的super(props),还有其他的解决办法,见下面的借用构造函数) 。

借用构造函数

使用apply()、call()等方法在新创建的对象上执行继承对象的构造函数。还可以通过此种方式绑定当前this并传参,或者用super。

getter和setter

使用Object.defineProperty()定义属性时,可以设置get、set、enumerable。

数据绑定视图

JS 深度解析对象创建模式 / 构造函数// 初始化逻辑,通常用于设置实例属性// ...// 方法定义// 实现细节// 实现细节// ...// 创建类的实例class关键字用于声明一个类。ClassName是类名,应遵循JavaScript的标识符命名规则。constructor是一个特殊的方法,它是类实例化时自动调用的函数,用于初始化新创建的对象。构造函数通常用于设置实例属性。this关键字在构造函数中指向新创建的实例,在方法中同样指代实例。 阅读详情

相关推荐

手把手教你用STM32实现三相永磁同步电机FOC控制(附代码)

本文详细介绍了基于STM32的三相永磁同步电机(PMSM)FOC控制实现方法,涵盖硬件设计、软件架构、参数调试及完整代码解析。通过磁场定向控制(FOC)算法,实现高效精准的电机控制,适用于工业自动化、电动汽车等领域。文章还提供了硬件选型建议、电流采样方案对比及PID参数整定技巧,助力开发者快速掌握FOC控制技术。

weixin_29168675的博客 96

javascript --- > 对象属性的深层次获取

现有对象如下 let obj = { a: { b:{ c:{ d:'Marron' } } } } 想通过一个方法,输入该对象和路径a.b.c.d获取Marron的值 【思路】: 首先使用split数据,将a.b.c.d变为[a, b, c, d] 然后使用shift()方法每次取出最前面的属性名,存放在prop中 新建一个res对象,让res = r...

栗子好好吃的博客 2651

CTF---Web---文件包含---01

文章目录前言一、题目描述二、解题步骤1.查看源代码2.文件包含(/etc/passwd)3.解码总结 前言 题目分类: CTF—Web—文件包含 一、题目描述 题目:提示寻找passwd文件 二、解题步骤 1.查看源代码 提示所有图片存储路径是download.php?name=img, 此时name参数的存在就提示此题可能为“文件包含”。 2.文件包含(/etc/passwd) 两种查看方式: 2.1、访问view-source:http://192.168.87.180/download.php

qq_22160557的博客 1391

如何在 JavaScript 中使用对象解构

对象解构是一个有用的 JavaScript 功能,用于从对象中提取属性并将其绑定到变量。更好的是,对象解构可以在一个语句中提取多个属性,可以从嵌套对象访问属性,并且可以在属性不存在时设置默认值。在这篇文章中,我将解释如何在JavaScript中使用对象解构。目录 1. 需要对对象进行解构 2. 提取属性 3. 提取多个属性 4. 默认值 5. 别名 6. 从嵌套对象中提取属性 7. 提取动态名称属性 8. 解构后的静止对象 9. 常见使用案例 10. 总结假设您要提取对象的某些属性。在 ES2015 之前的

南北极之间 1605

Delta-Sigma调制(DSM)技术

前言 数字信号处理和通信系统的性能很大程度上受到了模拟信号到数字信号转换接口——ADC的精度和分辨率的限制。而传统的线性脉冲编码调制(PCM)ADC受到了制造工艺的限制,无法达到很高的分辨率。但基于Delta-Sigma调制技术的ADC可以在现有工艺下实现高分辨率(大于16位),同时由于结构简单,所以易于实现。低成本高性能使得Delta-Sigma调制技术得到了广泛的应用。 Delta-Sigma型ADC的结构原理图如下图所示: 它最大的优势在于仅用1位ADC进行数据转换,同时其模拟电路部分结构简单不需要

阿星的博客 2万+

IBM X3650 M4做raid阵列

步骤1.开机出现此界面,同时按ctrl键和h键,进入IBM X3650 M4配置raid界面。 【注】不知道是不是因为我的服务器长期闲置,按键ctrl键和h键居然无法进入raid配置界面。这时候,我们可以进bios同样可以进入raid配置界面。如果你按ctrl键和h键就可以直接进入raid配置界面,那么请忽略此段,直接看步骤2 开机,按键F1,选中system setting ,接着选中Adapters and UEFI Drivers ...

ani5565的博客 2万+

数组的解构、对象的解构、对象的序列化、使用JSON进行深复制、Map、Map补充、Set——内建对象

数组的解构、对象的解构、对象的序列化、使用JSON进行深复制、Map、Map补充、Set

weixin_70320000的博客 524

3D 结构光相机工作原理全解 | 从编码投射到三维重建,原理 + 代码 + 工业实战一站式掌握

本文从3D结构光相机的整体架构出发,层层拆解了编码投射、相位计算、相位解包裹、三维重建的核心原理,补充了工业实战所需的公式推导、代码实现、参数调优、设备选型和案例落地,核心总结如下:相位是3D结构光成像的“灵魂”,其精度、稳定性直接决定3D重建的效果,包裹相位与绝对相位的区分的是工业实战的基础;编码投射的核心是“正弦条纹+格雷码条纹”组合,正弦条纹负责高精度相位提取,格雷码条纹辅助解包裹,适配工业场景的精度与稳定性需求;

getusushu的博客 417

JavaScript中 对象解构详解

默认值name : '明天也要努力' , city : '南京' , job : {post : '前端' } };const {post , level = '初级' } } = user;// 明天也要努力 25 undefined 前端 初级新变量创建一个全新的变量并分配一个使用对象属性值计算的值name : '明天也要努力' , city : '南京' , job : {post : '前端' } };const {

明天也要努力的博客 7213

【报错解决】OpenClaw 报错 FetchError: request to [https://registry.npmjs.org/](https://registry.npmjs.or

在国产基础软件与云原生生态逐步成熟的背景下,越来越多的开发者开始尝试将 Web 前端、AI 推理、系统服务等组件部署到国产操作系统与国产云环境中。我所在的项目正是这样一个场景: 我们基于 OpenClaw 构建一套云端 AI 管理平台,用于统一管理模型服务、前端控制台与后台 API。

博客 1753

2、系统建模、状态估计与故障诊断中的滤波设计与故障诊断方法

本文综述了系统建模、状态估计与故障诊断中的滤波设计与故障诊断方法。首先介绍了基于分析模型、知识和信号处理的三类故障诊断方法及其特点;随后总结了传统滤波方法(如维纳滤波、卡尔曼滤波)与非概率的集员滤波方法,重点阐述了在未知但有界噪声假设下的椭球、立方、多面体、区间和Zonotope等集员滤波算法原理与发展。文章还展示了各类集员滤波算法的应用实例与流程图,并对比了其计算复杂性与准确性。最后指出,根据不同系统特性选择合适的故障诊断与滤波方法至关重要,未来趋势将趋向于多方法融合与实际工程应用深化。

kmeans3miner的博客 139

ES6 深度解构

解构是一种从数组或对象中提取值并赋给独立变量的语法。深度解构是指对于嵌套的数据结构(例如对象中包含对象,数组中包含数组或对象等),可以通过一行代码实现多层级的解构赋值。这样可以更便捷地访问和使用嵌套结构中的数据。

weixin_43989656的博客 510

【机器学习-17】数据变换---小波变换特征提取及应用案列介绍

小波变换作为一种前沿的数据分析工具,近年来在信号分析领域崭露头角。小波分析的理论和方法凭借其独特优势,在信号处理、图像处理、语音处理、模式识别以及量子物理等多个领域得到了广泛的应用,堪称近年来在工具及方法上的重大突破。小波变换以其多分辨率的特性,在时域和频域均展现出对信号局部特征的强大表征能力。通过伸缩和平移等运算过程,小波变换能够对信号进行多尺度聚焦分析,为非平稳信号的时频分析提供了一种有效手段。它允许我们由粗及细地逐步观察信号,从而精准地提取出有用信息。

qq_38614074的博客 2万+

JS Reflect 对象 — 深度解析

JS Reflect对象深度解析

layneyao的博客 3742

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

JavaScript中对象进行深度clone,url参数解析

function cloneObject(o) { if(!o || 'object' !== typeof o) { return o; } var c = 'function' === typeof o.pop ? [] : {}; var p, v; for(p in o) { if(o.hasOwnProperty(p)) {

Wisdom_Qiu的博客 496

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

JavaScript 可迭代对象(Iterable)深度解析

JavaScript 可迭代对象(Iterable)深度解析 【免费下载链接】zh.javascript.info 现代 JavaScript 教程(The Modern JavaScript Tutorial),以最新的 ECMAScript 规范为基准,通过简单但足够详细的内容,为你讲解从基础到高阶的 JavaScr...

gitblog_00219的博客 390

【前端开发之JavaScript】(四)JS基础语法下篇:函数与对象核心要点深度解析

本文深入讲解JavaScript中函数与对象的核心概念。函数部分涵盖函数定义与调用、参数特性、函数表达式、作用域与作用域链;对象部分介绍三种创建方式、this关键字、JS与Java对象的区别。文章强调函数与对象的结合是JS编程的核心思维,通过将函数封装为对象方法实现代码结构化与复用。建议通过实践练习掌握这些基础知识,为后续学习DOM/BOM、框架等奠定基础。

2301_79248256的博客 2231

深度解析JS中的Array对象

深度实例解析JS中的Array对象,包括迭代方法filter,map,some,forEach,every等方法,也包含归并方法reduce的使用。

Linda的前端开发路 876

JavaScript变量对象深度解析

本文深入解析了JavaScript中的变量对象(VO)机制。主要内容包括:1)变量对象是执行上下文中存储函数声明、变量声明和函数形参的特殊对象;2)全局上下文的变量对象即全局对象(如window),函数上下文的称为活动对象(AO);3)详细阐述了变量对象的创建三阶段:建立arguments对象→扫描函数声明→扫描变量声明;4)通过代码示例演示了变量提升现象;5)解释了变量对象与作用域链的关系。全文通过可视化示例和交互演示,帮助读者理解这一核心概念。

油墨香^-^的博客 820

深度解析JavaScript事件对象

这篇文章主要介绍了JavaScript事件对象,结合实例形式深入分析了javascript DOM、IE及其他浏览器相关事件对象操作技巧与注意事项,写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。 触发 DOM 上的事件时,会生成一个事件对象 event,它包含着所有与事件有关的信息,诸如导致事件的元素、事件的类型以及其他与特定事件相关的信息。...

weixin_44526331的博客 222

JavaScript 对象 Objects 深度解析与实战指南

在本教程中,我们详细探讨了 JavaScript 中对象的各种操作和特性。对象是 JavaScript 中一种非常重要的数据结构,用于存储和管理复杂的数据。

caifox的博客 1141

JavaScript核心:函数与对象深度解析

函数:作为一等公民,支持高阶函数和闭包,是实现抽象、模块化和函数式编程的基础。对象:通过原型链实现继承,提供了数据封装和结构化的能力。结合:函数(特别是构造函数、闭包)与对象(实例、原型)共同构建了 JavaScript 的面向对象编程模型。ES6 的class提供了更友好的语法。理解这些核心概念及其相互关系,是掌握 JavaScript 的关键。

q_438141的博客 599

更新一种对象深度拷贝的方法

一直在为之前看到过的对象深度拷贝代码之复杂而忧桑,我这种脑容量,怎么取记住嘛!而且方法又都不是常用的,能不能简单明了一点!今天,有人告诉我了一个简单明了的方法,下面演示: 首先,我来定义一个对象obj1: let obj1 = {a: '1', b: '2', c: {d: '1'}} 然后,就是拷贝了: let obj2 = JSON.parse(JSON.stringify(obj1)...

weixin_42971933的博客 241

深度解析JavaScript原型对象

深度解析JavaScript原型对象 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 Python 机器学习入门之pandas的使用 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录深度解析JavaScript原型对象前言JavaScript原型,这里只分享我自己的见解一、原型是什么二、心得总结 前言 提示:这里可以添加本文要记录的大概内容: JavaScript原型,这里只分享我自己的见解 提示:以下是本篇文章正文内容,下面案例可供参考 一、原

ESTDA的博客 1191
上一篇: 奇舞学院JavaScript视频-如何写好原生js
下一篇: 奇舞学院及高程学习笔记-函数篇
KateCateCake
博客等级 码龄9年 26粉丝 25原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值