1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
| 9、为什么把bind,call,apply放在一起?有什么区别(相同点,不同点) 干什么的?:用来改变this的指向的 var name = 'fff' function say(){ var name = 'ddd' log('this.name',this.name) } say() 相同点:bind,call,apply都可以改变this指向 不同点:call和apply的传参方式不同(前者挨个传,后者传入一个数组)/bind(返回的是绑定this一个函数)和call,apply的返回值不同 apply、call 则是返回函数调用立即执行 #三、实现 call的应用场景 *判断数据类型 const array = [1,2,3,4]; const type = 0bject.prototype.toString.call(array); console.log('type', type) *类数组转数组 const arrayLike={ 0:'name', 1:'age', 2:'gender', length:3 } const res = Array.prototype.slice.call(arrayLike)
apply 应用场景 对给定数组求最大值/最小值 const array = [1,2,3,4,5] const max = Math.max.apply(null,array)
bind应用场景 通常用在react项目的组件中 利用bind函数将this的指向指向组件的实例
10、如何使用多种方式实现数组去重 分普通数组和对象数组 array = [1,2,3,4,5] indexOf 查找项的下标 没找到-1 filter 返回值[] sort 返回值[] 接收两个参数 返回a-b 从小到大排序 reduce 返回值[] const res = array.reduce(function(prev,current){return prev+current}) push 返回值length const array = [1,2,3,4,5,2,3]
过滤解决 function unique(array) { if( !Array.isArray(array)){ throw new Error( "unique function params is not Array")} return array.filter((item,index)=>{ return array.index0f(item)===index }) } const res = unique(array)
排序解决 function unique(array) { if(!Array.isArray(array)){ throw new Error( "unique function params is not Array")} array = array.sort() let res=[]; for(let i=0;i<array.length;i++){ if(array[i]!==array[i-1]){ res.push(array[i]) } } return res } const res = unique(array)
解构赋值解决 (先转化为集合 集合里的元素就已经是唯一的了 然后再解构赋值) function unique(array) { if(!Array.isArray(array)){ throw new Error( "unique function params is not Array")} return [...new Set(array)] } const res = unique(array)
11.怎么对给定数组求最大值 应用场景:数据处理的时候可以用到给定数组求最大值 Math.max()方法 const array = [1,2,3,4,5] const res = Math.max(...array) *** 或者借用这个函数 const res = Math.max.apply(null,array)
reduce函数方法 function getMax(array){ return array.reduce((prev,current)=>{ return current>prev?current : prev 或者return Math.max(prev,current) }) } const res = getMax(array)
sort()排序方法 function getMax(array){ const result = array.sort() return result[result.length-1] } const res = getMax(array) 考察的是对基本的数据处理能力
12.JS中判断数据类型的方式有哪些? typeof 优点:使用简单 也不精确 比如 typeof [] 会输出Object(数组本身就) 缺点:功能残缺,只能用来判断6种数据类型:string,number,boolean,undefined,symbol,function type of null symbol 的值是通过 Symbol() 函数生成,每一个 symbol 的值都是唯一的
Object.prototype.toString.call 优点:适用于判断所有数据类型 缺点:使用上相对typeof而言比较繁琐
instanceof(排除):instanceof运算符用于检测构造函数的prototype属性是否出现在某个实例对象的原型链上
js中判断数据类型的场景? 根据接口/返回参数类型/做区别处理。 js中的数据类型有些哪些? 基本数据类型:String、Number、Boolean、Symbol、undefined、Null 引用数据类型:Object、Array、Function
13.如何实现函数节流 (项目优化) 函数节流:规定在一个单位时间内,事件响应函数只能被触发一次。如果这个单位时间内触发多次函数,只有一次生效 使用场景:window.onresize事件 该事件是浏览器的视口不断被放大缩小的时候触发的 mousemove事件,鼠标拖动事件 这两个事件不断别触发 导致性能开销过大 因此要使用函数节流 window.onresize():函数节流 单位时间内触发一次 1.返回值是一个函数 2.开启定时器 3.如果定时器存在,直接返回false 4.定时器内部清空定时器,并且把timer置为null 然后执行我们的事件响应函数 function throttle(fn,interval) { var timer; return (event)=>{ if (timer){ return false; } timer = setTimeout(()=> { clearTimeout(timer); timer = null; fn(event)}, interval); } } window.onresize = throttle(function(event)){ log(event) }
14.如何实现函数防抖 事件防抖:事件被触发n秒后再执行回调,如果在这n秒执行过程中又被触发,则会把之前的事件响应清除掉,事件函数只执行一次。 使用场景:网站商品搜索框 1.返回值是一个函数 2.事件响应函数式在固定间隔试行的 <input type="text" id = "searchElement"> const SearchElement = document.getElementById("searchElement") function debounce(fn, delay){ let timer = null return ()=>{. clearTimeout(timer) timer = setTimeout(fn,delay) } } SearchElement.oninput = debounce(function(event)){ const value = searchElement.value log('value',value) ,1000}
15.如何使用多种方式实现数组拍平 概念 :数组拍平也叫数组扁平化、数组拉平、数组降维。**指的是把多维数组变成一维数组**。 使用场景:复杂场景下的数据处理 实现数组拍平的具体实现: const array = [1,2,3,4,[5,6,[7,8]]] array [1,2,3,4,5,6,7,8]; 1.使用reduce实现
function flatten(array) { return array.reduce(function(prev,current){ return prev.concat(Array.isArray(current)?flatten(current):current) },[]) }
const result = flatten(array); console.log(`result`, result);
function flatten(array) { return array.flat(Infinity); } const result = flatten(array) console.log(`result`, result);
function flatten(array) { while (array.some(Array.isArray)){ array = [].concat(...array) } return array; }
const result = flatten(array); console.log(`result`, result);
16.什么情况会使判断成立 let value = 0; Object.defineProperty(window,'a',{ get(){ return value += 1; } }); if(a===1&&a===2&&a===3){ console.log(`object`) } 17.实现new操作符 实际使用场景:封装第三方的工具(通过构造函数进行封装) const TMap = function(options){ this.name = options.name; this.address = options.address; return{ name:'map', address:'SZ' } }
const map = new TMap({ name: 'tmap', address:"BJ" });
console.log('map :>> ', map); 使用new操作符实例化后的对象有两种情况:如果构造函数里没有返回值的话,实例化对象输出的就是构造函数里的实例属性和方法 BJ 如果构造函数里有返回值的话,实例化对象就是那个返回值 SZ 如何实现new操作符 ->难先不看
18.实现一个bind函数 function origin(a,b){ console.log(this.name); console.log([a,b]); } const obj = { name:"freemen" } const func = origin.bind(obj,2); func(1) **模拟一个bind函数** 难先不看 bind函数的实现原理 1. bind 函数改变this指向 2. bind 函数是Function.prototype上的方法 3. bind 函数的返回值也是函数 4. bind 函数调用之后返回的函数的参数同样也接收处理
如何实现call和apply函数 apply入参方式是以数组传递的 实现也很难先不看 call 1.改变this指针 2.返回函数调用 3.参数挨个依次传递 apply 1.改变this指针 2.返回函数调用 3.数组方式传参
19.实现instanceof function Persion(){ this.name = "freemen" } const obj = new Persion
console.log(obj instanceof Persion) instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function instance_of(Obj, Constructor){ let implicitPrototype = Obj.__proto__; let displayPrototype = Constructor.prototype; while(true){ if(implicitPrototype === null){ return false }else if (implicitPrototype === displayPrototype){ return true } implicitPrototype = implicitPrototype.__proto__ } }
const has = instance_of(obj,Persion) console.log(`has`, has)
实现原理: 1. 获取实例对象的隐式原型 2.获取构造函数的prototype属性 3. while 循环->在原型链上不断向上查找 4. 在原型链上不断查找构造函数的显式原型 5,直到实例对象的隐式原型 = null都没找到,返回false 6.构造函数的prototype属性出现在实例对象的原型链上返回true (构造函数的显式原型===实例对象的隐式原型)
20.总结: 1、什么是原型和原型链? 1.什么是原型 在javascript中,函数可以有属性。每个函数都有一个特殊的属性叫作原型(prototype) 每个对象都会在其内部初始化一个属性,就是prototype(原型)
2.什么是原型链 原型链就是当我们访问对象的某个属性或方法时,如果在当前对象中找不到定义,会继续在当前对象的原型对象中查找,如果原型对象中依然没有找到,会继续在原型对象的原型中查找(原型也是对象,也有它自己的原型)如此继续,直到找到为止,或者查找到最顶层的原型对象中也没有找到,就结束查找,返回undefined。可以看出,这个查找过程是一个链式的查找,每个对象都有一个到它自身原型对象的链接,这些链接组件的整个链条就是原型链
3·原型和原型链存在的意义是什么? **使得实例对象可以共享构造函数原型上属性和方法**,节省内存。构造函数原型上的属性和方法越多,节省内存越大.
2如何理解作用域和作用域链? 讲清楚如下三点: 1.什么是作用域? 作用域是在运行时代码中的某些特定部分中**变量,函数和对象的可访问性**,作用域决定了代码区块中变量和其他资源的可见性。
2.作用域存在的意义是什么? **不同作用域下同名变量不会有冲突。** 作用域存在的最大意义就是变量隔离即: 3.什么是作用域链? 当我们在某个函数的内部作用域中查找某个变量时,如果没有找到就会到他的父级作用域中查找,如果父级也没找到就会接着一层一层的向上寻找,直到找到全局作用域还是没找到的话,就宣布放弃。这种一层一层的作用域嵌套关系,就是作用域链
3、你对闭包怎么理解? 讲清楚如下三点:
1.什么是闭包? **一个函数作用域能够访问另外一个函数作用域中的变量的函数** **闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找。不是在执行的地方!!!** bind方法只有在Function.prototype
2.闭包有哪些实际的使用场景? 1.事件函数的封装 2.用闭包模拟私有方法 3.在循环中给页面元素绑定事件响应函数 使用闭包主要为了设计私有的方法和变量 3.闭包存在什么问题? 好处是可以延伸这个变量的使用范围 缺点:闭包本身会造成内部变量常驻内存,会增大内存使用量,使用不当很容易造成内存泄露 原因就是在函数执行结束之后不会将变量进行销毁
|