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

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.xdnf.cn/news/14640.html

相关文章:

  • IPv4编址及IPv4路由基础
  • 73、MYSQL ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin含义
  • Transformer结构介绍
  • 记录存储的使用
  • uni-app项目实战笔记16--实现头部导航栏效果
  • 优化TCP/IP协议栈与网络层
  • 工程师生活:清除电热水壶(锅)水垢方法
  • Apache Hive技术详解
  • NetworkManager介绍与用法
  • Singularity 安装
  • [接口-ihrm]
  • Git版本控制详细资料
  • 计算机网络:(五)信道复用技术,数字传输系统,宽带接入技术
  • [Data Pipeline] Kafka消息 | Redis缓存 | Docker部署(Lambda架构)
  • 69、数据访问-准备阿里云redis环境
  • 面试题:设计一个分布式“附近的人”功能(如微信附近的人、交友应用位置匹配)
  • WSL 安装使用和常用命令
  • AD学习(4)
  • 使用MATLAB求解二维顶盖驱动流问题的详细代码和说明
  • Dify动手实战教程(入门-猜病、哄哄模拟器)
  • leetcode-3405 统计恰好有k个相等相邻数组的个数
  • Greenplum/PostgreSQL pg_hba.conf 认证方法详解
  • 【Node.js 的底层实现机制】从事件驱动到异步 I/O
  • TradingAgents:基于多智能体的大型语言模型(LLM)金融交易框架
  • vue | vue 插件化机制,全局注册 和 局部注册
  • 【音视频】PJSIP库——pjsua命令使用详解
  • 【C语言极简自学笔记】重讲运算符
  • LeetCode 632.最小区间
  • ChangeNotifierProvider 本质上也是 Widget
  • 利用tkinter函数构造MD5加密的可视化操作界面