作者:mobiledu2502886633 | 来源:互联网 | 2023-06-04 18:19
一,JS部分
1.深、浅拷贝的区别?你知道哪些实现深拷贝的方法?
点击这里去往详细博客
2.如何判断一个函数是否作为了构造函数?
用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。同时它可以判断一个对象是否是另一个对象的实例。
- 语法:
object instanceof constructor
object
:某个实例对象constructor
:某个构造函数
如果是则返回true,不是返回false。如代码所示,new F()返回true,即this (指向的对象,下同)是F的实例,this也已经被实例化;所以F这时候是一个构造函数。如果是F()调用,返回了false,即this不是F()的实例化对象,即F()只是一个普通函数。
3.new操作符做了哪些事情?
new操作符新建了一个空对象,这个对象原型指向构造函数的prototype,执行构造函数后返回这个对象
- 首先创建一个新的空对象。
- 然后将空对象的隐式原型对象(__proto__)指向构造函数的原型对象。
- 这步操作将新对象的__proto__对象赋值为构造函数的prototype属性,使得能通过构造函数创建的所有对象可以共享相同的原型。
- 这就意味着通过一个构造函数创建的所有对象都继承自同一个相同的对象,因此它们是同一个类的对象。
- 改变this指向,使它指向空对象。
- 对构造函数的返回值进行判断,然后返回对应的值。
- 一般是返回第一步创建的空对象。
- 但是当构造函数有返回值时,则需要做出判断后再对应的值,时对象类型的则返回对象,是原始类型的则返回第一步创建的空对象。
4.什么是类数组,列举你知道的类数组转为数组的方法。
类数组对象,就是含有 length 属性的对象,但这个对象不是数组。 通常来说还会有 0 ~ length-1 的属性,结构表现上非常像一个数组。
const a = {1:'a', 4: 'd', length: 9};
Array.isArray(a) // false不是数组
类数组转数组
从底层上来看,这个对象的原型链上没有 Array.prototype,所以我们不能用 Array.prototype 上的 forEach、map 等数组特有的方法。
1.我们可以用 Array.prototype.slice 内置方法。
Array.prototype.mySlice = function(start, end) {if (start == undefined) start = 0;if (end == undefined) end = this.length;const cloned = new Array(end - start);for (let i = 0; i < cloned.length; i++) {// 为了确保不存在的索引保持为 empty 值if (i in this) {cloned[i] = this[start + i];}}return cloned;
}
[].slice.call(obj);//[] 空数组效果同 Array.prototype.
//1.调用数组原型对象上的slice方法,我们不给 slice 方法传开始和结束位置参数,这样就会默认取整个范围。
//2.然后 call 来自 Function.prototype,可以使用一个指定的 this 值来调用一个函数,这里是 Array.prototype.slice。我们不给 slice 方法传开始和结束位置参数,这样就会默认取整个范围。
//3.因为 slice 用于拷贝返回一个新的子数组,且只需要被操作的目标有 length 属性就行了。
2.Array.from(),ES6 新出的方法,可以将类数组对象或者是可迭代对象转换为数组。
const a = {1:&#39;a&#39;, 4: &#39;d&#39;, length: 9};
arr = Array.from(a);
console.log(arr);
//和 Array.prototype.slice.call() 有点不同,不存在的索引的值被设置了 undefined。
//如果一个对象,既是类数组对象,又是可迭代对象,Array.from() 方法会使用该对象的迭代器方法。
5. 如图,连续多次bind()的结果是什么?
bind()方法:bind() 方法为被选元素添加一个或多个事件处理程序,并规定事件发生时运行的函数。
想要弄懂bind()就需要知道为什么需要改变this指向。详细点击这里
我们要明白在js中,多次bind()
只有第一次绑定会生效。
- 后面的bind只能改变上一个bind的this指向,最终foo执行绑定的this是由第一次bind决定
- 因此不管foo执行多少bind,都是第一次bind绑定的对象
6.说说什么是防抖和节流?尝试自定义防抖函数debounce和节流函数throttle?
防抖:一个函数连续多次触发,我们只执行最后一次。
节流:一个函数连续多次触发,我们按照一定的时间间隔多次执行。
eg:
- 一个按钮被点击时,会发送网络请求。为了防止用户无意多次点击,或有人恶意连续发送请求,我们不希望按钮连续被点击时,每次都发送网络请求。而是过一定时间没有再点击时,我们才发送请求——即只执行最后一次,而这种操纵就是防抖。
- 滚动事件中会触发网络请求,但是我们不希望在滚动时一直发送网络请求,而是隔一定时间发起一次——这种操作就是节流。
防抖函数:
const foo = (fn, time = 500) => {let timer = null// 使用闭包(这样节流函数复用时,不会相互影响,且不污染全局变量)return function( ...args ) {// 如果在500毫秒内再次触发,即timer存在,此时清除掉这个timer,因此这里就实现了执行只最后一次if (timer) clearTimeout(timer)timer = setTimeout(() => {fn.apply(this, args) // 利用apply绑定this,同时展开args数组并传参}, time)}
}
节流函数:
// fn是要节流的函数,wait是时间间隔,默认500毫秒
const myThrottle = (fn, time= 500) => {let timer;return function( ...args ) {// 如果在500毫秒内再次触发,即timer存在,此时return,等待这个timer执行完毕。// 这里实现了时间间隔if (timer) return// 这里表示第一次触发,或是上一个timer执行完毕。就可以重新开启一个定时器。timer = setTimeout(() => {fn.apply(this, args)timer = null}, time)}
}
7.写出 [&#39;10&#39;, &#39;10&#39;, &#39;10&#39;, &#39;10&#39;, &#39;10&#39;].map(parseInt) 的结果
map()
方法定义在Javascript的Array
中,它返回一个新的数组,数组中的元素为原始数组调用函数处理后的值。
map()
不会对空数组进行检测map()
不会改变原始数组
parseInt()
函数解析字符串并返回整数。只返回字符串中的第一个数字!
它指定了要转换的字符串的基准进制(通俗点讲,就是告诉它,这个将被转换的字符串是几进制的)
那么本题按照对数组中每一个元素对进行下标的进制转换
[&#39;10&#39;,&#39;10&#39;,&#39;10&#39;,&#39;10&#39;,&#39;10&#39;].map(parseInt))等同于[&#39;10&#39;,&#39;10&#39;,&#39;10&#39;,&#39;10&#39;,&#39;10&#39;].map((item,index) => {return parseInt(item,index)
})
// parseInt(&#39;10&#39;, 0) 10
// parseInt(&#39;10&#39;, 1) NaN
// parseInt(&#39;10&#39;, 2) 2
// parseInt(&#39;10&#39;, 3) 3
// parseInt(&#39;10&#39;, 4) 4