当前位置: 首页 > news >正文

JS红宝书笔记 8.2 创建对象

虽然使用Object构造函数或对象字面量可以方便地创建对象,但这些方式有明显不足:创建具有同样接口的多个对象需要重复编写很多代码

工厂模式可以用不同的参数多次调用函数,每次都会返回一个新对象,这种模式虽然可以解决创建多个类似对象的问题,但没有解决对象表示问题,即新创建的对象是什么类型

构造函数和工厂函数的区别:

  • 没有显式的创建对象
  • 属性和方法字节赋值给了this
  • 没有return

使用new操作符调用构造函数会执行如下操作:

  • 在内存中创建一个新对象
  • 这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性
  • 构造函数内部的this被赋值为这个新对象,即this指向新对象
  • 执行构造函数内部的代码,给新对象添加属性
  • 如果构造函数返回非空对象,则返回该对象,否则,返回刚创建的新对象

constructor本来是用于标识对象类型的,不过,一般认为instanceof操作符是确定对象类型更可靠的方式

相比于工厂模式,定义自定义构造函数可以确保实例被标识为特定类型。

构造函数不一定要写成函数声明的形式,赋值给变量的函数表达式也可以表示构造函数,在实例化时,如果不想传参数,那么构造函数后面的括号可加可不加。只要有new操作符,就可以调用相应的构造函数

构造函数与普通函数唯一的区别就是调用方式不同,除此之外,构造函数也是函数,并没有把某个函数定义为构造函数的特殊语法。任何函数只要使用new操作符调用就是构造函数,而不是用new操作符调用的函数就是普通函数。

构造函数的主要问题在于,其定义的方法会在每个实例上都创建一遍,因为都是做一样的事,所以没必要定义两个不同的Function实例,况且,this对象可以把函数与对象的绑定推迟到运行时


每个函数都会创建一个prototype属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法。实例上,这个对象就是通过调用构造函数创建的对象的原型,使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。原来在构造函数中直接赋给对象实例的值,可以直接赋值给它们的原型

无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个prototype属性指向原型对象,默认情况下,所有原型对象自动获得一个名为constructor的属性,指回与之关联的构造函数。

在自定义构造函数时,原型对象默认只会获得constructor属性,其他的所有方法都继承自Object,每次调用构造函数创建一个新实例,这个实例的内部[[Prototype]]指针就会被赋值为构造函数的原型对象。脚本中没有访问这个[[Prototype]]的标准方式,一些浏览器会在每个对象上暴露__proto__属性,通过这个属性可以访问对象的原型。

实例与构造函数原型之间有直接的联系,但实例与构造函数之间没有

虽然不是所有实现都对外暴露了[[Prototype]],但可以使用isPrototypeOf()方法确定两个对象之间的关系,isPrototypeOf()会在传入参数的[[Prototype]]指向调用它的对象时返回true

Object有一个方法叫Object.getPrototype(),返回参数的内部特性[[Prototype]]的值

Object.setPrototypeOf()可以向实例的私有特性[[Prototype]]写入一个新值,这样就可以重写一个对象的原型继承关系,但是会影响代码性能

Object.create()可以创建一个新对象,同时为其指定原型

原型层级

在通过对象访问属性时,会按照这个属性的名称开始搜索,搜索开始于对象实例本身,如果在这个实例上发现了给定的名称,则返回该名称对应的值,如果没有找到这个属性,则搜索会沿着指针进入原型对象,然后在原型对象上找到属性后,再返回对应的值,这就是原型用于在多个对象实例间共享属性和方法的原理

虽然可以通过实例读取原型对象上的值,但不能通过实例重写这些值,如果在实例上添加了一个原型对象中同名的属性,那就会在实例上创建这个属性,这个属性会遮住原型对象上的属性。

使用delete操作符可以删除实例上的属性

hasOwnProperty()方法用于确定某个属性是在实例上还是在原型对象上,这个方法是继承自Object的,会在属性存在于调用它的对象实例上时返回true

原型和in操作符

有两种方式使用in操作符:单独使用和在for-in循环中使用

在单独使用时,in操作符会在可以通过对象访问指定属性时返回true,无论该属性在实例上还是原型上。

如果要确定某个属性是否在原型上,可以同时使用hasOwnProperty()和in操作符

在for-in循环中使用in操作符时,可以通过对象访问且可以被枚举的属性都会返回,包括实例和原型属性

要获得对象上所有可枚举的实例属性,可以使用Object.keys()方法,这个方法接收一个对象作为参数,返回包含该对象所有可枚举属性名称的字符串数组

如果想列出所有实例属性,无论是否可以枚举,都可以使用Object.getOwnPropertyNames()

Object.getOwnPropertySymbols()方法针对符号

属性枚举顺序

for-in循环和Object.keys()的枚举顺序是不确定的

Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()和Object.assign()的枚举顺序是确定的,先以升序枚举数值键,然后以插入顺序枚举字符串和符号键,在对象字面量中定义的键以它们逗号分隔的顺序插入


Object.values()和Object.entries()将对象内容转换为序列化的,可迭代的格式,它们接收一个对象,返回它们内容的数组。Object.values()返回对象值的数组,Object.entries()返回键值对的数组,非字符串属性会被转换为字符串输出,这两个方法执行对象的浅复制,符号属性会被忽略

原型上搜索值是动态的,所以即使实例在修改原型之前已经存在,任何时候对原型对象的修改也会在实例上反映出来

实例的[[Prototype]]指针是在调用构造函数时自动赋值的,这个指针即使把原型修改为不同的对象也不会变,重写整个原型会切断最初原型与构造函数的联系,但实例引用的仍然是最初的原型

重写构造函数上的原型之后再创建的实例才会引用新的原型

通过原生对象的原型可以取得所有默认方法的引用,也可以给原生类型的实例定义新的方法。可以像修改自定义对象原型一样修改原生对象原型,因此随时可以添加方法

原型模式弱化了向构造函数传递初始化参数的能力,会导致所有实例默认都取得相同的属性值,原型的最主要问题是它的共享特性

http://www.lryc.cn/news/572554.html

相关文章:

  • 李宏毅《生成式人工智能导论》| 第1讲:什么是生成式人工智能
  • python画三维立体图
  • SpringBoot扩展——应用Web Service!
  • 简单理解HTTP/HTTPS协议
  • C#语言入门-task2 :C# 语言的基本语法结构
  • Python训练营打卡 Day55
  • C++实现手写strstr函数
  • 12.10 在主线程或子线程中更新 UI
  • Tensorflow推理时遇见PTX错误,安装CUDA及CuDNN, 解决问题!
  • 编辑器及脚本案例
  • 【Redis】主从复制
  • Transformer结构介绍
  • 【K8S】详解Labels​​ 和 ​​Annotations
  • 记录存储的使用
  • 计量经济学(复习/自用/未完)
  • AIGC - Prompt Optimizer 提示词优化器
  • uni-app项目实战笔记16--实现头部导航栏效果
  • 【数字人开发】Unity+百度智能云平台实现短语音文本识别功能
  • OpenAI 公布《走向理解与预防失准泛化:由“角色特征”驱动的突现性失准》研究总结
  • 用“Gemini 2.0 Flash Preview Image Generation”模型修改图片,有哪些常用的提示词和方法
  • Spring MVC参数绑定终极手册:单多参对象集合JSON文件上传精讲
  • MCAL学习(6)——诊断、DCM
  • 股票心理学习篇:交易的人性弱点 - 频繁交易
  • 基于Python的机动车辆推荐及预测分析系统
  • 计算机网络零基础完全指南
  • ROS2 笔记汇总(3) 动作
  • Linux树莓派项目实战:外网访问、PWM呼吸灯、超声波测距与驱动开发
  • 《思维力:高效的系统思维》
  • 【开源模型】高考数学139分!小米MiMo开源模型:7B参数突出重围
  • MySQL 的 WITH ROLLUP 功能