js面试
js知识点
1.常见的值和引用类型
值:
- undefine
- 字符串
- 数值
- bool
- symbol
引用:
- 对象
- 数组
- null
2.深拷贝与浅拷贝
对于一种问题,比如对象的引用
let obj1 = obj2
obj1.name = “aa”
那么,obj2的name也会因此改变,这就是浅拷贝
这两个对象实例都是指向的同一块内存空间,如果是深拷贝的话,就不会出现这种问题。深拷贝就相当于是把原对象通过递归的方式,将原对象原原本本的复制过去。这样,这个对象实例就变成了一个独立的个体,有着自己的内存空间。
1 | function deepClone(obj={}){ |
上述代码为深拷贝,主要的内容就是对对象中的对象进行递归遍历
3.parseInt
字符串转数字:parseInt
如果遇到字符串拼接问题
return 100+"10"返回的就是一个字符串
如果想要返回纯数字,那么就需要return 100+parseInt("10")
4.什么时候用== 和===
大部分情况下都可以用===
只有在判断空的时候可以用==
因为==会做一个强制的类型转换,可能会得到错误的结果
5.truly和falsely变量

1 | !!0 === false |
只要两次取反结果为true的变量就是truly变量
==if语句()中判断的就是truely变量和falsely变量==
==逻辑判断同理==
6.instanceof类型判断
从字面意思可以看出,instanceof就是看前者是不是后者的一个实例
instanceof会根据原型链一层一层的往上找,如果找到了就会返回一个true
7.隐式原型和显式原型

__proto__是隐式原型prototype是显式原型
8.原型链

对于原型链,我是这么理解的:
xialuo作为student类的一个实例,他的隐式原型就指向student的显示原型,而Student类继承于父类People,所以student也有一个隐式原型去指向父类people的显示原型
9.手写jQuery
1 | class jQuery { |
其中each()中的fn就是回调函数
10.闭包

对于闭包,对自由变量的查找,是从函数定义的地方开始的,然后向上级作用域一层一层的查找,直到window,而不是在执行的地方
11.property和attribute

尽量使用property,这个引起dom渲染的可能性较小
12.转化为数组

Array.prototype.slice.call(转化对象)
13.dom操作性能优化

通过createDocumentFragment(),创建一个文档片段,插入到文档片段的dom元素并不会立即被渲染,会在后续appendChild中统一渲染
14.事件代理(基于冒泡)

由于事件的冒泡行为,事件会向上进行传递

15.跨域问题
1.jsonp方式
因为script是可以跨域的,所以,可以通过script便签去请求网址,通过这个去传数据
另外也可以通过ajax传递

2.CORS通过服务器进行设置
通过服务端设置可信任的端口或者域名
16.手写ajax

1 | function ajax(url){ |
17.本地存储cookie,localstorage,sessionstorage
不同点:
设置值不同
cookie:通过document.cookie=''设置,并且不会覆盖,会类似于push的方式跟在后面,最大存储4k,每次向服务器发送请求都会跟着进去。
localStorage和sessionStorage:
从字面意思就可以看出,sessionStorage是只存在于本次会话,当浏览器关闭时,就会消失。
而localStorage可以存储在本地
这两个最大可以存储5M,通过setItem设置,getItem获取
并且不会随着http请求发送出去
综上,一般用localStorage比较多
18.手写防抖
防抖就是防止一个事件多次被触发,比如输入事件,按下键,的事件会被不停的触发,所以需要做出防抖,比如延时一段时间后才去执行某个函数
1 | function debounce(fn,delay = 500){ |
19.手写节流
对于类似拖拽事件,会触发很多事件,这时候就可以使用节流,每隔一段时间触发一次,而不是每动一下就触发一次,这样体感感觉不到,而且性能也有提升
20.多重解构
1 | const school = { |
1 | const { classes: { stu: { name } }} = school |
通过这种方式可以解构更加深层的属性
21.对属性访问的两种方式”. && []”
这两种方式都可以去的属性的值,但某些场景只能使用数组表示法才可以行得通
比如
1 | function foo(portfolio, stockname, shares){ |
在使用.操作符访问对象的属性的时候,属性名是通过标识符来表示的,标识符必须直接书写在js程序中,他们不是一种数据类型,不能被程序操作
上述文字是犀牛书的原文解释,例如上述的例子,stockname这个属性是对象通过[]也就是数组方式进行调用的,并不能通过.的形式进行调用。同时,如果你尝试用.进行调用,那么再编辑器上书写的时候,就会出现该参数未被使用的提示(vscode)。
通过这个例子可以简单的得出一个结论:通过.进行调用的是标识符,他不属于基本数据类型的一种,所以它不能通过函数进行动态的添加标识符,比如上述的例子中,属性名stockname是用户输入动态传入的,而标识符他是一个静态的,必须通过硬编码到程序中,也就是说需要我们去手动书写,而不是让代码去动态获取
所以最终的结论就是:==如果是需要通过函数或者程序动态进行操作对象属性名的,那么就只能使用[],数组方法去实现====如果是手动进行定义的对象属性名,那么[]数组方法和.调用都可以==
==一句话就是:用手写的用[]和.用代码写的用[]==,结束。
22.数组方法(改不改变原数组)
不改变原数组:map()






