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

js

1.原始类型

boolean number string null undefined symbol
原始类型储存的都是值,是没有函数可以调用的,undefined.toString() 显示报错,
但是'1'.toString() // "1" ; 是因为'1'被强制转换成了string类型,已经不是原始类型而是对象类型了;
用typeOf可以判断除了null的原始类型,typeOf null // OBJECT
判断null为object类型,其实这是js的一个bug, JS的最初版使用32位系统,为了性能考虑使用低位储存变量信息,000开头表示对象,而null都是0,所以判断null显示为对象。

2.对象类型

对象类型和原始类型的不同之处?函数参数是对象会发生什么问题?

再JS中除了原始类型之外都是对象类型,原始类型储存的是值,而对象类型储存的是地址(指针),

const a = [];

我们假设常量a的指针是#001, 那么#001存放了值是[];

const a = [];
const b = a;
b.push(1);

根据上面所说,我们将常量a的值赋给b,其实是将a的指针传给了b,即b也变成了#001,
那么当我们改变b的值其实是改变了#001的值,同样会导致a的值发生变化;

接下来我们看看函数参数是对象的情况来看看

function test(person) {
  person.age = 26
  person = {
    name: 'yyy',
    age: 30
  }

  return person
}
const p1 = {
  name: 'wpp',
  age: 25
}
const p2 = test(p1)
console.log(p1) // -> ?
console.log(p2) // -> ?

答案是什么呢?
我们来分析一下
首先,函数传参是传递对象指针的副本,
到函数内部修改参数的属性这步,p1的值也被修改了,
但是我们重新为person分配了一个对象时就出现了分歧,
所以最后person拥有了一个新的指针,也就和p1没有任何关系了,导致最终两个的值是不一样的。

clipboard.png

3.typeOf vs instanceof

typeof 是否能正确判断类型?instanceof 能正确判断对象的原理是什么?

typeOf对于原始类型除了null之外都能正确判断,而对于判断对象,除了函数都会显示object,所以我们不能使用typeOf来判断对象的类型;
如果我们想去判断一个原始类型我们可以使用instanceof来判断;其内部机制是通过原型链来判断的
对于原始类型我们直接使用instanceof来判断是不行的,当然我们还要办法使用instanceof来判断原始类型;

class PrimitiveString {
  static [Symbol.hasInstance](x) {
    return typeof x === 'string'
  }
}
console.log('hello world' instanceof PrimitiveString) // true

你可能不知道 Symbol.hasInstance 是什么东西,其实就是一个能让我们自定义 instanceof 行为的东西,以上代码等同于 typeof 'hello world' === 'string',所以结果自然是 true 了。这其实也侧面反映了一个问题, instanceof 也不是百分之百可信的。

4.This

如何正确判断 this?箭头函数的 this 是什么?

谁最后调用了this,this就指向谁

function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()

我们来分析一下上面的级格场景

  • 直接调用foo() ,this指向windows;
  • obj.foo obj最后调用foo,this指向obj;
  • 对于new来说this被绑定在了c上面。不会被改变;

接下来我们看看箭头函数中的this指向情况,

function a() {
  return () => {
    return () => {
      console.log(this)
    }
  }
}
console.log(a()()())

首先箭头函数其实是没有 this 的,箭头函数中的 this 只取决包裹箭头函数的第一个普通函数的 this。在这个例子中,因为包裹箭头函数的第一个普通函数是 a,所以此时的 this 是 window。另外对箭头函数使用 bind 这类函数是无效的。

最后种情况也就是 bind 这些改变上下文的 API 了,对于这些函数来说,this 取决于第一个参数,如果第一个参数为空,那么就是 window。
以上就是 this 的规则了,但是可能会发生多个规则同时出现的情况,这时候不同的规则之间会根据优先级最高的来决定 this 最终指向哪里。

首先,new 的方式优先级最高,接下来是 bind 这些函数,然后是 obj.foo() 这种调用方式,最后是 foo 这种调用方式,同时,箭头函数的 this 一旦被绑定,就不会再被任何方式所改变。

clipboard.png

5.== vs ===

== 和 === 有什么区别?

对于 == 来说,如果对比双方的类型不一样的话,就会进行类型转换
对于 === 来说就简单多了,就是判断两者类型和值是否相同

6.闭包

什么是闭包?

简单来讲就是函数A内有函数B,并且函数B可以访问到函数A中的变量,函数B就叫做闭包。
JS中闭包存在的意义是什么呢?
是为了让我们间接访问到函数内部的变量,
一个面试经典问题

for (var i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i)
  }, i * 1000)
}

首先因为 setTimeout 是个异步函数,所以会先把循环全部执行完毕,这时候 i 就是 6 了,所以会输出一堆 6。
第一种方式

for (var i = 1; i <= 5; i++) {
  ;(function(j) {
    setTimeout(function timer() {
      console.log(j)
    }, j * 1000)
  })(i)
}

第二种方式

for (let i = 1; i <= 5; i++) {
  setTimeout(function timer() {
    console.log(i)
  }, i * 1000)
}

直接使用let来代替var 也能解决这个问题

7.深拷贝和浅拷贝

什么是浅拷贝?如何实现浅拷贝?什么是深拷贝?如何实现深拷贝?

我们了解了对象类型在赋值的过程中其实是复制了地址,从而会导致改变了一方其他也都被改变的情况。通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个情况

浅拷贝

首先可以通过 Object.assign 来解决这个问题,很多人认为这个函数是用来深拷贝的。其实并不是,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

浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到最开始的话题了,两者享有相同的地址。要解决这个问题,我们就得使用深拷贝了。

深拷贝

这个问题通常可以通过 JSON.parse(JSON.stringify(object)) 来解决。
但是这个方法也有局限性

  • 会忽略undefined
  • 会忽略symbol
  • 不能序列化函数
  • 不能解决循环引用的问题

但是大部分情况这个方法都可以适用

8.原型

如何理解原型?如何理解原型链?

每个 JS 对象都有 proto 属性,这个属性指向了原型。这个属性在现在来说已经不推荐直接去使用它了,这只是浏览器在早期为了让我们访问到内部属性 [[prototype]] 来实现的一个东西。
好像还是没有弄明白什么是原型,接下来让我们再看看 proto 里面有什么吧。

clipboard.png
看到这里我们会发现原型也是对象,并且这个对象中包含了很多函数,所以我们可以得出一个结论:对于 obj 来说,可以通过 proto 找到一个原型对象,在该对象中定义了很多函数让我们来使用。
在上面的图中我们还可以发现一个 constructor 属性,也就是构造函数
打开 constructor 属性我们又可以发现其中还有一个 prototype 属性,并且这个属性对应的值和先前我们在 proto 中看到的一模一样。所以我们又可以得出一个结论:原型的 constructor 属性指向构造函数,构造函数又通过 prototype 属性指回原型,但是并不是所有函数都具有这个属性,Function.prototype.bind() 就没有这个属性。

clipboard.png
https://juejin.im/post/5c4fdb...
原型的详细介绍

9.类型转换

再JS中类型转换只分三种情况:
转换成布尔值,转换成数字,转换成字符串;

相关文章:

  • PHP multipart/form-data 远程DOS漏洞
  • java 内存分析 jmap
  • 功能架构图、信息结构图、产品结构图的区别和绘制方法
  • 我们雇佣了一只大猴子...
  • 关于Android P 开发者预览版首发
  • Flink1.7.2 local WordCount源码分析
  • PyQt5 -day3-3 格栅布局 又叫 网格布局
  • 云服务器绑定主机名的正确姿势
  • 第十八天-企业应用架构模式-基本模式
  • 移植之乱谈
  • HTTP 2.0与OkHttp
  • 360旗下公司推出区块链宠物游戏“恋猫”,要和360区块猫竞争吗
  • 项目微管理8 - 流程
  • vue axios ajax
  • z-index
  • @jsonView过滤属性
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 10个最佳ES6特性 ES7与ES8的特性
  • 230. Kth Smallest Element in a BST
  • ERLANG 网工修炼笔记 ---- UDP
  • JS字符串转数字方法总结
  • nginx 负载服务器优化
  • Ruby 2.x 源代码分析:扩展 概述
  • Service Worker
  • Spring技术内幕笔记(2):Spring MVC 与 Web
  • zookeeper系列(七)实战分布式命名服务
  • 程序员最讨厌的9句话,你可有补充?
  • 第13期 DApp 榜单 :来,吃我这波安利
  • 日剧·日综资源集合(建议收藏)
  • 我看到的前端
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​​​​​​​Installing ROS on the Raspberry Pi
  • ​Z时代时尚SUV新宠:起亚赛图斯值不值得年轻人买?
  • (06)Hive——正则表达式
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)ssm码农论坛 毕业设计 231126
  • (一)u-boot-nand.bin的下载
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转) SpringBoot:使用spring-boot-devtools进行热部署以及不生效的问题解决
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选
  • .net 反编译_.net反编译的相关问题
  • .NET/C# 使窗口永不激活(No Activate 永不获得焦点)
  • .NET国产化改造探索(三)、银河麒麟安装.NET 8环境
  • .sys文件乱码_python vscode输出乱码
  • [ 数据结构 - C++] AVL树原理及实现
  • [Android 13]Input系列--获取触摸窗口
  • [Android]使用Git将项目提交到GitHub
  • [Angular] 笔记 21:@ViewChild