JavaScript基础知识点整理(一)——运算符比较、闭包、深浅拷贝、原型、

news2024/11/17 13:54:14

内容主要涉及JavaScript:运算符比较、闭包、深浅拷贝、原型

JavaScript闭包、原型、深浅拷贝

  • 1、== 和 === 的差异
  • 2、JavaScript闭包
  • 3、JavaScript深浅拷贝
    • 3.1、浅拷贝
    • 3.2、深拷贝
  • 4、JavaScript原型


1、== 和 === 的差异

对于==而言,若对比双方的类型不一样的话,则存在类型转换,这也就用到了。

JavaScript类型转换:包括显式转换和隐式转换

当需要对比两个变量ab是否相同,需要如下流程:

  • 首先判定两者类型是否相同,相同则比较大小。
  • 类型不同的话,则进行类型参数转换。
  • 判定是否对比nullundefined,是的话就返回true
  • 判定两者类型是否stringnumber,是的话就将字符串转换为number
1 == '1'1 ==  1
  • 判定其中的一方是否boolean,是的话就boolean转换为number,并且进行重写进行判定的流程。
'1' == true'1' ==  11  ==  1
  • 判定其中一方是否object,并且另一方是stringnumber,是的话就将object转换为原始类型进行判定,也就是执行x.tostring以及valueof
'1' == { name: 'yck' }'1' == '[object Object]'
  • 返回false

综述,如下流程图:
在这里插入图片描述


2、JavaScript闭包

首先给出闭包的正确定义:

设定一个函数能访问外部的变量,那么就形成了一个闭包,而且不是一定要返回一个函数

给出下述代码:

let a = 1
// 产生闭包
function fn() {
  console.log(a);
}

function fn1() {
  let a = 1
  // 产生闭包
  return () => {
    console.log(a);
  }
}
const fn2 = fn1()
fn2()

接下来阐述数据存放的正确规则:局部、占用空间确定的数据,一般存放于栈中,否则就在堆中;
在这里插入图片描述
上图能看到一个内部的对象scopes,这个对象就是一般所说的作用域链。
根据作用域链寻找的顺序,包含了闭包、全局对象。因此我们能够通过闭包访问本次销毁的变量,所以原始数据一般存放在栈上。

另外最开始对于闭包的定位是:假如一个函数能够访问外部的变量,则形成了闭包。给出如下代码:

let a = 1
var b = 2
// 形成闭包
function fn() {
  console.log(a, b);
}

在这里插入图片描述

可以得出结论,若是var则直接被挂载到global上,若是其他的关键字声明则被挂载到Script上面,虽然这些数据同样还是存在于scopes,但是全局变量在内存中是存放在静态区域的,因为全局变量无需参与到GC。

最后总结一下原始类型存储位置:局部变量被存储在栈上,全局变量存储在静态区域上,其它都存储在堆上。


3、JavaScript深浅拷贝

3.1、浅拷贝

首先可以通过Object.assign来解决这个问题,这个函数会拷贝所有的属性数值到新的对象中,若属性是对象的话,就拷贝地址

let a = {
  age: 1
}
let b = Object.assign({}, a)
a.age = 2
console.log(b.age) // 1

也可以利用...来实现浅拷贝:

let a = {
  age: 1
}
let b = { ...a }
a.age = 2
console.log(b.age) // 1

通常而言浅拷贝能够解决大部分的问题,若遇到下面的情况需要利用深拷贝:

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = { ...a }
a.jobs.first = 'native'
console.log(b.jobs.first) // native

3.2、深拷贝

深拷贝通常可以利用JSON.parse(JSON.stringify(object))来解决,这个方式能够解决大部分的情况:

let a = {
  age: 1,
  jobs: {
    first: 'FE'
  }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

不过该方法存在的问题:

let obj = {
  a: 1,
  b: {
    c: 2,
    d: 3,
  },
}
obj.c = obj.b
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c
let newObj = JSON.parse(JSON.stringify(obj))
console.log(newObj)

若对象存在循环引用,则报如下错误:

在这里插入图片描述
同时遇到不支持的数据类型,例如函数、undefined、symbol等等,这些属性都会被忽略掉:

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function() {},
  name: 'yck'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "yck"}

给出JSON支持的数据类型:
在这里插入图片描述

若需要拷贝的对象含有内置类型并且不包含函数,则可以利用MessageChannel

function structuralClone(obj) {
  return new Promise(resolve => {
    const { port1, port2 } = new MessageChannel()
    port2.onmessage = ev => resolve(ev.data)
    port1.postMessage(obj)
  })
}

var obj = {
  a: 1,
  b: {
    c: 2
  }
}

obj.b.d = obj.b

// 注意该方法是异步的
// 可以处理 undefined 和循环引用对象
const test = async () => {
  const clone = await structuralClone(obj)
  console.log(clone)
}
test()

同时我们也可以自己实现一个深拷贝:

// 利用 WeakMap 解决循环引用
let map = new WeakMap()
function deepClone(obj) {
  if (obj instanceof Object) {
    if (map.has(obj)) {
      return map.get(obj)
    }
    let newObj
    if (obj instanceof Array) {
      newObj = []     
    } else if (obj instanceof Function) {
      newObj = function() {
        return obj.apply(this, arguments)
      }
    } else if (obj instanceof RegExp) {
      // 拼接正则
      newobj = new RegExp(obj.source, obj.flags)
    } else if (obj instanceof Date) {
      newobj = new Date(obj)
    } else {
      newObj = {}
    }
    // 克隆一份对象出来
    let desc = Object.getOwnPropertyDescriptors(obj)
    let clone = Object.create(Object.getPrototypeOf(obj), desc)
    map.set(obj, clone)
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        newObj[key] = deepClone(obj[key])
      }
    }
    return newObj
  }
  return obj
}

不过上述代码存在缺陷,递归可能存在栈溢出,这是因为执行栈的大小有限,可以通过遍历的方式改写递归,例如JavaScript实现层序遍历BFS,也可以利用数组模拟栈解决栈溢出的问题。


4、JavaScript原型

当创建一个对象时,let obj = { age: 25 },我们可以发现能使用很多种函数,但是没有定义过他们,如下图:
在这里插入图片描述

在浏览器中打印obj会发现存在一个__proto__的属性,这是因为每一个JavaScript对象都有一个__proto__的属性,这个属性指向了原型 ,这个属性目前不推荐使用,这只是浏览器早起为了访问内部属性prototype来实现的东西;
在这里插入图片描述
原型也是一个对象,并且该对象包含了很多的函数,所以推出结论:

对于obj而言,可以通过__proto__找到一个原型对象,再该对象中定义了很多的函数让我们使用。

同时还可以发现一个constructor的属性,也就是构造函数:
在这里插入图片描述

打开constructor属性可以发现其中还有一个prototype属性,并且该属性和之前的__prototype__中的一模一样,因此给出如下的结论:

原型的constructor属性指向了构造函数,构造函数通过prototype来指向原型,不过并不是所有的函数都具有这个属性,Function.prototype.bind() 就没有这个属性

给出如下的图来总结记忆:
在这里插入图片描述
原型链就是多个对象通过__proto__方式连接起来了,总结具体如下:

  • object是所有对象的父亲,所有对象都可以通过__proto__找到它。
  • Funciton是所有函数的父亲,所有函数都可以通过__proto__找到它。
  • 函数的prototype是一个对象
  • 对象的__proto__属性指向了原型,__proto__把对象和原型连接起来组成了原型链。

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

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

相关文章

MicroBlaze系列教程(2):AXI_INTC的使用

文章目录 @[TOC]AXI_INTC简介常用函数使用示例参考资料工程下载本文是Xilinx MicroBlaze系列教程的第1篇文章。 AXI_INTC简介 AXI_INTC中断控制器用于将多路中断信号按照优先级输出一路给处理器,支持AXI4-Lite总线,最多支持32个中断输入,中断输入可配置为边沿触发或电平触发…

【vuex】一.vue.js的基本指令;二.vue.js全家桶开发;三.vuex

目录 一.vue.js的基本指令 1.Vue的作用:快速的构建前端页面(封装了html、css、js),以工程化的方式进行前端的开发 2.Vue的核心: (1)组件化: (2)数据的双…

shell执行脚本的方法及环境变量

执行脚本的方法 (1)bash ./filename.sh(产生子进程,再运行,使用当前指定的bash shell去运行) (2)./filename.sh(产生子进程,再运行,使用脚本里面指…

vue3 手撕日历控件

vue制作日历控件 效果如下&#xff1a; <template><div class"cal_con" style"margin-left:200px"><div class"cal_header"><!-- 顶部左侧 --><div class"cal_header_left"><div class"cal_he…

STL分析(十 hash、function type_traits、cout、move )

hash function 假定存在一个Customer类 class Customer{ public:string fname, lname;int no; };其哈希函数存在三种方式 //方式一&#xff1a;创建可调用类型 class CustomerHash { public:std::size_t operator()(const Customer& c) const{return ......} };unordere…

Android 签名基础知识

目录Android 为什么要签名keystore的生成&#xff1a;keystore信息的查看参数说明&#xff1a;Android 怎么签名使用 jarsigner 签名如何查找 jdk 位置签名时遇到的问题查看 apk 是否签名查看 Apk 的MD5值以及MD5不显示时的解决办法缺少 xx.RSA 文件的原因V1 vs V2Android 为什…

Coolify系列-解决局域网主机突然连不了虚拟机

开始之前&#xff0c;我们需要确保配置一切正常&#xff0c;原始配置参考下文 Coolify系列-手把手教学解决局域网局域网中的其他主机访问虚拟机以及docker服务 如果是之前已经配置好的&#xff0c;突然无法访问了&#xff0c;采取以下方式进行排查操作 在虚拟机执行 ifconf…

【GD32F427开发板试用】基于蓝牙的远程步进电机控制

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;寒冰1988 一、前言 接上篇文章【GD32F427开发板试用】基于蓝牙模块的远程点灯演示&#xff0c;本篇是第二篇&#xff0c;基于调通的蓝牙模块添…

Pytest-Allure测试报告

Allure 模块下载 pip install allure-pytest包下载 https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/此处我选择下载最新的&#xff0c;版本上可以选择不是最新的&#xff0c;2.9.0的。下载zip或者tgz后缀格式的都可以。 配置环境变量 找到解压…

RPA自动办公01——Uibot的安装和基础用法

本期开始RPA的学习流程。 RPA是机器人自动化流程的简写&#xff0c;目的在于减少重复性的劳动&#xff0c;而且上手很简单&#xff0c;无需编程就能用。 本系列使用Uibot 软件&#xff0c;其下载地址在&#xff1a;来也科技流程创造者&#xff08;UiBot Creator&#xff09; …

searchableSelect 插件使用

<script type"text/javascript" src"//searchableSelect.js"></script> <script>function getUserServer() {var _this 自定义封装接口请求、弹窗等方法;_this.getAjax("get","//xxxxx/server", {}, function(res)…

前端异常监控平台Sentry安装配置使用及问题

前言&#xff1a;Sentry是一款开源的异常监控平台,支持各种语言的SDK&#xff0c;通过对应SDK可以收集错误信息和性能数据&#xff0c;并可以再后台web页面中查看相关信息。官方地址&#xff1a;安装说明&#xff1a;https://develop.sentry.dev/self-hosted/后台使用说明&…

1.1计算机组成结构:CPU组成、冯·诺依曼结构与哈佛结构、嵌入式芯片术语

1.1计算机组成结构&#xff1a;CPU组成、冯诺依曼结构与哈佛结构、嵌入式芯片术语计算机组成结构CPU组成运算器控制器冯诺依曼结构与哈佛结构冯诺依曼结构哈佛结构嵌入式——芯片术语计算机组成结构 CPU组成 CPU分成两个部分&#xff0c;包括运算器和控制器。 CPU是计算机中核…

Linux之环境搭建

目录 一、VMware 二、centos7的安装 三、Mysql安装 四、 前端项目部署 1.确保前台项目能用 2.将前台项目打包npm run build 3.做ip/host主机映射 4.完成Nginx动静分离的default.conf的相关配置 5.将前端构件号的dist项目&#xff0c;上传到云服务器/usr/local/... …

[Swift]SDK开发

本文主要介绍使用swift语言制作framework Demo:https://github.com/Gamin-fzym/CMSDK 一、创建工程 1.创建目录 这里我创建了一个“CMSDK”目录 2.打开Xcode新建workspace放入CMSDK目录 这里命名为“CMSDK” 3.打开CMSDK.xcworkspace新建SDK工程放入CMSDK目录 这里还是命…

06 CSS-盒子模型【尚硅谷JavaWeb教程】

06 CSS-盒子模型【尚硅谷JavaWeb教程】 JAVAWEB的学习笔记 学习视频来自&#xff1a;https://www.bilibili.com/video/BV1AS4y177xJ/?vd_source75dce036dc8244310435eaf03de4e330 不同的浏览器导致前端展示页面不一样&#xff0c;盒子的大小的不同。&#xff08;所以前端要考虑…

奇迹mu开服教程

奇迹mu开服教程&#xff1a;开服服务端的架设及开服注意事项服务器推荐奇迹开服需要准备什么&#xff1f;开服大概成本分析奇迹MU商业服务端版本&#xff1a;1.02W、1.03H、1.03K、S6EP3、S7EP2、S9EP2&#xff1b;HE网站系统&#xff1a;绑定域名授权&#xff0c;功能可定制&a…

Jenkins部署项目一(物理机器部署SpringBoot项目)

一、Jenkins部署SpringBoot项目 设备&#xff1a;MacOS 准备工作 1.已安装java开发工具包JDK 2.已安装依赖管理工具Maven 3.已安装代码版本控制工具Git 4.已安装Jenkins learn-moon代码地址&#xff1a;https://github.com/BillDavidup/learn-moon SSH: gitgithub.com:Bil…

【学Vue就跟玩一样】如何使用集中式状态管理的Vuex以及如何模块化编码+命名空间

1.vuex是什么一个专门在Vue中实现集中式状态管理的一个Vue插件,可以对vue应用中多个组件的共享状态进行集中式的管理(读取/写入)&#xff0c;也是一种组件间通信的方式&#xff0c;并且适用于任意组件间通信2.什么时候使用Vuex1.多个组件依赖于同一状态2.来自不同组件的行为需要…

Goland入门指南(使用Goland创建并运行项目)

在文章《Goland下载和安装》详细介绍了 Goland 的安装和破解&#xff0c;本节我们来介绍一下怎么使用 Goland 来创建并运行一个项目。 创建项目 首先&#xff0c;在“文件”菜单中找到“New”&#xff0c;并在下一级菜单中选择“Project”来创建一个新项目。 为项目选择一个…