ホームページ > 記事 > ウェブフロントエンド > 高頻度の知識ポイントを習得するために、これらのフロントエンドの面接の質問を見てください (8)
この記事は、JavaScript の面接での質問をいくつかまとめたもので、使用頻度の高い知識ポイントを習得するのに役立ちます。
let | const | var | ||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
繰り返し宣言することはできません。SyntaxError が報告されます | const 定数を定義します。値を変更できない変数を定数と呼びます。初期値を割り当てる必要があります。変更できないからです。 | 繰り返し宣言可能 | ||||||||||||||||||||||||||||||||||||||||||||||||||||
所有 | 所有 | 所有されていない | #グローバル変数 (ウィンドウにマウントされている) を汚染しますか | |||||||||||||||||||||||||||||||||||||||||||||||||||
No | Yes |
説明
let answer; function fn(){ //如果此时没有将变量变量提升到这里,answer应该取外层answer的值 console.log(answer); //Uncaught ReferenceError: Cannot access 'answer' before initialization let answer=42; }2. var によって作成されたグローバル変数 -> グローバル オブジェクトの属性、let および const -> によってグローバル スコープで宣言された変数は、グローバル オブジェクトの属性ではありません3 定数が配列またはオブジェクトの場合、その内部要素への変更は定数への変更としてカウントされず、エラーは報告されません。定数はアドレスを指します。アドレスが変更されない場合、エラーは報告されません。 変数のプロモーションと関数のプロモーション
# #スコープとスコープ チェーン理解: コード セグメントが配置される領域。 は静的であり、はコードの作成時に決定されます。 関数: 変数バインディングはこのスコープ 内で有効であり、変数を分離し、異なるスコープ内の同じ名前の変数と競合することはありません。
関数のスコープは宣言時に決定され、呼び出し位置とは関係ありません。 したがって、aaa() を実行するときは、まず aaa のスコープ内を検索します。 a、親スコープ ウィンドウに移動し、 a=10 実行コンテキスト を見つけます。現在の JavaScript 実行環境 要約: JavaScript は実行を開始するたびに、実行コンテキストで実行されます。#グローバル実行コンテキスト: グローバル コードを実行する前にウィンドウをグローバル実行コンテキストとして決定します
#var --> 未定義、ウィンドウのプロパティとして宣言されたグローバル関数を追加
arguments (仮パラメータ リストにカプセル化された擬似配列) --> 割り当て (実際のパラメータ リスト)、に追加関数実行コンテキストの属性 var で定義されたローカル変数 –>未定義、関数実行コンテキストの属性
4. 現在の関数が実行された後、オブジェクトを削除しますスタックの最上位 (スタックをポップ) 5. すべてのコードが実行されると、ウィンドウ
this的指向
bind、call、apply的区别与实现apply、call、bind 函数可以改变 this 的指向。
bind函数的特殊点 call函数的实现 //从第二个参数开始依次传入,所以接收时使用rest参数 Function.prototype.call=function(obj,...args){ obj = obj || window; args = args ? args : []; //给obj新增一个独一无二的属性以免覆盖原有属性 const key = Symbol() obj[key] = this; const res = obj[key](...args); delete obj[key]; return res; } apply函数的实现 Function.prototype.apply=function(obj,args){ obj = obj || window; args = args ? args : []; //给obj新增一个独一无二的属性以免覆盖原有属性 const key = Symbol() obj[key] = this; const res = obj[key](...args); delete obj[key]; return res; } bind函数的实现 Function.prototype.bind=function(obj,...args){ obj = obj || window; args = args ? args : []; return (...args2) => { return this.apply(obj,[...args,...args2]) } } 一般函数和箭头函数箭头函数的作用:确保函数内部的this和外部的this是一样的 箭头函数是普通函数的语法糖,书写要更加简洁
闭包是什么
function foo(){ var a=2; function bar(){ //覆盖foo()内部作用域的闭包 console.log(a++); } return bar; } var bar = foo(); //foo执行创建一个执行上下文环境,由于bar引用了其内部变量,也就是bar持有foo本次执行上下文的引用,foo本次的执行上下文不会被销魂 bar();//2 bar();//3 var fn = foo(); //foo执行创建一个新的执行上下文环境,fn持有了foo本次执行上下文的引用 fn();//2 有什么用 JavaScript闭包就是在另一个作用域中保存了一份它从上一级函数或者作用域得到的变量,而这些变量是不会随上一级函数的执行完成而销毁 常用场景:节流防抖 手写节流和防抖函数作用是:控制回调函数触发的频率,进行性能优化 节流:在函数被频繁触发时, 函数执行一次后,只有大于设定的执行周期后才会执行第二次。一个时间段,只触发一次 //使用形式,绑定时候throttle函数就会执行,所以this是window window.addEventListener('scroll',throttle(()=>{},500)) /* 思路 需要记录上一次触发的时间,才可以和当前时间比较,是否超过了间隔时间 第一次必然立刻触发 */ function throttle(callback,wait){ let pre = new Date(); //这里的this是window return function(...args){ //这里的this是绑定的DOM const now = new Date(); if(now-pre>=wait){ callback.apply(this,args); pre = now; } } } /* 使用setTimeout实现 第一次需要延迟delay后触发 */ function throttle(callback,delay){ let timer = null; //这里的this是window return function(...args){ if(timer){//说明已经触发了 return; } timer = setTimeout(()=>{ callback.apply(this,args); timer = null; },delay) } } 函数防抖:指定时间间隔内只会执行一次任务。如果在等待的过程中再一次触发了事件,计时器重新开始计时,直到达到时间后执行最后一次的回调 function debounce(callback,delay){ let timer = null; //这里的this是window return function(){ if(timer){//说明已经触发了 clearTimeout(timer); } timer = setTimeout(()=>{ callback.apply(this,arguments); timer = null; },delay) } } //立即执行 function debounce(func,delay) { let timeout; return function (...args) { if (timeout) clearTimeout(timeout); const callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, delay) if (callNow) func.apply(this, args) } } 原型和原型链
JavaScript 线程机制与事件循环机制内容
DOM渲染内容
重绘和回流内容
setTimeout 、setInterval、requestAnimationFrame内容
观察者模式和发布订阅机制观察者是软件设计模式中的一种,但发布订阅只是软件架构中的一种消息范式 观察者模式 观察者模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。 被依赖的对象叫做 //subject 被观察者 class Subject { constructor() { this.observerList = []; } addObserver(observer) { this.observerList.push(observer); } removeObserver(observer) { const index = this.observerList.findIndex(o => o.name === observer.name); this.observerList.splice(index, 1); } notifyObservers(message) { const observers = this.observeList; observers.forEach(observer => observer.notified(message)); } } //Observer 观察者 class Observer { constructor(name, subject) { this.name = name; if (subject) { subject.addObserver(this); } } notified(message) { console.log(this.name, 'got message', message); } } //使用 const subject = new Subject(); const observerA = new Observer('observerA', subject); const observerB = new Observer('observerB'); subject.addObserver(observerB); subject.notifyObservers('Hello from subject'); subject.removeObserver(observerA); subject.notifyObservers('Hello again'); 发布订阅机制 //事件调度中心 class PubSub { constructor() { // 存储格式: warTask: [], routeTask: [] // {订阅事件:[回调1,回调2...],订阅事件2:[回调1,回调2..]} this.events = {} } // 订阅方法 订阅哪个类型type就把对应的回调函数放入 subscribe(type, cb) { if (!this.events[type]) { this.events[type] = []; } this.events[type].push(cb); } // 发布方法 publish(type, ...args) { if (this.events[type]) { this.events[type].forEach(cb => cb(...args)) } } // 取消订阅方法 的某一个类型的某一个回调 unsubscribe(type, cb) { if (this.events[type]) { const cbIndex = this.events[type].findIndex(e=> e === cb) if (cbIndex != -1) { this.events[type].splice(cbIndex, 1); } } if (this.events[type].length === 0) { delete this.events[type]; } } } //测试 let pubsub = new PubSub(); //订阅 pubsub.subscribe('warTask', function (taskInfo){ console.log("宗门殿发布战斗任务,任务信息:" + taskInfo); }) pubsub.subscribe('routeTask', function (taskInfo) { console.log("宗门殿发布日常任务,任务信息:" + taskInfo); }); pubsub.subscribe('allTask', function (taskInfo) { console.log("宗门殿发布五星任务,任务信息:" + taskInfo); }); //发布 pubsub.publish('warTask', "猎杀时刻"); pubsub.publish('allTask', "猎杀时刻"); pubsub.publish('routeTask', "种树浇水"); pubsub.publish('allTask', "种树浇水"); 区别
异步编程解决方案 Generator生成器函数 async/await、Promise笔记内容
扩展运算符的原理和应用浅拷贝和深拷贝深浅拷贝只是针对引用数据类型
浅拷贝
深拷贝方式一: JSON.parse(JSON.stringify())
问题1: 函数属性会丢失,不能克隆方法 //循环引用:b中引用了c,c中又有b obj = { b:['a','f'], c:{h:20} } obj.b.push(obj.c); obj.c.j = obj.b; b:['a','f',{h:20,j:[]}], c:{h:20,j:['a','f',[]]} function deepClone1(target) { //通过数组创建JSON格式的字符串 let str = JSON.stringify(target); //将JSON格式的字符串转换为JS数据 let data = JSON.parse(str); return data; } 方式二:递归+map //map存放已经拷贝过的对象,key为需要拷贝的对象,value为拷贝后的对象 function deepClone(target,map=new Map()){ //1.判断是否是引用类型 if(typeof target === 'object' && target !==null ){ if(map.has(target))return map.get(target); //说明已经拷贝过了 let isArr = Array.isArray(target); let res = isArr?[]:{}; map.set(target,res) if(isArr){//拷贝的是数组 target.forEach((item,index) => { res[index] = deepClone(item,map); }); }else{//拷贝的是对象 Object.keys(target).forEach(key=>{ res[key]=deepClone(target[key],map); }) } return res; //返回的是一个数组或对象 }else{ return target; } } //测试 console.log(deepClone([1,[1,2,[3,4]]])) commonJS和ES6模块化内容
【推荐学习:javascript高级教程】 |
以上が高頻度の知識ポイントを習得するために、これらのフロントエンドの面接の質問を見てください (8)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。