> 헤드라인 > 3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

青灯夜游
풀어 주다: 2022-12-16 19:59:03
앞으로
3778명이 탐색했습니다.

올해 취업 상황은 그야말로 암울합니다. 내년은 올해보다 더 안 좋을 것이라는 '운이 좋은 마음'으로 한달 반 동안 고민한 끝에 꽤 좋은 제안을 받았습니다. , 급여 및 플랫폼이 크게 개선되었지만 여전히 내 심리적 기대와는 큰 격차가 있습니다. 그래서 가장 큰 결론은: 노골적으로 말하지 마세요! 알몸으로 아무 말도 하지 마세요! 알몸으로 아무 말도 하지 마세요! 인터뷰를 하면서 받는 압박감과 현실과 이상의 괴리로 인한 심리적 피해는 헤아릴 수 없을 만큼 크기 때문에 그런 환경에서 살아남는 것이 좋은 선택이다.

관련 추천: 2023년 대규모 프론트엔드 면접 질문 요약(모음)

다음은 일반적인 상황에서 프론트엔드 인터뷰에서 경험하게 될 다음 4단계와 3가지 결정 요소를 요약한 것입니다.

3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인프론트엔드 직원으로서는 기술의 깊이와 폭이 1위입니다. 이때 자신의 위치와 방향을 찾아야 합니다.

둘째, 좋은 의사소통 능력과 표현력, 의상과 퍼포먼스, 기타 오프사이트 요소는 면접관의 인지도를 높일 수 있습니다.

어떤 사람들은 매우 능숙하지만 면접관은 당신이 오만하고 엉성하며 독선적이며 명확하게 표현하지 못한다고 생각하여 당신을 거부할 것입니다.

다음은 제가 받은 질문과 제가 준비한 전체 내용을 요약한 것입니다. 왜냐하면 면접 과정에서 면접관과의 의사소통은 대체로 단순한 승인이 아니기 때문에 자신의 지식을 전달하는 것이 가장 좋습니다. 요약하고 간결하게 표현한 후, 면접관의 질문에 따라 즉석에서 완성합니다. [추천 학습: 웹 프론트 엔드, 프로그래밍 교육]

1. 자기 소개

면접관은 자기 소개를 요구하며, 자기 소개의 범위를 제한하지 않습니다. 자기소개서에서 배우기 나는 당신을 알고 있으므로 소개는 짧고 원활해야 합니다. 다른 면접관을 만나도 자기소개서의 내용은 똑같을 수 있으므로 미리 단어를 준비하고 확실하게 하는 것이 중요합니다. 주의를 기울이십시오: 넘어지지 말고 자신감을 가지십시오! 원활한 표현력과 소통 능력도 면접관이 지원자를 평가하는 포인트 중 하나입니다. 나도 면접관이었는데, 자신감 있고 관대한 지원자가 선호될 가능성이 더 높습니다.

1. 기본 이력서를 포함한 개인 소개(기본 정보)는 짧아야 합니다

2. 기술적인 것과 비기술적인 것을 포함하여 자신이 잘하는 것. 기술적인 사람들은 당신의 전환을 이해할 수 있고, 기술적인 사람이 아닌 사람들은 당신을 사람으로 이해할 수 있습니다

3. 당신이 수행한 가장 핵심적인 프로젝트를 선택하고, 추천과 같은 모든 프로젝트를 소개하지 마십시오

4. 관심사나 의견, 심지어 자신의 경력 계획까지. 이것은 면접관에게 느낌을 주어야 합니다: "던지기" 또는 "생각"에 열심입니다

예:

안녕하세요 면접관님, 제 이름은 xx년에 xx대학교를 졸업했고 졸업 후 프론트엔드 개발에 종사해 왔습니다. . 일하다.

제가 잘하는 기술 스택은 vue family bucket입니다. 저는 vue2와 vue3의 사용 및 소스 코드에 대해 어느 정도 연구했습니다. 저는 webpack 및 vite 구현을 주도한 경험이 있습니다. 중대형 프로젝트를 처음부터 끝까지 수행할 수 있습니다.

이전 회사에서는 주로 xx 제품군을 담당했고, 주요 업무는 다음과 같았습니다. . . . . .

개발 관련 업무 외에도 그는 요구 사항 검토, UI/UE 상호 작용 검토 심사위원, 개발 일정 담당, 멤버 협업, 멤버 코드 검토, 정기 회의 구성 등 특정 기술 관리 경험도 보유하고 있습니다.

보통 제가 만든 블로그에 연구 기사나 연구 노트를 기록하고 있으며 독창적인 기술 기사를 작성하여 Nuggets에 게시하고 있으며 XX상을 수상했습니다.

일반적으로 자기소개는 3~5분 정도를 유지하도록 노력하세요. 간결하고 핵심을 전달하는 것이 가장 중요하며, 그다음에는 자신의 능력과 장점을 강조하세요.

일반 기술 면접관의 경우 자기 소개는 면접 전 관례적인 서두에 불과합니다. 일반적으로 이력서에 기재된 기본 정보는 이미 귀하에 대한 기본적인 이해를 충족시켰습니다. 그러나 감독자 수준의 면접관이나 HR의 경우, 그들은 귀하의 성격, 행동 습관, 스트레스 저항성 및 기타 포괄적인 능력을 중요하게 여길 것입니다. 따라서 면접 과정에서 최대한 긍정적이어야 하며, 지속적인 학습, 팀워크 등 폭넓은 취미를 가지고 있어야 하며, 무조건 야근을 할 수 있어야 합니다. 물론 치트를 허용하려는 것은 아니지만, 이런 환경에서는 이러한 '사이드 능력'도 어느 정도 경쟁력을 높일 수 있는 마법 무기이기도 하다.

2. 프로젝트 마이닝

현재 시장 상황에서 면접 통지를 받은 경우에는 귀하의 프로젝트 경험이 귀하가 모집하는 직위에 더 적합하기 때문일 가능성이 높습니다. 따라서 다음과 같이 프로젝트 준비에 특별한 주의를 기울여야 합니다.

  • 프로젝트에 사용된 기술을 자세히 알아보세요

  • 디자인 전반의 통제프로젝트 아이디어

  • 프로젝트 관리운영 프로세스

  • 팀워크 능력

    .
  • 프로젝트의 최적화 포인트

    는 무엇인가요

자세한 내용은 사람마다 다르기 때문에 따로 언급하지 않고 각자의 상황에 맞춰서 파헤쳐보겠습니다.

3. 개인

먼저 개인에 대해 이야기해 보겠습니다. 기술 면접을 통과하고 상사 및 HR 수준에 도달하면 현재 기술이 아무리 훌륭하더라도 추가로 개인 잠재력, 학습 능력, 성격, 팀 통합 등 소프트 스킬과 관련하여 쉽게 질문할 수 있는 질문은 다음과 같습니다.

왜 직업을 바꾸셨나요?

자신의 야망을 보여주기 위해 개인 개발부터 직접 시작하세요.
  • 저는 항상 더 나은 기술적 분위기를 가질 뿐만 아니라 더 많은 것을 배울 수 있는 더 큰 플랫폼으로 가고 싶었습니다.
  • 나 자신을 확장하고 싶습니다. 지식 측면에서 저는 항상 x-end xx 제품을 만들어 왔습니다. 기술 스택은 비교적 간단하므로 xx로부터 배워야 합니다.
  • 저는 이전 직장에서 편안함을 느꼈고, 그런 일만 할 수 있었습니다. 플랫폼을 변경하여 기술 범위를 넓히고, 새로운 기술 시스템을 접하고 배우는 것이 더 유익할 것입니다. 나의 개인적인 발전을 위해

당신과 평범한 프런트 엔드에 대해 알려주십시오.

1. 나는 내가 다루는 프로젝트를 종합적으로 분석하는 데 능숙합니다. 하나는 마인드 맵을 사용하여 각 모듈의 비즈니스를 분해하는 것입니다. 해결책은 기능에 따라 각 코드 모듈을 구별하는 것입니다. 다시 개발로 들어갑니다. 이것은 맹목적인 비즈니스 개발만 하는 많은 프런트엔드가 할 수 없는 일이라고 생각합니다

2. 저는 주로 Vue의 소스 코드를 계속해서 배우고 있으며, 예전에 한줄 한줄 썼었는데 teleport

소스코드를 집중적으로 읽어보고, 작성하는데 30시간 정도 걸렸고, 소스코드 각 줄의 기능과 역할을 해석해봤습니다(그런데 읽기와 좋아요가 왜 이렇게 적나요) .

당신의 단점은 무엇입니까?

저는 좀 더 진지하고 내성적인 성격이라 좀 더 외향적인 사람이 되도록 노력하겠습니다.

하나는 프론트엔드 대표로서 다양한 자료를 준비하고 스피치도 해야 하고 다양한 리뷰 미팅을 해야 합니다.

그래서 저는 팀 내에서 기술 공유를 더 많이 하고 매주 정기적인 회의를 주최하는데, 이를 통해 표현하고 토론할 수 있는 용기도 얻게 됩니다.

최근 주목받고 있는 신기술이 있나요?

  • 패키지 종속성 관리 도구 pnpm(종속성 반복 설치 없음, 플랫하지 않은 node_modules 구조, 기호 링크를 통해 종속 패키지 추가)
  • 패키징 도구 vite(매우 빠른 개발 환경)
  • flutter(Google 크로스 플랫폼, 고충실도, 고성능에 초점을 맞춘 오픈 소스 모바일 애플리케이션(App) 개발 프레임워크 출시)
  • rust (js의 미래 기반이라고 들었는데)
  • turbopack, webpack의 후속 , Vite보다 10배 빠르며, webpack은 700배 빠르다고 합니다. 그렇다면 You Yuxi는 Vite보다 10배 빠르지 않다는 것을 직접 확인했습니다. 계속 연구하시겠습니까?
  • 제 개인적인 계획은 다음과 같습니다.

  • 3~5년 안에 기술적인 깊이를 향상시키면서 지식도 넓힐 것입니다. 즉, 주로 폭에 있어서 깊이와 폭을 모두 향상시키겠습니다. 큰 프론트엔드, 더 나은 선택을 할 수 있나요

5~7년은 충분한 지식을 축적한 후, 관심 있는 특정 방향을 선택해 깊이 있게 공부하고 해당 분야의 전문가가 되기 위해 노력할 수 있습니다

팀 규모, 팀 사양 및 개발 프로세스

사람마다 다르기 때문에 그에 맞게 준비하세요. 다양한 규모의 팀의 R&D 모델은 매우 다르기 때문입니다.

코드 검토의 목표

1. 가장 중요한 것은 코드의 유지 관리성(변수 이름 지정, 주석, 함수 통일 원칙 등)입니다.

2. 확장성: 캡슐화 기능(구성 요소 및 코드 논리 여부) 애플리케이션 재현 가능, 확장성)

3. ES 새로운 기능(es6+, ES2020, ES2021 옵셔널 체인, at)4. 기능 사용 사양(예: forEach로 맵을 사용할 때)

5. 알고리즘을 사용하여 더 우아하고 성능이 뛰어난 코드를 작성하는 방법

팀을 이끄는 방법

저는 이전 회사에서 기술 관리 직책을 맡았습니다.

0,

개발 사양 구현

, 이름 지정부터 모범 사례, 다양한 도구 라이브러리 사용까지 회사 내부 위키에 게시했습니다. 초기에는 새로운 사람이 들어오면 코드 품질에 대한 후속 조치를 우선적으로 수행합니다1.

팀 분업

: 각 사람이 단독으로 제품 개발을 담당하고 그 다음에는 일반적으로 지정합니다. 소수의 사람들이 공개 모듈을 개발합니다

2. 코드 품질 보증: 우리는 매주 코드를 검토하고 코드에 대한 교차 검토를 구성하며 수정 결과의 출력 기사를 위키에 올릴 것입니다.

3 정기 회의 조직: 매주 정기 회의를 조직하여 각자의 진행 상황과 위험을 동기화하고 각자의 진행 상황에 따라 업무를 할당합니다.

4. 기술 공유: 가끔 기술 공유도 진행합니다. 처음에는 마이크로 프론트 엔드 시스템, ice stark

5의 소스 코드, Public Demand Pool 등을 공유했습니다. webpack5/vite의 업그레이드 등; pnpm 사용 소개, 토폴로지 맵 성능 최적화

6, 최적화 프로젝트: 제품의 첫 번째 버전이 나온 후 특별한 성능 최적화 프로젝트, 첫 번째 화면 로딩 성능, 패키징 볼륨 최적화도 시작했습니다. ; 해당 최적화 항목은 모두가 책임지도록 하세요

야근에 대해 어떻게 생각하시나요?

잔업을 하는 경우에는 일반적으로 두 가지 상황이 있다고 생각합니다.

첫째, 프로젝트 일정이 빡빡해서 당연히 프로젝트 진행이 우선이고, 결국 모두가 이것에 생계가 달려있습니다

둘째, 자신의 능력 문제, 사업에 익숙하지 않거나 새로운 기술 스택을 도입하면 따라잡기 위해 야근을 해야 할 뿐만 아니라, 여가 시간을 활용하여 부족한 점을 보완하고 공부해야 한다고 생각합니다

당신의 취미는 무엇입니까?

저는 주로 독서를 좋아합니다. 즉, WeChat 읽기에서 심리학, 시간 관리, 말하기 기술에 관한 책을 읽습니다.

그런 다음 기사를 씁니다. 왜냐하면 메모하는 것만으로는 잊어버리기 쉽기 때문입니다. 나는 다른 사람의 내용만 기록하고 나만의 독창적인 기사를 작성하는 과정에서 매우 높은 비율의 지식을 내 것으로 변환할 수 있습니다. 따라서 나만의 금광 기사 외에도 종종 금광 기사에 대한 의견도 있습니다. 기사는 위키로 내보내집니다.

다른 취미는 친구들과 농구하고 노래하는 것입니다.

4. 기술

기술 인터뷰에 주의하세요. 간결하고 요점을 명확하게 하세요. 적절하게 자세하게 설명해주시고, 이해가 안 되시면 이해가 안 된다고 말씀해주세요. 면접 과정은 면접관과의 대면 소통 과정이기 때문에 면접관은 핵심 내용을 말하지 않고 오랫동안 수다를 떠는 지원자를 좋아하지 않을 것이다. 동시에, 말하는 과정에서 듣는 사람은 수동적으로 반응할 것이다. 관심 없는 부분은 무시하기 때문에 특정 기술의 핵심 기능을 부각시키고 핵심을 중심으로 적절하게 확장하는 것이 필요합니다.

대기업은 기본적으로 알고리즘 질문을 통해 후보자를 선별합니다. 알고리즘에는 지름길이 없습니다. 차근차근 질문에 답한 뒤 다시 질문에 답하는 것뿐입니다.

기술 면접 과정은 주로 프론트엔드 분야와 관련된 기술에 대한 질문을 하게 됩니다. 일반적으로 면접관은 귀하의 소속을 기반으로 진행되며, 더 자주 면접관은 이전에 준비한 면접 질문을 기반으로 하거나, 프로젝트 팀이 잘 알고 있는 기술이기 때문에 질문하려면 클릭하세요. 모든 측면이 상당히 까다롭기 때문입니다.

발전 전망이 좋은 중견 기업에 입사하고 싶다면, 다른 사람의 경험만 외운다고 자신을 속일 수는 없습니다. 포인트는 종합적인 학습을 거쳐 추출한 핵심 지식 포인트 중 일부이므로 면접관의 '다양한 사고'를 두려워하지 않습니다.

면접 과정에는 일반적으로 다음 8가지 주요 지식 유형을 고려하는 과정이 포함됩니다:

JS/CSS/TypeScript/프레임워크(Vue, React)/브라우저 및 네트워크/성능 최적화/프론트엔드 엔지니어링/아키텍처/기타

3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

따라서 인터뷰 전 기술적인 준비는 결코 하루아침에 이루어지지 않습니다. 또한 매일의 축적이 필요합니다. 예를 들어, 장기적으로는 작은 지식 포인트 중 하나를 종합적으로 공부하는 데 10~20분을 투자할 수 있습니다. 몇 년의 인터뷰라도 설득력있게 이야기하는 것만으로도 충분합니다 .

JS 장

JS 학습용 빨간 봉투 책과 Yu Yu 씨의 심층 JS 시리즈 블로그기본적으로 괜찮습니다.

일반적인 JS 면접 질문에는 일반적으로 다음이 포함됩니다. 프로토타입 체인?

3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인프로토타입의 본질은

객체

입니다. 생성자를 만들 때 이 함수는 기본적으로

속성을 가지며 이 속성의 값은 이 함수의 프로토타입 개체를 가리킵니다.

이 프로토타입 객체는 생성자를 통해 생성된 인스턴스 객체에 대한 공유 속성을 제공하는 데 사용됩니다. 즉, 프로토타입 기반 상속 및 속성 공유를 구현하는 데 사용됩니다.

prototype따라서 생성자를 통해 생성된 인스턴스 객체

는 모두 이 함수의 프로토타입 객체는 위의 속성을 상속받습니다

인스턴스의 속성을 읽을 때 찾을 수 없으면 객체와 관련된 프로토타입에서 속성을 찾습니다. 찾을 수 없으면 최상위 수준에 도달할 때까지 프로토타입의 프로토타입을 찾습니다. (최상위 수준은 Object.prototype의 프로토타입이고 값은 null입니다.) Object.prototype的原型,值为null)。

所以通过原型一层层相互关联的链状结构就称为原型链

什么是闭包?

定义:闭包是指引用了其他函数作用域中变量的函数,通常是在嵌套函数中实现的。

从技术角度上所有 js 函数都是闭包。

从实践角度来看,满足以下俩个条件的函数算闭包

  • 即使创建它的上下文被销毁了,它依然存在。(比如从父函数中返回)

  • 在代码中引用了自由变量(在函数中使用的既不是函数参数也不是函数局部变量的变量称作自由变量)

使用场景:

  • 创建私有变量

    vue 中的data,需要是一个闭包,保证每个data中数据唯一,避免多次引用该组件造成的data共享

  • 延长变量的生命周期

    一般函数的词法环境在函数返回后就被销毁,但是闭包会保存对创建时所在词法环境的引用,即便创建时所在的执行上下文被销毁,但创建时所在词法环境依然存在,以达到延长变量的生命周期的目的

应用

  • 柯里化函数
  • 例如计数器、延迟调用、回调函数等

this 的指向

在绝大多数情况下,函数的调用方式决定了 this 的值(运行时绑定)

1、全局的this非严格模式指向window对象,严格模式指向 undefined

2、对象的属性方法中的this 指向对象本身

3、apply、call、bind 可以变更 this 指向为第一个传参

4、箭头函数中的this指向它的父级作用域,它自身不存在 this

浏览器的事件循环?

js 代码执行过程中,会创建对应的执行上下文并压入执行上下文栈中。

如果遇到异步任务就会将任务挂起,交给其他线程去处理异步任务,当异步任务处理完后,会将回调结果加入事件队列中。

当执行栈中所有任务执行完毕后,就是主线程处于闲置状态时,才会从事件队列中取出排在首位的事件回调结果,并把这个回调加入执行栈中然后执行其中的代码,如此反复,这个过程就被称为事件循环。

事件队列分为了宏任务队列和微任务队列,在当前执行栈为空时,主线程回先查看微任务队列是否有事件存在,存在则依次执行微任务队列中的事件回调,直至微任务队列为空;不存在再去宏任务队列中处理。

常见的宏任务有setTimeout()setInterval()setImmediate()、I/O、用户交互操作,UI渲染

常见的微任务有promise.then()promise.catch()new MutationObserverprocess.nextTick()

그래서

프로토타입을 통해 층층이 서로 연결되는 체인형 구조를 프로토타입 체인이라고 합니다.

클로저란 무엇인가요?
  • 정의: 클로저는 일반적으로 중첩된 함수에서 구현되는 다른 함수 범위의 변수를 참조하는 함수

    를 나타냅니다.
  • 기술적으로 모든 js 함수는 클로저입니다.

    실용적인 관점에서 다음 두 가지 조건을 충족하는 함수는 클로저로 간주됩니다.

만든 컨텍스트가 파괴되더라도 여전히 존재합니다. (예를 들어 상위 함수에서 반환)

자유 변수는 코드에서 참조됩니다(함수 매개변수도 아니고 함수 로컬 변수도 아닌 함수에서 사용되는 변수를 자유 변수라고 합니다)

사용 시나리오:

    개인 변수 만들기

vue의 데이터는 각 데이터의 데이터가 고유함을 보장하고 구성 요소에 대한 여러 참조로 인해 발생하는 데이터 공유를 방지하기 위해 클로저여야 합니다.

변수의 수명 주기 연장

🎜일반적으로 함수가 반환된 후 함수의 어휘 환경이 파괴되지만, 클로저는 함수가 생성된 실행 컨텍스트가 파괴되더라도 해당 함수가 생성된 어휘 환경에 대한 참조를 저장합니다. 확장을 달성하기 위해 여전히 존재합니다. id="heading-17">🎜this 🎜🎜🎜를 가리키는 경우 대부분의 경우 함수를 호출하는 방법에 따라 this(런타임 바인딩) 🎜🎜1의 값이 결정됩니다. 엄격 모드는 창 개체를 가리키고, 엄격 모드는 정의되지 않은 창 개체를 가리킵니다🎜🎜2. 개체의 속성 메서드에서 이는 개체 자체를 가리킵니다🎜🎜3. 첫 번째 전달된 매개변수🎜🎜4. 화살표 함수의 이 매개변수는 자체적으로 존재하지 않는 상위 범위를 가리킵니다.🎜

🎜브라우저의 이벤트 루프? 🎜🎜🎜js 코드가 실행되는 동안 해당 실행 컨텍스트가 생성되어 실행 컨텍스트 스택에 푸시됩니다. 🎜🎜비동기 작업이 발생하면 작업이 일시 중지되고 비동기 작업을 처리하기 위해 다른 스레드로 넘겨집니다. 비동기 작업이 처리되면 콜백 결과가 이벤트 대기열에 추가됩니다. 🎜🎜실행 스택의 모든 작업이 실행되면, 즉 메인 스레드가 유휴 상태일 때 가장 먼저 순위가 매겨진 이벤트 콜백 결과가 이벤트 큐에서 꺼내지고 이 콜백이 실행 스택에 추가된 다음 그 안에 있는 코드가 실행되므로 이 프로세스를 반복적으로 이벤트 루프라고 합니다. 🎜🎜이벤트 큐는 🎜매크로 작업 큐🎜와 마이크로 작업 큐로 구분됩니다. 현재 실행 스택이 비어 있으면 메인 스레드는 먼저 마이크로 작업 큐에 이벤트가 있는지 확인하고 이벤트 콜백을 수행합니다. 마이크로 작업 대기열은 마이크로 작업 대기열이 비어 있을 때까지 순차적으로 실행됩니다. 존재하지 않으면 매크로 작업 대기열에서 처리됩니다. 🎜🎜🎜일반적인 매크로 작업에는 🎜setTimeout(), setInterval(), setImmediate(), I/O, 사용자 상호 작용 작업, UI가 포함됩니다. 렌더링🎜🎜🎜일반적인 마이크로 작업에는🎜promise.then(), promise.catch(), new MutationObserver, process.nextTick이 포함됩니다. ()🎜🎜🎜매크로 작업과 마이크로 작업의 근본적인 차이점🎜🎜🎜🎜🎜매크로 작업에는 실행과 콜백이 필요한 명확한 비동기 작업이 있으며 다른 비동기 스레드의 지원이 필요합니다🎜🎜🎜🎜마이크로 작업 명확하지 않습니다. 비동기 작업을 실행해야 하며 콜백만 필요하며 다른 비동기 스레드 지원은 필요하지 않습니다. 🎜🎜🎜🎜🎜JavaScript에서 데이터가 스택과 힙에 저장되는 방식🎜🎜🎜1. 기본 데이터 유형은 크기가 고정되어 있고 조작하기 쉽기 때문에 참조 크기에 저장됩니다. 데이터의 종류가 불확실하므로 스택에 저장하고 메모리 신청 시 크기를 결정하도록 합니다. 🎜🎜3. 이런 방식으로 별도로 저장하면 메모리 사용량을 최소화할 수 있습니다. 스택의 효율성은 힙의 효율성보다 높습니다🎜🎜4. 스택 메모리의 변수는 실행 환경이 종료된 후 즉시 가비지 수집되며, 힙 메모리의 변수에 대한 모든 참조는 종료되기 전에 종료되어야 합니다. 재활용되세요🎜🎜🎜v8 가비지 수집에 대해 이야기해 보겠습니다🎜🎜 🎜1. 객체의 생존 시간에 따라 여러 세대로 메모리 가비지 수집을 수행한 다음 세대마다 다른 재활용 알고리즘을 사용합니다. 시간에 대한 공간 청소 알고리즘을 사용합니다. 전체 공간을 두 개의 블록으로 나누고 그 중 하나의 변수만 존재하며, 살아남은 변수는 다른 공간으로 복사되고, 살아남지 않는 변수는 재활용됩니다. 반복해서 반복됩니다🎜🎜3. 이전 세대는 마크 지우기 및 마크 정렬을 사용합니다. 마크 지우기: 모든 객체를 순회하면 해당 객체에 액세스할 수 있으며(라이브), 라이브가 아닌 객체는 가비지로 재활용됩니다. 재활용 후에는 메모리 단절을 피하기 위해 살아있는 객체를 표시 및 정렬을 통해 메모리의 한쪽 끝으로 이동한 다음 이동이 완료된 후 경계 메모리를 정리해야 합니다🎜

함수 호출 방법

1. 일반 함수()를 직접 사용하여 다음과 같은 매개변수를 호출하고 전달합니다. function test(x, y) { return x + y}, test(3, 4)function直接使用()调用并传参,如:function test(x, y) { return x + y}test(3, 4)

2、作为对象的一个属性方法调用,如:const obj = { test: function (val) { return val } }, obj.test(2)

3、使用callapply调用,更改函数 this 指向,也就是更改函数的执行上下文

4、new可以间接调用构造函数生成对象实例

defer和async的区别

一般情况下,当执行到 script 标签时会进行下载 + 执行两步操作,这两步会阻塞 HTML 的解析;

async 和 defer 能将script的下载阶段变成异步执行(和 html解析同步进行);

async下载完成后会立即执行js,此时会阻塞HTML解析;

defer会等全部HTML解析完成且在DOMContentLoaded 事件之前执行。

浏览器事件机制

DOM 事件流三阶段:

  • 捕获阶段:事件最开始由不太具体的节点最早接受事件, 而最具体的节点(触发节点)最后接受事件。为了让事件到达最终目标之前拦截事件。

    比如点击一个div,则 click 事件会按这种顺序触发: document => => => <div>,即由 document 捕获后沿着 DOM 树依次向下传播,<strong>并在各节点上触发捕获事件</strong>,直到到达实际目标元素。<li> <p><strong>目标阶段</strong></p> <p>当事件到达目标节点的,事件就进入了目标阶段。<strong>事件在目标节点上被触发</strong>(执行事件对应的函数),然后会逆向回流,直到传播至最外层的文档节点。</p> </li> <li> <p><strong>冒泡阶段</strong></p> <p>事件在目标元素上触发后,会继续随着 DOM 树一层层往上冒泡,直到到达最外层的根节点。</p> </li> <p>所有事件都要经历捕获阶段和目标阶段,但有些事件会跳过冒泡阶段,比如元素获得焦点 focus 和失去焦点 blur 不会冒泡</p> <p><strong>扩展一</strong></p> <p>e.target 和 e.currentTarget 区别?</p> <ul> <li> <code>e.target 指向触发事件监听的对象。

  • e.currentTarget 指向添加监听事件的对象。

例如:

<ul>
  <li><span>hello 1</span></li>
</ul>

let ul = document.querySelectorAll(&#39;ul&#39;)[0]
let aLi = document.querySelectorAll(&#39;li&#39;)
ul.addEventListener(&#39;click&#39;,function(e){
  let oLi1 = e.target  
  let oLi2 = e.currentTarget
  console.log(oLi1)   //  被点击的li
  console.log(oLi2)   // ul
  console.og(oLi1===oLi2)  // false
})
로그인 후 복사

给 ul 绑定了事件,点击其中 li 的时候,target 就是被点击的 li, currentTarget 就是被绑定事件的 ul

事件冒泡阶段(上述例子),e.currenttargete.target是不相等的,但是在事件的目标阶段,e.currenttargete.target是相等的

作用:

e.target可以用来实现事件委托,该原理是通过事件冒泡(或者事件捕获)给父元素添加事件监听,e.target指向引发触发事件的元素

扩展二

addEventListener 参数

语法:

addEventListener(type, listener);
addEventListener(type, listener, options || useCapture);
로그인 후 복사
  • type: 监听事件的类型,如:'click'/'scroll'/'focus'

  • listener: 必须是一个实现了 EventListener 接口的对象,或者是一个函数。当监听的事件类型被触发时,会执行

  • options:指定 listerner 有关的可选参数对象

    • capture: 布尔值,表示 listener 是否在事件捕获阶段传播到 EventTarget 时触发
    • once:布尔值,表示 listener 添加之后最多调用一次,为 true 则 listener 在执行一次后会移除
    • passive: 布尔值,表示 listener 永远不会调用 preventDefault()
    • signal:可选,AbortSignal,当它的abort()
    • 2. 다음과 같이 객체의 속성 메서드로 호출됩니다. const obj = { test: function (val) { return val } }, obj.test(2)
  • 3. call 또는 apply를 사용하여 호출하세요. 그리고 this가 가리키는 함수를 변경합니다. 즉, 함수의 실행 컨텍스트를 변경하면
  • 4. new는 간접적으로 생성자를 호출하여 객체 인스턴스

    🎜defer와 async의 차이점🎜🎜🎜 일반적인 상황에서 스크립트 태그가 실행되면 다운로드 + 2단계 작업이 실행됩니다. 이 두 단계는 HTML 구문 분석을 차단합니다. 🎜🎜async 및 defer는 스크립트의 🎜다운로드 단계🎜를 비동기 실행(HTML 구문 분석과 동기화)으로 전환합니다). 🎜🎜async는 다운로드가 완료된 후 즉시 js를 실행하여 HTML 구문 분석을 차단합니다. 🎜🎜defer는 모든 HTML 구문 분석이 완료될 때까지 기다립니다. DOMContentLoaded 이벤트 이전에 완료되고 실행됩니다. 🎜

    🎜브라우저 이벤트 메커니즘🎜🎜🎜DOM 이벤트 흐름 3단계: 🎜
      🎜🎜🎜캡처 단계🎜: 이벤트 이벤트를 먼저 수신하는 덜 구체적인 노드부터 시작하고 이벤트를 마지막으로 수신하는 가장 구체적인 노드(트리거링 노드)부터 시작합니다. 이벤트가 최종 목적지에 도달하기 전에 차단합니다. 🎜🎜예를 들어 div를 클릭하면 다음 순서로 클릭 이벤트가 실행됩니다. document => <html> => > => < code>
      즉, 문서에 의해 캡처된 다음 DOM 트리를 따라 아래쪽으로 전파되고 🎜 실제 대상 요소에 도달할 때까지 각 노드에서 캡처 이벤트를 트리거합니다 🎜 . 🎜🎜🎜🎜🎜대상 단계🎜🎜🎜이벤트가 대상 노드에 도달하면 이벤트가 대상 단계에 들어갑니다. 🎜대상 노드에서 이벤트가 발생🎜(이벤트에 해당하는 함수 실행)한 후 가장 바깥쪽 문서 노드로 전파될 때까지 역방향으로 다시 흐릅니다. 🎜🎜🎜🎜🎜버블링 단계🎜🎜🎜이벤트가 대상 요소에서 트리거된 후 가장 바깥쪽 루트 노드에 도달할 때까지 DOM 트리를 따라 레이어별로 계속 버블링됩니다. 🎜🎜🎜🎜모든 이벤트는 캡처 단계와 대상 단계를 거쳐야 하지만 요소가 초점을 맞추고 초점을 잃는 등 일부 이벤트는 버블링 단계를 건너뜁니다. 흐림 효과는 버블링되지 않습니다 🎜🎜🎜확장된 것 🎜🎜🎜e. 타겟과 e.currentTarget의 차이점은 무엇입니까? 🎜
        🎜e.target은 이벤트 수신을 트리거하는 객체를 가리킵니다. 🎜🎜e.currentTarget은 이벤트를 수신하기 위해 추가된 개체를 가리킵니다. 🎜🎜🎜예: 🎜
        // 比如
        <input v-model="sth" />
        // 等价于
        <input :value="sth" @input="sth = $event.target.value" />
        로그인 후 복사
        로그인 후 복사
        🎜가 ul에 이벤트를 바인딩했습니다. li를 클릭하면 대상은 클릭된 li이고 currentTarget은 바인딩된 이벤트의 ul🎜🎜 이벤트 버블링 단계입니다(위 예). code> e.currenttarget 및 e.target은 동일하지 않지만 이벤트의 대상 단계에서는 e.currenttargete.target >같음 🎜🎜함수: 🎜🎜e.target을 사용하여 이벤트 위임, 원칙은 이벤트 버블링(또는 이벤트 캡처) 상위 요소를 수신하는 이벤트를 추가하려면 e.target이 트리거 이벤트를 트리거한 요소를 가리킵니다. 🎜🎜🎜Extension 2🎜🎜🎜addEventListener 매개변수🎜🎜구문: ​​🎜
        // 父组件
        <my-button v-model="number"></my-button>
        
        // 子组件
        <script>
        export default {
          props: {
            value: Number, //  属性名必须是 value
          },
        
          methods: {
            add() {
              this.$emit(&#39;input&#39;, this.value + 1) // 事件名必须是 input
            },
          }
        }
        </script>
        로그인 후 복사
        로그인 후 복사

        Vue 기사

        저자는 주로 Vue 관련 개발에 종사하고 있으며, React 관련 프로젝트도 해본 적이 있습니다. 물론 React는 프로젝트를 할 수 있는 수준에 불과하니 그런 편입니다. Vue 소스 코드 시리즈를 배우면 프레임워크가 비싸지 않습니다. 학습 과정에서도 마찬가지입니다. 프레임워크의 원리를 마스터할 수 있다면 다른 프레임워크를 배우는 것은 시간 문제일 뿐입니다.

        3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

        vue와 React의 차이점

        1. 데이터 가변성

        2、写法

        3、diff 算法

        扩展:了解 react hooks吗

        组件类的写法很重,层级一多很难维护。

        函数组件是纯函数,不能包含状态,也不支持生命周期方法,因此无法取代类。

        React Hooks 的设计目的,就是加强版函数组件,完全不使用"类",就能写出一个全功能的组件

        React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。

        vue组件通信方式

        vue 渲染列表为什么要加key?

        Vue 在处理更新同类型 vnode 的一组子节点(比如v-for渲染的列表节点)的过程中,为了减少 DOM 频繁创建和销毁的性能开销:

        对没有 key 的子节点数组更新是通过就地更新的策略。它会通过对比新旧子节点数组的长度,先以比较短的那部分长度为基准,将新子节点的那一部分直接 patch 上去。然后再判断,如果是新子节点数组的长度更长,就直接将新子节点数组剩余部分挂载;如果是新子节点数组更短,就把旧子节点多出来的那部分给卸载掉)。所以如果子节点是组件或者有状态的 DOM 元素,原有的状态会保留,就会出现渲染不正确的问题

        有 key 的子节点更新是调用的patchKeyedChildrenVue는 데이터 가변성을 기반으로 반응형 데이터를 설계하고 데이터 변경을 모니터링하여 자동으로 뷰를 업데이트합니다

        2. 작성 방법

        🎜🎜React는 jsx + 인라인 스타일 사용을 권장합니다. 양식은 모두 js에 있습니다🎜🎜Vue는 구성 요소 내에서 모듈(tmplate/script/style)로 구분된 단일 파일 구성 요소(SFC) 형식입니다. 물론 vue는 vue의 UI를 개발할 때 사용할 수 있는 jsx 형식도 지원합니다. 컴포넌트 라이브러리🎜 🎜🎜3. Diff 알고리즘🎜🎜🎜Vue2는 이중 비교를 사용하고, Vue3은 빠른 비교를 사용합니다.🎜🎜react는 주로 diff 대기열을 사용하여 업데이트해야 하는 DOM을 저장하고 패치를 가져옵니다. 그런 다음 통합 작업을 수행하여 DOM을 일괄적으로 업데이트합니다. , 반응 렌더링을 수동으로 최적화하려면 shouldComponentUpdate()를 사용해야 합니다. 🎜🎜🎜🎜확장: React Hooks를 아시나요? 🎜🎜🎜컴포넌트 클래스 작성이 매우 무겁고 레벨이 너무 많으면 유지 관리가 어렵습니다. 🎜🎜함수 구성 요소는 순수 함수이고 상태를 포함할 수 없으며 수명 주기 메서드를 지원하지 않으므로 클래스를 대체할 수 없습니다. 🎜🎜🎜React Hooks의 설계 목적은 "클래스"를 전혀 사용하지 않고도 모든 기능을 갖춘 구성 요소를 작성할 수 있다는 것을 의미합니다. 외부 구성 요소가 필요한 경우 기능 및 부작용을 위해 후크를 사용하여 외부 코드를 "연결"합니다. 🎜🎜

        🎜vue 컴포넌트 통신 방법🎜🎜🎜🎜props / $emit🎜🎜ref / $refs🎜🎜<의미>p arent/< /mi>부모 /root🎜🎜attrs / listenings🎜🎜eventBus / vuex / pinia / localStorage / sessionStorage / Cookie / window🎜🎜provide / inject🎜🎜

        🎜vue가 렌더링 목록에 키를 추가하는 이유는 무엇입니까? 🎜🎜🎜Vue는 동일한 유형의 vnode(예: v-for로 렌더링된 목록 노드)의 하위 노드 그룹을 업데이트하는 중입니다. DOM 성능 오버헤드의 빈번한 생성 및 파괴를 줄이기 위해: 🎜🎜키가 없는 하위 노드 배열의 업데이트는 🎜in-place update🎜 전략을 통해 이루어집니다. 이전 자식 노드 배열과 새 자식 노드 배열의 길이를 비교하고, 먼저 더 짧은 길이를 기준으로 사용하고, 새 자식 노드의 일부를 직접 패치합니다. 그런 다음 새 하위 노드 배열의 길이가 더 길면 새 하위 노드 배열의 나머지 부분을 직접 마운트하고, 새 하위 노드 배열이 더 짧으면 이전 하위 노드의 추가 부분을 제거합니다. 🎜따라서 하위 노드가 구성 요소이거나 상태 저장 DOM 요소인 경우 원래 상태가 유지되고 잘못된 렌더링이 발생합니다🎜. 🎜🎜키가 있는 하위 노드를 업데이트하는 것을 patchKeyedChildren이라고 합니다. 이 함수는 핵심 diff 알고리즘을 구현하는 데 익숙한 곳입니다. 일반적인 프로세스는 헤드 노드를 동기화하고 처리하는 것입니다. 노드 추가 및 삭제, 마지막으로 가장 긴 증가 부분 수열을 해결하는 방법을 사용하여 알려지지 않은 부분 수열을 처리합니다. 이는 기존 노드의 재사용을 극대화하고 DOM 작업의 성능 오버헤드를 줄이며 내부 업데이트로 인해 발생하는 하위 노드 상태 오류 문제를 방지하기 위한 것입니다. 🎜🎜결론적으로 v-for를 사용하여 상수를 순회하거나 하위 노드가 일반 텍스트와 같이 "상태"가 없는 노드인 경우 키를 추가하지 않고도 쓰기 방법을 사용할 수 있습니다. 그러나 실제 개발 과정에서는 키를 균일하게 추가하는 것이 좋습니다. 그러면 더 넓은 범위의 시나리오를 실현하고 가능한 상태 업데이트 오류를 ​​피할 수 있습니다. 일반적으로 ESlint를 사용하여 키를 v-for의 필수 요소로 구성할 수 있습니다. 🎜

        想详细了解这个知识点的可以去看看我之前写的文章:v-for 到底为啥要加上 key?

        vue3 相对 vue2的响应式优化

        vue2使用的是Object.defineProperty去监听对象属性值的变化,但是它不能监听对象属性的新增和删除,所以需要使用$set$delete这种语法糖去实现,这其实是一种设计上的不足。

        所以 vue3 采用了proxy去实现响应式监听对象属性的增删查改。

        其实从api的原生性能上proxy是比Object.defineProperty要差的。

        而 vue 做的响应式性能优化主要是在将嵌套层级比较深的对象变成响应式的这一过程。

        vue2的做法是在组件初始化的时候就递归执行Object.defineProperty把子对象变成响应式的;

        而vue3是在访问到子对象属性的时候,才会去将它转换为响应式。这种延时定义子对象响应式会对性能有一定的提升

        Vue 核心diff流程

        前提:当同类型的 vnode 的子节点都是一组节点(数组类型)的时候,

        步骤:会走核心 diff 流程

        Vue3是快速选择算法

        • 同步头部节点
        • 同步尾部节点
        • 新增新的节点
        • 删除多余节点
        • 处理未知子序列(贪心 + 二分处理最长递增子序列)

        Vue2是双端比较算法

        在新旧字节点的头尾节点,也就是四个节点之间进行对比,找到可复用的节点,不断向中间靠拢的过程

        diff目的:diff 算法的目的就是为了尽可能地复用节点,减少 DOM 频繁创建和删除带来的性能开销

        vue双向绑定原理

        基于 MVVM 模型,viewModel(业务逻辑层)提供了数据变化后更新视图视图变化后更新数据这样一个功能,就是传统意义上的双向绑定。

        Vue2.x 实现双向绑定核心是通过三个模块:Observer监听器、Watcher订阅者和Compile编译器。

        首先监听器会监听所有的响应式对象属性,编译器会将模板进行编译,找到里面动态绑定的响应式数据并初始化视图;watchr 会去收集这些依赖;当响应式数据发生变更时Observer就会通知 Watcher;watcher接收到监听器的信号就会执行更新函数去更新视图;

        vue3的变更是数据劫持部分使用了porxy 替代 Object.defineProperty,收集的依赖使用组件的副作用渲染函数替代watcher

        v-model 原理

        vue2 v-model 原理剖析

        V-model 是用来监听用户事件然后更新数据的语法糖。

        其本质还是单向数据流,内部是通过绑定元素的 value 值向下传递数据,然后通过绑定 input 事件,向上接收并处理更新数据。

        单向数据流:父组件传递给子组件的值子组件不能修改,只能通过emit事件让父组件自个改。

        // 比如
        <input v-model="sth" />
        // 等价于
        <input :value="sth" @input="sth = $event.target.value" />
        로그인 후 복사
        로그인 후 복사

        给组件添加 v-model 属性时,默认会把value 作为组件的属性,把 input作为给组件绑定事件时的事件名:

        // 父组件
        <my-button v-model="number"></my-button>
        
        // 子组件
        <script>
        export default {
          props: {
            value: Number, //  属性名必须是 value
          },
        
          methods: {
            add() {
              this.$emit(&#39;input&#39;, this.value + 1) // 事件名必须是 input
            },
          }
        }
        </script>
        로그인 후 복사
        로그인 후 복사

        如果想给绑定的 value 属性和 input 事件换个名称呢?可以这样:

        在 Vue 2.2 及以上版本,你可以在定义组件时通过 model 选项的方式来定制 prop/event:

        <script>
        export default {
          model: {
            prop: &#39;num&#39;, // 自定义属性名
            event: &#39;addNum&#39; // 自定义事件名
          }
        }
        로그인 후 복사

        vue3 v-model 原理

        实现和 vue2 基本一致

        <Son v-model="modalValue"/>
        로그인 후 복사

        等同于

        <Son v-model="modalValue"/> 
        로그인 후 복사

        自定义 model 参数

        <Son v-model:visible="visible"/>
        setup(props, ctx){
            ctx.emit("update:visible", false)
        }
        로그인 후 복사

        vue 响应式原理

        不管vue2 还是 vue3,响应式的核心就是观察者模式 + 劫持数据的变化,在访问的时候做依赖收集和在修改数据的时候执行收集的依赖并更新数据。具体点就是:

        vue2 的话采用的是 Object.definePorperty劫持对象的 get 和 set 方法,每个组件实例都会在渲染时初始化一个 watcher 实例,它会将组件渲染过程中所接触的响应式变量记为依赖,并且保存了组件的更新方法 update。当依赖的 setter 触发时,会通知 watcher 触发组件的 update 方法,从而更新视图。

        Vue3 使用的是 ES6 的 proxy,proxy 不仅能够追踪属性的获取和修改,还可以追踪对象的增删,这在 vue2中需要 set/set/delete 才能实现。然后就是收集的依赖是用组件的副作用渲染函数替代 watcher 实例。

        性能方面,从原生 api 角度,proxy 这个方法的性能是不如 Object.property,但是 vue3 强就强在一个是上面提到的可以追踪对象的增删,第二个是对嵌套对象的处理上是访问到具体属性才会把那个对象属性给转换成响应式,而 vue2 是在初始化的时候就递归调用将整个对象和他的属性都变成响应式,这部分就差了。

        扩展一

        vue2 通过数组下标更改数组视图为什么不会更新?

        尤大:性能不好

        注意:vue3 是没问题的

        why 性能不好?

        我们看一下响应式处理:

        export class Observer {
          this.value = value
            this.dep = new Dep()
            this.vmCount = 0
            def(value, &#39;__ob__&#39;, this)
            if (Array.isArray(value)) {
              // 这里对数组进行单独处理
              if (hasProto) {
                protoAugment(value, arrayMethods)
              } else {
                copyAugment(value, arrayMethods, arrayKeys)
              }
              this.observeArray(value)
            } else {
              // 对对象遍历所有键值
              this.walk(value)
            }
          }
          walk (obj: Object) {
            const keys = Object.keys(obj)
            for (let i = 0; i < keys.length; i++) {
              defineReactive(obj, keys[i])
            }
          }
          observeArray (items: Array<any>) {
            for (let i = 0, l = items.length; i < l; i++) {
              observe(items[i])
            }
          }
        }
        로그인 후 복사

        对于对象是通过Object.keys()遍历全部的键值,对数组只是observe监听已有的元素,所以通过下标更改不会触发响应式更新。

        理由是数组的键相较对象多很多,当数组数据大的时候性能会很拉胯。所以不开放

        computed 和 watch

        Computed 的大体实现和普通的响应式数据是一致的,不过加了延时计算和缓存的功能:

        在访问computed对象的时候,会触发 getter ,初始化的时候将 computed 属性创建的 watcher (vue3是副作用渲染函数)添加到与之相关的响应式数据的依赖收集器中(dep),然后根据里面一个叫 dirty 的属性判断是否要收集依赖,不需要的话直接返回上一次的计算结果,需要的话就执行更新重新渲染视图。

        watchEffect?

        watchEffect会自动收集回调函数中响应式变量的依赖。并在首次自动执行

        推荐在大部分时候用 watch 显式的指定依赖以避免不必要的重复触发,也避免在后续代码修改或重构时不小心引入新的依赖。watchEffect 适用于一些逻辑相对简单,依赖源和逻辑强相关的场景(或者懒惰的场景 )

        $nextTick 原理?

        vue有个机制,更新 DOM 是异步执行的,当数据变化会产生一个异步更行队列,要等异步队列结束后才会统一进行更新视图,所以改了数据之后立即去拿 dom 还没有更新就会拿不到最新数据。所以提供了一个 nextTick 函数,它的回调函数会在DOM 更新后立即执行。

        nextTick 本质上是个异步任务,由于事件循环机制,异步任务的回调总是在同步任务执行完成后才得到执行。所以源码实现就是根据环境创建异步函数比如 Promise.then(浏览器不支持promise就会用MutationObserver,浏览器不支持MutationObserver就会用setTimeout),然后调用异步函数执行回调队列。

        所以项目中不使用$nextTick的话也可以直接使用Promise.then或者SetTimeout实现相同的效果

        Vue 异常处理

        1、全局错误处理:Vue.config.errorHandler

        Vue.config.errorHandler = function(err, vm, info) {};

        如果在组件渲染时出现运行错误,错误将会被传递至全局Vue.config.errorHandler 配置函数 (如果已设置)。

        比如前端监控领域的 sentry,就是利用这个钩子函数进行的 vue 相关异常捕捉处理

        2、全局警告处理:Vue.config.warnHandler

        Vue.config.warnHandler = function(msg, vm, trace) {};
        로그인 후 복사

        注意:仅在开发环境生效

        像在模板中引用一个没有定义的变量,它就会有warning

        3、单个vue 实例错误处理:renderError

        const app = new Vue({
            el: "#app",
            renderError(h, err) {
                return h("pre", { style: { color: "red" } }, err.stack);
            }
        });
        로그인 후 복사

        和组件相关,只适用于开发环境,这个用处不是很大,不如直接看控制台

        4、子孙组件错误处理:errorCaptured

        Vue.component("cat", {
            template: `<div><slot></slot></div>`,
            props: { name: { type: string } },
            errorCaptured(err, vm, info) {
                console.log(`cat EC: ${err.toString()}\ninfo: ${info}`);
                return false;
            }
        });
        로그인 후 복사

        注:只能在组件内部使用,用于捕获子孙组件的错误,一般可以用于组件开发过程中的错误处理

        5、终极错误捕捉:window.onerror

        window.onerror = function(message, source, line, column, error) {};
        로그인 후 복사

        它是一个全局的异常处理函数,可以抓取所有的 JavaScript 异常

        Vuex 流程 & 原理

        Vuex 利用 vue 的mixin 机制,在beforeCreate 钩子前混入了 vuexinit 方法,这个方法实现了将 store 注入 vue 实例当中,并注册了 store 的引用属性 store,所以可以使用this.store ,所以可以使用 `this.store.xxx`去引入vuex中定义的内容。

        然后 state 是利用 vue 的 data,通过new Vue({data: {$$state: state}} 将 state 转换成响应式对象,然后使用 computed 函数实时计算 getter

        Vue.use函数里面具体做了哪些事

        概念

        可以通过全局方法Vue.use()注册插件,并能阻止多次注册相同插件,它需要在new Vue之前使用。

        该方法第一个参数必须是ObjectFunction类型的参数。如果是Object那么该Object需要定义一个install方法;如果是Function那么这个函数就被当做install方法。

        Vue.use()执行就是执行install方法,其他传参会作为install方法的参数执行。

        所以**Vue.use()本质就是执行需要注入插件的install方法**。

        源码实现

        export function initUse (Vue: GlobalAPI) {
         Vue.use = function (plugin: Function | Object) {
          const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))
          // 避免重复注册
          if (installedPlugins.indexOf(plugin) > -1) {
           return this
          }
          // 获取传入的第一个参数
          const args = toArray(arguments, 1)
          args.unshift(this)
          if (typeof plugin.install === &#39;function&#39;) {
           // 如果传入对象中的install属性是个函数则直接执行
           plugin.install.apply(plugin, args)
          } else if (typeof plugin === &#39;function&#39;) {
           // 如果传入的是函数,则直接(作为install方法)执行
           plugin.apply(null, args)
          }
          // 将已经注册的插件推入全局installedPlugins中
          installedPlugins.push(plugin)
          return this
         }
        }
        로그인 후 복사

        使用方式

        installedPlugins import Vue from &#39;vue&#39;
        import Element from &#39;element-ui&#39;
        Vue.use(Element)
        로그인 후 복사

        怎么编写一个vue插件

        要暴露一个install方法,第一个参数是Vue构造器,第二个参数是一个可选的配置项对象

        Myplugin.install = function(Vue, options = {}) {
          // 1、添加全局方法或属性
          Vue.myGlobalMethod = function() {}
          // 2、添加全局服务
          Vue.directive(&#39;my-directive&#39;, {
            bind(el, binding, vnode, pldVnode) {}
          })
          // 3、注入组件选项
          Vue.mixin({
            created: function() {}
          })
          // 4、添加实例方法
          Vue.prototype.$myMethod = function(methodOptions) {}
        }
        로그인 후 복사

        CSS篇

        Css直接面试问答的题目相对来说比较少,更多的是需要你能够当场手敲代码实现功能,一般来说备一些常见的布局,熟练掌握flex基本就没有什么问题了。

        什么是 BFC

        Block Formatting context,块级格式上下文

        BFC 是一个独立的渲染区域,相当于一个容器,在这个容器中的样式布局不会受到外界的影响。

        比如浮动元素、绝对定位、overflow 除 visble 以外的值、display 为 inline/tabel-cells/flex 都能构建 BFC。

        常常用于解决

        • 处于同一个 BFC 的元素外边距会产生重叠(此时需要将它们放在不同 BFC 中);

        • 清除浮动(float),使用 BFC 包裹浮动的元素即可

        • 阻止元素被浮动元素覆盖,应用于两列式布局,左边宽度固定,右边内容自适应宽度(左边float,右边 overflow)

        伪类和伪元素及使用场景

        伪类

        伪类即:当元素处于特定状态时才会运用的特殊类

        开头为冒号的选择器,用于选择处于特定状态的元素。比如:first-child选择第一个子元素;:hover悬浮在元素上会显示;:focus用键盘选定元素时激活;:link + :visted点击过的链接的样式;:not用于匹配不符合参数选择器的元素;:fist-child匹配元素的第一个子元素;:disabled 匹配禁用的表单元素

        伪元素

        伪元素用于创建一些不在文档树中的元素,并为其添加样式。比如说,我们可以通过::before 来在一个元素前增加一些文本,并为这些文本添加样式。虽然用户可以看到这些文本,但是这些文本实际上不在文档树中。示例:

        ::before 在被选元素前插入内容。需要使用 content 属性来指定要插入的内容。被插入的内容实际上不在文档树中

        h1:before {
            content: "Hello ";
        }
        로그인 후 복사

        ::first-line 匹配元素中第一行的文本

        src 和 href 区别

        • href是Hypertext Reference的简写,表示超文本引用,指向网络资源所在位置。href 用于在当前文档和引用资源之间确立联系

        • src是source的简写,目的是要把文件下载到html页面中去。src 用于替换当前内容

        • 浏览器解析方式

          当浏览器遇到href会并行下载资源并且不会停止对当前文档的处理。(同时也是为什么建议使用 link 方式加载 CSS,而不是使用 @import 方式)

          当浏览器解析到src ,会暂停其他资源的下载和处理,直到将该资源加载或执行完毕。(这也是script标签为什么放在底部而不是头部的原因)

        不定宽高元素的水平垂直居中

        • flex

          <div class="wrapper flex-center">
            <p>horizontal and vertical</p>
          </div>
          
          .wrapper {
              width: 900px;
              height: 300px;
              border: 1px solid #ccc;
          }
          .flex-center {  // 注意是父元素
              display: flex;
              justify-content: center;  // 主轴(竖线)上的对齐方式
              align-items: center;      // 交叉轴(横轴)上的对齐方式
          }
          로그인 후 복사
        • flex + margin

          <div class="wrapper">
            <p>horizontal and vertical</p>
          </div>
          
          .wrapper {
              width: 900px;
              height: 300px;
              border: 1px solid #ccc;
              display: flex;
          }
          .wrapper > p {
              margin: auto;
          }
          로그인 후 복사
        • Transform + absolute

          <div class="wrapper">
              <img  src="test.png" alt="3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인" >
          </div>
          
          .wrapper {
              width: 300px;
              height: 300px;
              border: 1px solid #ccc;
              position: relative;
          }
          .wrapper > img {
              position: absolute;
              left: 50%;
              top: 50%;
              tansform: translate(-50%, -50%)
          }
          로그인 후 복사

          注:使用该方法只适用于行内元素(a、img、label、br、select等)(宽度随元素的内容变化而变化),用于块级元素(独占一行)会有问题,left/top 的50%是基于图片最左侧的边来移动的,tanslate会将多移动的图片自身的半个长宽移动回去,就实现了水平垂直居中的效果

        • display: table-cell

          <div class="wrapper">
            <p>absghjdgalsjdbhaksldjba</p>
          </div>
          
          .wrapper {
              width: 900px;
              height: 300px;
              border: 1px solid #ccc;
              display: table-cell;
              vertical-align: middle;
              text-align: center;
          }
          로그인 후 복사

        浏览器和网络篇

        浏览器和网络是八股中最典型的案例了,无论你是几年经验,只要是前端,总会有问到你的浏览器和网络协议。

        最好的学习文章是李兵老师的《浏览器工作原理与实践》

        3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

        跨页面通信的方法?

        这里分了同源页面和不同源页面的通信。

        不同源页面可以通过 iframe 作为一个桥梁,因为 iframe 可以指定 origin 来忽略同源限制,所以可以在每个页面都嵌入同一个 iframe 然后监听 iframe 中传递的 message 就可以了。

        同源页面的通信大致分为了三类:广播模式、共享存储模式和口口相传模式

        第一种广播模式,就是可以通过 BroadCast Channel、Service Worker 或者 localStorage 作为广播,然后去监听广播事件中消息的变化,达到页面通信的效果。

        第二种是共享存储模式,我们可以通过Shared Worker 或者 IndexedDB,创建全局共享的数据存储。然后再通过轮询去定时获取这些被存储的数据是否有变更,达到一个的通信效果。像常见cookie 也可以作为实现共享存储达到页面通信的一种方式

        最后一种是口口相传模式,这个主要是在使用 window.open 的时候,会返回被打开页面的 window 的引用,而在被打开的页面可以通过 window.opener 获取打开它的页面的 window 点引用,这样,多个页面之间的 window 是能够相互获取到的,传递消息的话通过 postMessage 去传递再做一个事件监听就可以了

        详细说说 HTTP 缓存

        在浏览器第一次发起请求服务的过程中,会根据响应报文中的缓存标识决定是否缓存结果,是否将缓存标识和请求结果存入到浏览器缓存中。

        HTTP 缓存分为强制缓存和协商缓存两类。

        强制缓存就是请求的时候浏览器向缓存查找这次请求的结果,这里分了三种情况,没查找到直接发起请求(和第一次请求一致);查找到了并且缓存结果还没有失效就直接使用缓存结果;查找到但是缓存结果失效了就会使用协商缓存。

        强制缓存有 Expires 和 Cache-control 两个缓存标识,Expires 是http/1.0 的字段,是用来指定过期的具体的一个时间(如 Fri, 02 Sep 2022 08:03:35 GMT),当服务器时间和浏览器时间不一致的话,就会出现问题。所以在 http1.1 添加了 cache-control 这个字段,它的值规定了缓存的范围(public/private/no-cache/no-store),也可以规定缓存在xxx时间内失效(max-age=xxx)是个相对值,就能避免了 expires带来的问题。

        캐시 협상은 캐시된 결과를 강제로 무효화하는 프로세스입니다. 브라우저는 캐시 식별자를 전달하여 서버에 요청을 시작하고, 서버는 캐시 식별자를 통해 캐시를 사용할지 여부를 결정합니다.

        협상 캐시를 제어하는 ​​필드는 last-modified / if-modified-since 및 Etag / if-none-match이며 후자가 더 높은 우선순위를 갖습니다.

        일반적인 프로세스는 요청 메시지를 통해 last-modified 또는 Etag 값을 서버에 전달하고 결과가 if-modified-since 또는 if-none-과 일치하는 경우 서버의 해당 값과 비교하는 것입니다. 응답 메시지에서 일치한 다음 협상 캐시가 유효하고 캐시된 결과를 사용하고 304를 반환합니다. 그렇지 않으면 유효하지 않으며 결과를 다시 요청하고 200을 반환합니다.

        페이지 표시에 URL을 입력하는 전체 과정

        사용자가 콘텐츠를 입력하면 브라우저는 먼저 해당 콘텐츠가 검색인지 여부를 결정합니다. 콘텐츠가 여전히 검색 콘텐츠인 경우 기본 검색 엔진과 결합되어 URL을 생성합니다. 예를 들어 Google 브라우저는 goole.com/search?xxxx입니다. URL인 경우 http/https와 같이 프로토콜이 결합됩니다. 페이지가 beforeupload 시간을 수신하지 않거나 실행 프로세스를 계속하는 데 동의하면 브라우저 아이콘 표시줄이 로딩 상태로 들어갑니다.

        다음으로, 브라우저 프로세스는 IPC 프로세스 간 통신을 통해 네트워크 프로세스에 URL 요청을 보냅니다. 네트워크 프로세스는 먼저 캐시에서 리소스를 검색하고 요청을 가로채서 200을 직접 반환합니다. 그렇지 않은 경우 네트워크 요청 프로세스로 들어갑니다.

        네트워크 요청 프로세스는 네트워크 프로세스가 도메인 이름에 해당하는 IP 및 포트 번호를 반환하도록 DNS 서버에 요청하는 것입니다(이전에 캐시된 경우 포트 번호가 없으면 캐시된 결과가 직접 반환됩니다). , http의 기본값은 80, https의 기본값은 443입니다. https인 경우 암호화된 데이터 채널을 생성하려면 TLS 보안 연결도 설정해야 합니다.

        그런 다음 TCP 3방향 핸드셰이크가 브라우저와 서버 간의 연결을 설정한 다음 데이터 전송을 수행합니다. 데이터 전송이 완료된 후 손을 네 번 흔들어 연결을 끊으면 언제든지 연결을 유지할 수 있습니다. 연결. connection: keep-alive

        네트워크 프로세스는 TCP를 통해 얻은 데이터 패킷을 구문 분석합니다. 먼저 응답 헤더의 콘텐츠 유형에 따라 데이터 유형이 결정됩니다. 바이트 스트림 또는 파일 유형인 경우 다운로드로 전달됩니다. 지금 다운로드를 위한 관리자를 탐색하세요. 프로세스가 끝났습니다. text/html 유형인 경우 렌더링할 문서를 가져오도록 브라우저 프로세스에 알립니다.

        브라우저 프로세스는 렌더링 알림을 받고 현재 페이지와 새로 입력된 페이지를 기반으로 동일한 사이트인지 판단합니다. 그렇지 않으면 별도의 렌더링이 재사용됩니다. 프로세스가 생성됩니다.

        브라우저 프로세스는 "문서 제출" 메시지를 렌더링 프로세스로 보냅니다. 렌더링 프로세스가 메시지를 수신하면 데이터 전송이 완료된 후 "제출 확인"을 반환합니다. " 메시지를 브라우저 프로세스에 보냅니다.

        브라우저는 렌더링 프로세스에서 "제출 확인" 메시지를 받은 후 브라우저의 페이지 상태(보안 상태, 주소 표시줄 URL, 순방향 및 역방향 기록 메시지)를 업데이트하고 이때 웹페이지를 업데이트합니다. 빈 페이지(흰색 화면)입니다.

        페이지 렌더링 프로세스(키 메모리)

        마지막으로 렌더링 프로세스는 문서의 페이지 구문 분석 및 하위 리소스 로딩을 수행합니다. 렌더링 프로세스는 HTML을 DOM 트리 구조로 변환하고 CSS를 styleSeets(CSSOM)으로 변환합니다. 그런 다음 DOM 트리를 복사하고 표시되지 않는 요소를 필터링하여 기본 렌더링 트리를 만듭니다. 그런 다음 각 DOM 노드의 스타일을 계산하고 각 노드의 위치 레이아웃 정보를 계산하여 레이아웃 트리를 만듭니다.

        레이어링 컨텍스트가 있거나 자르기가 필요한 경우 레이어가 독립적으로 생성되며, 이는 결국 레이어 트리를 형성하게 됩니다. 렌더링 프로세스는 각 레이어에 대한 드로잉 목록을 생성하여 합성 스레드에 제출합니다. 합성 스레드는 레이어를 타일로 나누고(레이어의 모든 내용을 한 번에 그리는 것을 방지하고 뷰포트 부분을 타일 우선순위에 따라 렌더링할 수 있음) 타일을 래스터화 스레드 풀에서 비트맵으로 변환합니다. .

        변환이 완료된 후 합성 스레드는 드로잉 블록 명령 DrawQuard를 브라우저 프로세스로 보냅니다. 브라우저는 DrawQuard 메시지를 기반으로 페이지를 생성하여 브라우저에 표시합니다.

        약어:

        브라우저의 렌더링 프로세스는 html을 dom 트리로 구문 분석하고, css를 cssom 트리로 구문 분석합니다. 그런 다음 먼저 DOM 트리를 복사하여 표시되지 않는 요소(예: display: none)를 필터링합니다. 그런 다음 cssom을 결합하여 각 DOM 노드의 레이아웃 정보를 결합하고 계산하여 레이아웃 트리를 만듭니다.

        레이아웃 트리가 생성된 후 레이어의 스택 컨텍스트에 따라 레이어링되거나 잘린 부분이 레이어드 트리를 형성합니다.

        그런 다음 렌더링 프로세스에서는 각 레이어에 대한 도면 목록을 생성하고 이를 컴포지션 스레드에 제출합니다. 일회성 렌더링을 방지하기 위해 컴포지션 스레드는 레이어를 타일로 나누고 래스터화를 통해 타일을 변환합니다. 스레드 풀.

        변환이 완료된 후 합성 스레드는 표시를 위해 브라우저에 타일을 그리는 명령을 보냅니다

        TCP와 UDP의 차이점

        UDP는 User Datagram Protocol(User Dataprogram Protocol)입니다. IP는 IP 주소 정보를 통해 지정된 컴퓨터로 데이터 패킷을 전송한 후 UDP가 데이터 패킷을 올바른 컴퓨터로 배포할 수 있습니다. 포트 번호 프로그램을 통해. UDP는 데이터가 올바른지 확인할 수 있지만 재전송 메커니즘이 없으며 잘못된 데이터 패킷만 폐기합니다. 동시에 UDP는 데이터를 보낸 후 대상에 도달했는지 여부를 확인할 수 없습니다. UDP는 데이터의 신뢰성을 보장할 수는 없으나 전송 속도가 매우 빠르기 때문에 데이터 무결성을 엄격하게 보장하지 못하는 온라인 동영상, 대화형 게임 등의 영역에서 주로 사용됩니다.

        TCP는 UDP 데이터가 손실되기 쉽고 데이터 패킷을 올바르게 조립할 수 없는 문제를 해결하기 위해 도입된 전송 제어 프로토콜(Transmission Control Protocol)입니다. 연결 지향적이고 안정적인 바이트 스트림 기반 전송 계층 통신 프로토콜입니다. . TCP는 패킷 손실을 처리하기 위한 재전송 메커니즘을 제공하고, TCP는 순서가 잘못된 데이터 패킷을 완전한 파일로 결합할 수 있는 패킷 정렬 메커니즘을 도입합니다.

        TCP 헤더는 대상 포트와 로컬 포트 ​​번호 외에도 정렬을 위한 시퀀스 번호도 제공하므로 수신측에서는 시퀀스 번호를 통해 데이터 패킷을 재정렬할 수 있습니다.

        TCP와 UDP의 차이점

        TCP 연결의 수명주기는 링크 단계, 데이터 전송 및 연결 해제 단계의 세 단계를 거칩니다.

        연결 단계

        는 클라이언트와 서버 간의 링크를 설정하는 데 사용됩니다. 3방향 핸드셰이크는 클라이언트와 서버 간의 데이터 패킷 송수신 기능을 확인하는 데 사용됩니다.

        1. 클라이언트는 먼저 SYN 메시지를 보내 서버가 데이터를 보낼 수 있음을 확인하고 SYN_SENT 상태로 들어가 서버의 확인을 기다립니다.

        2. 서버가 SYN 메시지를 받으면 ACK를 보냅니다. 동시에 서버는 클라이언트에게 SYN 메시지를 보내 클라이언트가 데이터를 보낼 수 있는지 확인합니다. 이때 서버는 클라이언트가 수신하면 SYN_RCVD 상태로 들어갑니다. ACK + SYN 메시지는 서버에 메시지를 보냅니다. 데이터 패킷을 보내고 ESTABLISHED 상태로 들어갑니다(연결 설정). 서버가 클라이언트가 보낸 ACK 패킷을 받으면 ESTABLISHED 상태로 들어가고 완료됩니다. the three-way handshake

        데이터 전송 단계

        이 단계에서는 수신 측에서 각 패킷을 처리해야 합니다. 확인 작업을 수행합니다. 지정된 시간 내에 수신자가 수신하면 패킷 손실로 판단되어 재전송 메커니즘이 시작됩니다.

        대용량 파일이 있습니다. 전송 과정에서 데이터 패킷이 목적지에 도착한 후 여러 개의 작은 데이터 패킷으로 나뉩니다. 수신 측에서는 데이터 무결성을 보장하기 위해 TCP 헤더의 시퀀스 번호에 따라 정렬됩니다.

        연결 해제 단계

        양쪽이 설정한 연결이 끊어질 수 있도록 4번 웨이브1 클라이언트가 서버에 FIN 패킷을 시작하고 FIN_WAIT_1 상태로 들어갑니다

        2. 패킷을 보내고 자신의 시퀀스 번호가 포함된 확인 패킷 ACK를 보내면 서버는 CLOSE_WAIT 상태로 들어갑니다. 이때 클라이언트는 서버로 보낼 데이터가 없지만 서버가 클라이언트로 보낼 데이터가 있는 경우 클라이언트는 이를 수신해야 합니다. ACK를 받은 후 클라이언트는 FIN_WAIT_2 상태로 들어갑니다

        3. 서버는 데이터 전송을 완료한 후 FIN 패킷을 클라이언트로 보냅니다. 이때 서버는 LAST_ACK 상태로 들어갑니다

        4. FIN 패킷을 전송하고 확인 패킷 ACK를 보냅니다. 이때 클라이언트는 TIME_WAIT 상태로 진입하고 2MSL을 기다린 후 CLOSED 상태로 진입합니다. 서버는 클라이언트의 ACK를 받은 후 CLOSED 상태로 진입합니다.

        4개의 웨이브의 경우 TCP는 전이중 통신이므로 활성 종료 당사자가 FIN 패킷을 보낸 후에도 수신 측에서는 여전히 데이터를 보낼 수 있으며 서버에서 클라이언트로의 데이터 채널을 즉시 닫을 수 없으므로 서버는 -side can be FIN 패킷은 ACK 패킷과 함께 클라이언트로 전송됩니다. ACK는 먼저 확인될 수 있으며 그 다음에는 서버는 FIN 패킷을 보낼 필요가 없을 때까지 를 보내지 않으므로 4개의 웨이브는 4개의 데이터 패킷 상호 작용이어야 합니다</p><h4 data-id="heading-50"><p>Content-length Do 이해해요? </p><p><code>FIN 包与对客户端的 ACK 包合并发送,只能先确认 ACK,然后服务器待无需发送数据时再发送 FIN 包,所以四次挥手时必须是四次数据包的交互

        Content-length 了解吗?

        Content-length 是 http 消息长度,用十进制数字表示的字节的数目。

        如果 content-length > 实际长度,服务端/客户端读取到消息队尾时会继续等待下一个字节,会出现无响应超时的情况

        如果 content-length < 实际长度,首次请求的消息会被截取,然后会导致后续的数据解析混乱。

        当不确定content-length的值应该使用Transfer-Encoding: chunked,能够将需要返回的数据分成多个数据块,直到返回长度为 0 的终止块

        跨域常用方案

        什么是跨域?

        协议 + 域名 + 端口号均相同时则为同域,任意一个不同则为跨域

        解决方案

        1、 传统的jsonp:利用<script>Content-length는 http 메시지 길이로, 십진수로 표현된 바이트 수입니다.

        🎜content-length > 실제 길이인 경우 서버/클라이언트는 메시지 대기열의 끝을 읽을 때 다음 바이트를 계속 기다리며 응답 없음 시간 초과가 발생합니다. 🎜🎜content-length < , 처음으로 요청된 메시지가 가로채어 후속 데이터 구문 분석에 혼란을 초래할 수 있습니다. 🎜🎜content-length 값이 확실하지 않은 경우 길이가 0인 종료 블록이 반환될 때까지 반환할 데이터를 여러 데이터 청크로 나눌 수 있는 Transfer-Encoding: Chunked를 사용해야 합니다.🎜

        🎜일반적인 교차 도메인 솔루션🎜🎜🎜🎜교차 도메인이란 무엇인가요? 🎜🎜🎜프로토콜 + 도메인 이름 + 포트 번호가 동일하면 동일한 도메인입니다. 🎜🎜🎜Solution🎜🎜🎜1. <script> 태그에는 도메인 간 제한이 없으며 get 인터페이스만 지원합니다. 더 이상 이 태그를 사용하면 안 됩니다.

        2、 一般使用 cors(跨域资源共享)来解决跨域问题,浏览器在请求头中发送origin字段指明请求发起的地址,服务端返回Access-control-allow-orign,如果一致的话就可以进行跨域访问

        3、 Iframe 解决主域名相同,子域名不同的跨域请求

        4、 浏览器关闭跨域限制的功能

        5、 http-proxy-middleware 代理

        预检

        补充:http会在跨域的时候发起一次预检请求,“需预检的请求”要求必须首先使用OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。“预检请求”的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

        withCredentials为 true不会产生预请求;content-type为application/json会产生预请求;设置了用户自定义请求头会产生预检请求;delete方法会产生预检请求;

        XSS 和 CSRF

        xss基本概念

        Xss (Cross site scripting)跨站脚本攻击,为了和 css 区别开来所以叫 xss

        Xss 指黑客向 html 或 dom 中注入恶意脚本,从而在用户浏览页面的时候利用注入脚本对用户实施攻击的手段

        恶意脚本可以做到:窃取 cookie 信息、监听用户行为(比如表单的输入)、修改DOM(比如伪造登录界面骗用户输入账号密码)、在页面生成浮窗广告等

        恶意脚本注入方式:

        • 存储型 xss

          黑客利用站点漏洞将恶意 js 代码提交到站点服务器,用户访问页面就会导致恶意脚本获取用户的cookie等信息。

        • 反射性 xss

          用户将一段恶意代码请求提交给 web 服务器,web 服务器接收到请求后将恶意代码反射到浏览器端

        • 基于 DOM 的 xss 攻击

          通过网络劫持在页面传输过程中更改 HTML 内容

        前两种属于服务端漏洞,最后一种属于前端漏洞

        防止xss攻击的策略

        1、服务器对输入脚本进行过滤或者转码,比如将code:<script>alert('你被xss攻击了')转换成code:<script>alert('你被xss攻击了')

        2、充分利用内容安全策略 CSP(content-security-policy),可以通过 http 头信息的 content-security-policy 字段控制可以加载和执行的外部资源;或者通过html的meta 标签<meta http-equiv="Content-Security-Policy" content="script-src &#39;self&#39;; object-src &#39;none&#39;; style-src cdn.example.org third-party.org; child-src https:">

        3、cookie设置为 http-only, cookie 就无法通过 document.cookie 来读取

        csrf基本概念

        Csrf(cross site request forgery)跨站请求伪造,指黑客引导用户访问黑客的网站。

        CSRF 是指黑客引诱用户打开黑客的网站,在黑客的网站中,利用用户的登录状态发起的跨站请求。简单来讲,CSRF 攻击就是黑客利用了用户的登录状态,并通过第三方的站点来做一些坏事。

        Csrf 攻击场景

        • 自动发起 get 请求

          比如黑客网站有个图片:

          <img  src="https://time.geekbang.org/sendcoin?user=hacker&number=100" alt="3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인" >
          로그인 후 복사

          黑客将转账的请求接口隐藏在 img 标签内,欺骗浏览器这是一张图片资源。当该页面被加载时,浏览器会自动发起 img 的资源请求,如果服务器没有对该请求做判断的话,那么服务器就会认为该请求是一个转账请求,于是用户账户上的 100 极客币就被转移到黑客的账户上去了。

        • 自动发起 post 请求

          黑客在页面中构建一个隐藏的表单,当用户点开链接后,表单自动提交

        • 引诱用户点击链接

          比如页面上放了一张美女图片,下面放了图片下载地址,而这个下载地址实际上是黑客用来转账的接口,一旦用户点击了这个链接,那么他的极客币就被转到黑客账户上了

        防止csrf方法

        1、设置 cookie 时带上SameSite: strict/Lax选项

        2、验证请求的来源站点,通过 origin 和 refere 判断来源站点信息

        3、csrf token,浏览器发起请求服务器生成csrf token,发起请求前会验证 csrf token是否合法。第三方网站肯定是拿不到这个token。我们的 csrf token 是前后端约定好后写死的。

        websocket

        websocket是一种支持双向通信的协议,就是服务器可以主动向客户端发消息,客户端也可以主动向服务器发消息。

        HTTP 프로토콜을 기반으로 연결을 설정하므로 HTTP 프로토콜과 잘 호환되므로 동일 출처 제한이 없습니다.

        WebSocket은 이벤트 중심 프로토콜이므로 진정한 실시간 통신에 사용할 수 있습니다. 업데이트를 지속적으로 요청해야 하는 HTTP와 달리 웹소켓을 사용하면 업데이트가 제공되는 즉시 전송됩니다.

        웹소켓은 연결이 종료될 때 자동으로 복구되지 않습니다. 이는 애플리케이션 개발에서 직접 구현해야 하는 메커니즘입니다. , 클라이언트 측 오픈 소스 라이브러리가 필요한 이유 중 하나는 많습니다.

        webpack 및 vite와 같은 devServer는 웹소켓을 사용하여 핫 업데이트를 구현합니다.

        Post와 Get의 차이점

        • 애플리케이션 시나리오: (GET 요청은 idempotent 요청입니다.) 일반적으로 Get 요청은 다음을 요청하는 데 사용됩니다. 웹 페이지에 대한 리소스 요청과 같이 리소스가 영향을 미치지 않는 서버 시나리오. (그리고 Post는 idempotent 요청이 아닙니다.) 일반적으로 사용자 등록과 같은 작업과 같이 서버 리소스에 영향을 미치는 시나리오에서 사용됩니다. (Idempotence는 요청 메서드를 여러 번 실행하고 한 번만 실행하는 효과가 완전히 동일하다는 의미)
        • 캐시할지 여부: 두 가지의 적용 시나리오가 다르기 때문에 브라우저는 일반적으로 Get 요청을 캐시하지만, 드물게 게시 요청 캐싱을 요청합니다.
        • 매개변수는 다양한 방식으로 전달됩니다. Get은 쿼리 문자열을 통해 매개변수를 전달하고 Post는 요청 본문을 통해 매개변수를 전달합니다.
        • 보안: Get 요청은 요청된 매개변수를 URL에 넣어 서버로 보낼 수 있습니다. 이 접근 방식은 요청한 URL이 기록에 유지되므로 Post 요청보다 덜 안전합니다.
        • 요청 길이: URL의 브라우저 길이 제한으로 인해 데이터를 보낼 때 요청 가져오기 길이에 영향을 미칩니다. 이 제한은 RFC가 아닌 브라우저에 의해 규정됩니다.
        • 매개변수 유형: get 매개변수는 ASCII 문자만 허용하며 post 매개변수 전송은 더 많은 데이터 유형(예: 파일, 그림)을 지원합니다.

        성능 최적화

        성능 최적화는 중견기업과 대기업이 크게 주목하는 포인트입니다. 프론트엔드 인력의 KPI와도 밀접한 관련이 있기 때문에 자연스럽게 면접 질문이 잦아지게 됩니다.

        3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

        성능 최적화 방법은 무엇인가요

        • 캐싱의 관점에서

          • localstorage/sessionStorage/indexdDB를 통해 자주 변경되지 않는 대용량 데이터를 읽어보세요
          • http 캐시를 사용하세요(강력한 캐시와 협상) 캐시), 메모리나 하드디스크에 콘텐츠 저장, 서버에 대한 요청 감소
        • 네트워크에서는 정적 리소스에 CDN을 사용하는 것이 더 일반적입니다

        • 패키징 측면에서

          • - 요청 시 경로 로드
          • 최적화된 패키징 최종 리소스 크기
          • gzip 압축 리소스 활성화
          • 필요에 따라 타사 라이브러리 로드
        • 코드 수준

          • 불필요한 요청을 줄이고 불필요한 코드를 삭제하세요
          • 긴 시간을 피하세요 -메인 스레드를 차단하는 시간 js 처리(시간이 많이 걸리고 DOM과 관련 없는 스레드는 처리를 위해 웹 작업자에게 전달되거나 작은 작업으로 분할될 수 있음)
          • 사진은 지연 로딩을 사용하여 로드할 수 있고 긴 목록은 가상 스크롤을 사용할 수 있음
        • 첫 번째 화면 속도 향상

          • 코드 압축, 패키지된 정적 리소스의 양 감소(Terser 플러그인/MiniCssExtratplugin)
          • 경로의 지연 로딩, 첫 번째 화면은 첫 번째 경로의 관련 리소스만 요청함
          • cdn을 사용하여 세 번째 가속화 -파티 라이브러리, 우리는 toB의 제품이므로 필요합니다. 인트라넷에 배포되므로 일반적으로 사용되지 않습니다. ToC는 대부분
          • ssr 서버 측 렌더링으로 사용되며, 서버는 스플라이싱된 ​​html을 직접 반환합니다. 페이지
        • vue 일반적인 성능 최적화 방법

          • 이미지 지연 로딩: vue-lazyLoad
          • 가상 스크롤
          • 기능적 구성 요소
          • v-show/ keep-alive DOM 재사용
          • defer 지연된 렌더링 구성 요소(requestIdleCallback)
          • 타임 슬라이싱

        프런트엔드 모니터링 SDK 기술 포인트

        • window.performance

        • 를 통해 다양한 성과 지표 데이터를 얻을 수 있습니다. 완전한 프런트엔드 모니터링 플랫폼에는 다음이 포함됩니다: 데이터 수집 및 보고, 데이터 정렬 및 저장, 데이터 표시

        • 웹 페이지 성능 지표:

          • FP(first-paint) 페이지가 로드된 후 첫 번째 픽셀이 화면에 그려지는 시간
          • FCP(first-contentful-paint) ), 페이지가 로드된 시점부터 페이지 콘텐츠의 일부가 화면에서 렌더링을 완료할 때까지의 시간
          • LCP(largest-contentful-paint), 페이지 로딩부터 가장 큰 텍스트 또는 이미지 요소의 렌더링이 완료될 때까지의 시간 화면에
        • 위 지표는 PerformanceObserver

          를 통해 얻을 수 있습니다.
        • 首屏渲染时间计算:通过MutationObserver监听document对象的属性变化

        如何减少回流、重绘,充分利用 GPU 加速渲染?

        首先应该避免直接使用 DOM API 操作 DOM,像 vue react 虚拟 DOM 让对 DOM 的多次操作合并成了一次。

        • 样式集中改变,好的方式是使用动态 class

        • 读写操作分离,避免读后写,写后又读

          // bad 强制刷新 触发四次重排+重绘
          div.style.left = div.offsetLeft + 1 + &#39;px&#39;;
          div.style.top = div.offsetTop + 1 + &#39;px&#39;;
          div.style.right = div.offsetRight + 1 + &#39;px&#39;;
          div.style.bottom = div.offsetBottom + 1 + &#39;px&#39;;
          
          
          // good 缓存布局信息 相当于读写分离 触发一次重排+重绘
          var curLeft = div.offsetLeft;
          var curTop = div.offsetTop;
          var curRight = div.offsetRight;
          var curBottom = div.offsetBottom;
          
          div.style.left = curLeft + 1 + &#39;px&#39;;
          div.style.top = curTop + 1 + &#39;px&#39;;
          div.style.right = curRight + 1 + &#39;px&#39;;
          div.style.bottom = curBottom + 1 + &#39;px&#39;;
          로그인 후 복사

          原来的操作会导致四次重排,读写分离之后实际上只触发了一次重排,这都得益于浏览器的渲染队列机制:

          当我们修改了元素的几何属性,导致浏览器触发重排或重绘时。它会把该操作放进渲染队列,等到队列中的操作到了一定的数量或者到了一定的时间间隔时,浏览器就会批量执行这些操作。

        • 使用display: none后元素不会存在渲染树中,这时对它进行各种操作,然后更改 display 显示即可(示例:向2000个div中插入一个div)

        • 通过 documentFragment 创建 dom 片段,在它上面批量操作 dom ,操作完后再添加到文档中,这样只有一次重排(示例:一次性插入2000个div)

        • 复制节点在副本上操作然后替换它

        • 使用 BFC 脱离文档流,重排开销小

        Css 中的transformopacityfilterwill-change能触发硬件加速

        大图片优化的方案

        • 优化请求数

          • 雪碧图,将所有图标合并成一个独立的图片文件,再通过 background-urlbackgroun-position来显示图标
          • 懒加载,尽量只加载用户正则浏览器或者即将浏览的图片。最简单使用监听页面滚动判断图片是否进入视野;使用 intersection Observer API;使用已知工具库;使用css的background-url来懒加载
          • base64,小图标或骨架图可以使用内联 base64因为 base64相比普通图片体积大。注意首屏不需要懒加载,设置合理的占位图避免抖动。
        • 减小图片大小

          • 使用合适的格式比如WebP、svg、video替代 GIF 、渐进式 JPEG
          • 削减图片质量
          • 使用合适的大小和分辨率
          • 删除冗余的图片信息
          • Svg 压缩
        • 缓存

        代码优化

        • 非响应式变量可以定义在created钩子中使用 this.xxx 赋值

        • 访问局部变量比全局变量块,因为不需要切换作用域

        • 尽可能使用 const声明变量,注意数组和对象

        • 使用 v8 引擎时,运行期间,V8 会将创建的对象与隐藏类关联起来,以追踪它们的属性特征。能够共享相同隐藏类的对象性能会更好,v8 会针对这种情况去优化。所以为了贴合”共享隐藏类“,我们要避免”先创建再补充“式的动态属性复制以及动态删除属性(使用delete关键字)。即尽量在构造函数/对象中一次性声明所有属性。属性删除时可以设置为 null,这样可以保持隐藏类不变和继续共享。

        • 避免内存泄露的方式

          • 尽可能少创建全局变量
          • 手动清除定时器
          • 少用闭包
          • 清除 DOM 引用
          • 弱引用
        • 避免强制同步,在修改 DOM 之前查询相关值

        • 避免布局抖动(一次 JS 执行过程中多次执行强制布局和抖动操作),尽量不要在修改 DOM 结构时再去查询一些相关值

        • 合理利用 css 合成动画,如果能用 css 处理就交给 css。因为合成动画会由合成线程执行,不会占用主线程

        • 避免频繁的垃圾回收,优化存储结构,避免小颗粒对象的产生

        感兴趣的可以看看我之前的一篇性能优化技巧整理的文章极意 · 代码性能优化之道

        프런트엔드 엔지니어링

        프론트엔드 엔지니어링은 프론트엔드 ER 성장에 있어서 가장 필수적인 스킬 포인트입니다. 프런트엔드 개발 효율성을 높일 수 있는 모든 기능은 프론트엔드의 일부라고 볼 수 있습니다. 엔지니어링을 종료합니다. 이제 막 시작한 사람들은 스캐폴딩을 처음부터 구축하는 것부터 시작할 수 있습니다10,000 단어에 달하는 긴 글은 엔터프라이즈급 vue3 + vite2+ ts4 프레임워크를 처음부터 구축하는 전체 과정을 자세히 설명합니다

        인터뷰에서 가장 중요한 것은 시험은 포장 도구의 숙달입니다.

        3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

        webpack의 실행 프로세스 및 라이프사이클

        webpack은 최신 JS 애플리케이션에 정적 리소스 패키징 기능을 제공하는 번들입니다.

        핵심 프로세스는 초기화 단계, 구성 단계 및 생성 단계의 세 단계로 구성됩니다.

        1 초기화 단계에서는 구성 파일, 구성 개체 및 셸 매개변수에서 초기화 매개변수를 읽어 기본 구성과 결합하여 구성합니다. 최종 매개변수는 물론 컴파일러 개체를 생성하고 실행 환경을 초기화합니다

        2. 컴파일러는 run() 메서드를 실행하여 컴파일 프로세스를 시작합니다. 항목 파일에서 항목 파일 검색을 시작합니다. 직접 또는 간략하게 연관된 모든 파일에 대한 종속 개체를 생성한 다음 종속 개체를 기반으로 모듈 개체를 생성합니다. 이때 로더는 모듈을 표준으로 변환하는 데 사용됩니다. js 콘텐츠를 호출한 다음 js 인터프리터를 호출하여 콘텐츠를 AST 개체로 변환한 다음 AST에서 모듈이 의존하는 모듈을 찾고 모든 항목 종속성 파일이 이 단계에서 처리될 때까지 이 단계를 반복합니다. 마지막으로 모듈 컴파일이 완료되고, 각 모듈의 번역된 내용과 이들 사이의 종속성 그래프가 얻어집니다. 이 종속성 그래프는 프로젝트에 사용되는 모든 모듈의 매핑 관계입니다.

        3. 생성 단계에서는 컴파일된 모듈을 덩어리로 결합한 후 각 덩어리를 별도의 파일로 변환하여 파일 목록에 출력합니다. 출력 내용을 결정한 후 구성에 따라 출력 경로와 파일 이름을 결정합니다. , 그리고 파일을 추가하세요. 콘텐츠는 파일 시스템에 기록됩니다

        webpack의 플러그인과 로더

        loader

        webpack은 JS 및 JSON 파일만 이해할 수 있습니다. 로더는 본질적으로 다른 유형의 파일을 변환할 수 있는 변환기입니다.

        Loader는 webpack 빌드 단계에서 종속 객체에 의해 생성된 모듈을 표준 js 콘텐츠로 변환합니다. 예를 들어 vue-loader는 vue 파일을 js 모듈로 변환하고, 이미지 글꼴은 url-loader를 통해 데이터 URL로 변환하는 것입니다.

        module.rules에서 다양한 로더를 구성하여 다양한 파일을 구문 분석할 수 있습니다

        plugin

        플러그인은 기본적으로 적용 함수가 있는 클래스입니다class myPlugin { apply(compiler) {} } 이 적용 함수에는 매개변수 컴파일러가 있습니다. webpack 객체의 초기화 단계에서는 컴파일러 객체에서 후크를 호출하여 다양한 후크에 대한 콜백을 등록할 수 있습니다. 이러한 후크는 전체 컴파일 수명 주기 동안 실행됩니다. 따라서 개발자는 후크 콜백을 통해 특정 코드를 여기에 삽입하여 특정 기능을 달성할 수 있습니다.

        예를 들어 stylelint 플러그인은 stylelint가 확인해야 하는 파일 형식과 파일 범위를 지정할 수 있습니다. HtmlWebpackPlugin은 패키지된 템플릿 파일을 생성하는 데 사용되며 MiniCssExtactPlugin은 모든 CSS를 독립적인 청크로 추출하고 stylelintplugin은 개발 단계에서 스타일 확인 기능을 제공할 수 있습니다. .

        Webpack의 해시 전략

        MiniCssExtractPlugin 브라우저의 경우 페이지 리소스를 요청할 때마다 최신 리소스를 가져오길 기대하는 반면, 리소스가 있을 때 캐시된 개체를 재사용할 수 있을 것으로 기대합니다. 변경되지 않았습니다. 이때, 파일명 + 파일 해시값 방식을 이용하면 파일명만으로 리소스가 업데이트 되었는지 구별할 수 있다. Webpack에는 생성된 파일에 대해 해시 계산 방법이 내장되어 있으며 출력 파일에 해시 필드를 추가할 수 있습니다.

        Webpack에는 3개의 내장 해시가 있습니다

        • hash: 프로젝트가 빌드될 때마다 전체 프로젝트와 관련된 해시가 생성됩니다.

          해시는 각 프로젝트의 콘텐츠를 기반으로 계산되므로 불필요한 해시 변경이 발생하기 쉽고 이는 버전 관리에 도움이 되지 않습니다. 일반적으로 해시를 직접 사용할 기회는 거의 없습니다.

        • content hash: 단일 파일의 콘텐츠와 관련됩니다. 지정된 파일의 내용이 변경되면 해시도 변경됩니다. 내용은 변경되지 않고 해시 값도 변경되지 않습니다.

          Css 파일의 경우 일반적으로 MiniCssExtractPlugin을 사용하여 별도의 CSS 파일로 추출합니다.

          이 시점에서 contenthash를 사용하여 표시하면 CSS 파일의 내용이 변경될 때 해시가 업데이트될 수 있습니다.

        • chunk hash: 웹팩 패키징으로 생성된 청크와 관련됩니다. 각 항목에는 서로 다른 해시가 있습니다.

          일반적으로 출력 파일에는 청크해시를 사용합니다.

          webpack이 패키징된 후에는 각 항목 파일과 해당 종속 항목이 결국 별도의 js 파일을 생성하게 되기 때문입니다.

          이때 청크해시를 사용하면 패키지된 콘텐츠 전체의 업데이트 정확성을 보장할 수 있습니다.

        확장: file-loader hash 일부 학생들은 다음과 같은 질문을 할 수 있습니다.

        일부 이미지 및 글꼴 파일-로더 패키징을 처리할 때 [이름]_[hash:8].[ext]를 사용하는 경우를 종종 볼 수 있습니다

        그러나 index.js와 같은 다른 프로젝트 파일이 변경되면 생성된 이미지 해시가 변경되지 않았습니다.

        여기서 로더 자체에 의해 정의된 자리 표시자인 file-loader의 해시 필드는 webpack의 내장 해시 필드와 일치하지 않는다는 점에 유의해야 합니다.

        여기서 해시는 md4와 같은 해시 알고리즘을 사용하여 파일 내용을 해시하는 것입니다.

        파일 내용이 변경되지 않는 한 해시는 일관성을 유지합니다.

        Vite 원리

        Vite는 주로 두 부분으로 구성됩니다

        • 개발 환경

          Vite는 브라우저를 사용하여 서버 측에서 가져오기를 구문 분석하고, 컴파일하고 요청 시 반환하므로 패키징 개념을 완전히 건너뛰고, 서버는 사용하기 쉽습니다(개발 중인 파일을 ESM 형식으로 변환하여 브라우저로 직접 보내는 것과 동일)

          브라우저가 './comComponents/HelloWorld.vue'에서 import HelloWorld를 구문 분석할 때 요청을 보냅니다. 해당 리소스(ESM은 상대 경로 구문 분석 지원)에 대해 브라우저에서 직접 해당 파일을 다운로드하고 모듈 레코드로 구문 분석합니다(네트워크 패널을 열면 응답 데이터가 모두 ESM 유형 js임을 확인할 수 있습니다). ). 그런 다음 모듈에 메모리를 인스턴스화하고 할당하고 import 및export 문에 따라 모듈과 메모리 간의 매핑 관계를 설정합니다. 마지막으로 코드를 실행해 보세요.

          vite는 koa 서버를 시작하여 브라우저의 ESM 요청을 가로채고, 요청 경로를 통해 디렉터리에서 해당 파일을 찾아 ESM 형식으로 처리한 후 클라이언트에 반환합니다.

          Vite의 핫 로딩은 클라이언트와 서버 사이에 웹소켓 연결을 설정합니다. 코드가 수정된 후 서버는 클라이언트에게 수정된 모듈 코드를 요청하라는 메시지를 보냅니다. 핫 업데이트를 완료하려면 무엇이든 다시 요청해야 합니다. 뷰 파일이 변경됩니다. 해당 파일은 핫 업데이트 속도가 프로젝트 크기에 영향을 받지 않도록 합니다.

          개발 환경은 esbuild를 사용하여 종속성에 대한 캐시를 사전 구축합니다. 첫 번째 시작은 느려지고 후속 시작은 캐시를 직접 읽습니다.

        • 프로덕션 환경

          은 롤업을 사용하여 코드를 빌드하고 다음을 제공합니다. 빌드 프로세스 최적화에 대한 지침입니다. 단점은 개발 환경과 프로덕션 환경이 일치하지 않을 수 있다는 것입니다.

        webpack과 vite의 비교

        Webpack의 핫 업데이트 원칙은 단순히 특정 종속성이 발생하면(예: a.js )改变,就将这个依赖所处的 module 的更新,并将新的 module 发送给浏览器重新执行。每次热更新都会重新生成 bundle. 파일 하나만 수정하더라도 이론적으로 핫 업데이트 속도는 점점 더 느려질 것입니다.

        Vite는 브라우저를 사용하여 가져오기를 구문 분석하고 필요에 따라 컴파일하고 서버 측에 반환하며 완전히 건너뜁니다. 패키징의 개념에 따르면 서버는 언제든지 사용할 수 있으며 핫 업데이트는 클라이언트와 서버 사이에 웹 소켓 연결을 설정하는 것입니다. 코드가 수정된 후 서버는 수정된 모듈 코드를 요청하도록 클라이언트에 알리는 메시지를 보냅니다. 어떤 파일이 변경되든 핫 업데이트를 완료하려면 다시 요청해야 합니다. 이를 통해 핫 업데이트 속도가 프로젝트 크기에 영향을 받지 않습니다.

        그래서 현재 Vite의 가장 큰 특징은 서비스가 시작된다는 것입니다. 빠르고 핫 업데이트가 빨라 개발자 경험을 최적화합니다. 프로덕션 환경의 최하위 계층이 롤업이므로 롤업은 확장성 및 기능 측면에서 소규모 프로젝트에 더 적합합니다. Vite를 개발 서버로 사용하고, 프로덕션 패키징에는 webpack을 사용할 수 있습니다.

        어떤 webpack 최적화를 수행했나요? 0. webpack 버전을 3리터로 업그레이드하세요. 4. 실제 테스트는 패키징 속도를 높이는 것입니다. 수십 초

        1. SplitChunksPlugin은 공유 모듈을 분리하고 별도의 청크를 출력합니다. 일부 타사 종속 라이브러리와 마찬가지로 단일 청크가 너무 커지는 것을 방지하기 위해 별도로 분할할 수 있습니다.

        2. 위의 종속 라이브러리는 비즈니스 코드에서 분리되는 것과 같습니다. 종속 라이브러리 자체의 버전이 변경되는 경우에만 다시 패키징되어 패키징 속도가 향상됩니다.

        3. 로더에 oneOf를 사용할 수 있습니다

        . 해당 로더가 일치하는 한 로더는 계속 실행되지 않습니다. 로더의 동기 실행을 병렬 실행으로 변환하려면 happyPack을 사용하세요. loader, css-loader, less-loader가 결합되어 실행됩니다.

          4. 별칭은 일치하는 범위를 지정합니다.
        • 5. ESM 프로젝트는 다음과 같습니다. useExport 태그에서 tree-shaking을 사용합니다
        • 7. 별칭은 일치 범위를 지정하고, 캐시 로더 영구 저장소를 지정합니다.

        8.terserPlugin은 MiniCssExtractPlugin을 압축합니다. CSS

        npm 실행 프로세스

        0 스크립트 구성 항목은 package.json 파일에 정의할 수 있으며, 이는 스크립트 실행을 위한 키와 값을 정의할 수 있습니다

        1. node_modules/.bin 디렉터리에 대한 스크립트 소프트 링크 , node_modules/.bin目录下,同时将./bin加入当环境变量$PATH,所以如果在全局直接运行该命令会去全局目录里找,可能会找不到该命令就会报错。比如 npm run start,他是执行的webpack-dev-server带上参数

        2、还有一种情况,就是单纯的执行脚本命令,比如 npm run build,实际运行的是 node build.js,即使用 node 执行 build.js 这个文件

        ESM和CJS 的区别

        ES6

        • ES6模块是引用,重新赋值会编译报错,不能修改其变量的指针指向,但可以改变内部属性的值;
        • ES6模块中的值属于动态只读引用。
        • 对于只读来说,即不允许修改引入变量的值,import的变量是只读的,不论是基本数据类型还是复杂数据类型。当模块遇到import命令时,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。
        • 对于动态来说,原始值发生变化,import 加载的值也会发生变化。不论是基本数据类型还是复杂数据类型。
        • 循环加载时,ES6模块是动态引用。只要两个模块之间存在某个引用,代码就能够执行。

        CommonJS

        • CommonJS模块是拷贝(浅拷贝),可以重新赋值,可以修改指针指向;
        • 对于基本数据类型,属于复制。即会被模块缓存。同时,在另一个模块可以对该模块输出的变量重新赋值。
        • 对于复杂数据类型,属于浅拷贝。由于两个模块引用的对象指向同一个内存空间,因此对该模块的值做修改时会影响另一个模块。 当使用require命令加载某个模块时,就会运行整个模块的代码。
        • 当使用require命令加载同一个模块时,不会再执行该模块,而是取到缓存之中的值。也就是说,CommonJS模块无论加载多少次,都只会在第一次加载时运行一次,以后再加载,就返回第一次运行的结果,除非手动清除系统缓存。
        • 当循环加载时,脚本代码在require的时候,就会全部执行。一旦出现某个模块被"循环加载",就只输出已经执行的部分,还未执行的部分不会输出。

        设计模式篇

        代理模式

        代理模式:为对象提供一个代用品或占位符,以便控制对它的访问

        例如实现图片懒加载的功能,先通过一张loading图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img환경 변수 $PATH./bin 추가

        따라서 이 명령을 전역적으로 직접 실행하면 전역 디렉터리에서 검색됩니다. 명령을 찾을 수 없으면 오류가 보고됩니다. 예를 들어 npm run start는

        2 매개변수를 사용하여 webpack-dev-server를 실행합니다. npm run build와 같은 단순히 스크립트 명령을 실행하면 실제로 node build.js, 즉 node를 실행하는 경우도 있습니다. build.js 파일

        ESM과 CJS의 차이점

        ES6

        • ES6 모듈은 참고용이므로 재할당하면 컴파일 오류가 발생하므로 불가능합니다. 해당 변수의 포인터를 수정하지만 내부 속성의 값을 변경할 수 있습니다.
        • ES6 모듈의 값은 동적 읽기 전용 참조입니다.
        • 읽기 전용의 경우, 즉 가져온 변수의 값은 기본 데이터 유형이든 복합 데이터 유형이든 읽기 전용입니다. 모듈이 import 명령을 만나면 읽기 전용 참조가 생성됩니다. 스크립트가 실제로 실행되면 이 읽기 전용 참조를 기반으로 로드된 모듈에서 값이 검색됩니다.
        • 동적의 경우 원래 값이 변경되면 가져오기로 로드된 값도 변경됩니다. 기본 데이터 유형인지 복합 데이터 유형인지 여부.
        • 루프에서 로드할 때 ES6 모듈은 동적으로 참조됩니다. 두 모듈 사이에 일부 참조가 존재하는 한 코드는 실행될 수 있습니다.

        CommonJS

        • CommonJS 모듈은 재할당될 수 있고 포인터가 가리키는 복사본(얕은 복사본)입니다.
        • 기본 데이터 유형의 경우; , 사본에 속합니다. 즉, 모듈에 의해 캐시됩니다. 동시에 이 모듈에서 출력된 변수는 다른 모듈에 다시 할당될 수 있습니다.
        • 복잡한 데이터 유형의 경우 얕은 복사본입니다. 두 모듈에서 참조하는 개체는 동일한 메모리 공간을 가리키므로 모듈 값을 수정하면 다른 모듈에 영향을 미칩니다. require 명령을 사용하여 모듈을 로드하면 전체 모듈의 코드가 실행됩니다.
        • require 명령을 사용하여 동일한 모듈을 로드하는 경우 해당 모듈은 다시 실행되지 않지만 캐시에 있는 값을 가져옵니다. 즉, CommonJS 모듈은 아무리 많이 로드해도 처음 로드할 때 한 번만 실행됩니다. 나중에 로드할 경우 시스템 캐시가 없으면 첫 번째 실행 결과가 반환됩니다. 수동으로 지워졌습니다.
        • 루프에서 로드할 때 필요할 때 모든 스크립트 코드가 실행됩니다. 모듈이 "루프 로드"되면 실행된 부분만 출력되고 실행되지 않은 부분은 출력되지 않습니다.

        디자인 패턴

        에이전트 모드

        에이전트 모드: 제공 개체에 대한 액세스를 제어하기 위한 대체 또는 자리 표시자

        예를 들어, 이미지 지연 로딩 기능을 구현하려면 먼저 loading 이미지 자리 표시자를 전달한 다음 이미지를 비동기식으로 로드하고, 이미지가 로드된 후 완성된 이미지를 img 태그에 로드

        Decorator 모드

        데코레이터 모드의 정의: 프로그램이 실행 중일 때 객체 자체를 변경하지 않고 이 기간 동안 , 메소드는 객체에 동적으로 추가됩니다

        일반적으로 원래 메소드를 변경하지 않고 유지한 다음 기존 요구 사항을 충족하기 위해 원래 메소드에 다른 메소드를 마운트하는 데 사용됩니다. 🎜🎜typescript와 같은 데코레이터는 일반적인 데코레이터 패턴이며 vue🎜🎜🎜singleton 패턴🎜🎜🎜의 mixin은 클래스에 인스턴스가 하나만 있고 이에 액세스할 수 있는 전역 액세스 포인트를 제공합니다. 구현 방법은 먼저 인스턴스가 존재하는지 확인하고 존재하지 않으면 직접 생성하여 반환합니다. 이렇게 하면 클래스에 인스턴스 객체가 하나만 있는 것을 보장합니다🎜🎜예를 들어 ice stark의 경우 하위 애플리케이션은 한 번에 하나만 렌더링하도록 보장됩니다. 게시자로 간주될 수 있음), 관찰자 ​​모드는 특정 대상에 의해 예약되는 반면 게시/구독 모드는 일정 센터에 의해 균일하게 조정되므로 구독자와 관찰자 모드의 게시자 간에 종속성이 있습니다. /subscribe 모드는 그렇지 않습니다. 🎜🎜2. 두 패턴 모두 느슨한 결합, 향상된 코드 관리 및 잠재적인 재사용을 위해 사용될 수 있습니다. 🎜🎜3. 관찰자 모드에서는 관찰자는 주체를 알고, 주체는 관찰자의 기록을 유지합니다. 그러나 게시-구독 모델에서는 게시자와 구독자가 서로의 존재를 인식하지 못합니다. 그들은 메시지 브로커를 통해서만 통신합니다🎜🎜4. 관찰자 모드는 대부분 동기식입니다. 예를 들어 이벤트가 트리거되면 주제는 관찰자 메서드를 호출합니다. 게시-구독 패턴은 대부분 비동기식입니다(메시지 대기열 사용) 🎜

        Others

        정규 표현식

        정규 표현식은 어떤 데이터 유형인가요?

        는 객체입니다. let re = /ab+c/let re = new RegExp('ab+c')let re = /ab+c/等价于let re = new RegExp(&#39;ab+c&#39;)

        正则贪婪模式和非贪婪模式?

        量词

        *:0或多次; ?:0或1次; +:1到多次; {m}:出现m次; {m,}:出现至少m次; {m, n}:出现m到n次

        贪婪模式

        正则中,表示次数的量词默认是贪婪的,会尽可能匹配最大长度,比如a*会从第一个匹配到a的时候向后匹配尽可能多的a,直到没有a为止。

        非贪婪模式

        在量词后面加?就能变成非贪婪模式,非贪婪即找出长度最小且满足条件的

        贪婪& 非贪婪特点

        贪婪模式和非贪婪模式,都需要发生回溯才能完成相应的功能

        独占模式

        独占模式和贪婪模式很像,独占模式会尽可能多地去匹配,如果匹配失败就结束,不会进行回溯,这样的话就比较节省时间。

        写法:量词后面使用+

        优缺点:独占模式性能好,可以减少匹配的时间和 cpu 资源;但是某些情况下匹配不到,比如:


        正则文本结果
        贪婪模式a{1,3}abaaab匹配
        非贪婪模式a{1,3}?abaaab匹配
        独占模式a{1,3}+abaaab不匹配

        a{1,3}+ab 去匹配 aaab 字符串,a{1,3}+ 会把前面三个 a 都用掉,并且不会回溯

        常见正则匹配

        *: 0회 이상, ?: 0회 또는 1회 +: 1회 이상; {m}: m번 나타남; {m,}: 최소 m번 나타남; {m, n}: m번에서 n번 나타남 times
        操作符说明实例

        .表示任何单个字符


        [ ]字符集,对单个字符给出范围[abc]表示 a、b、c,[a-z]表示 a-z 的单个字符

        [^ ]非字符集,对单个字符给出排除范围[^abc]表示非a或b或c的单个字符

        _前一个字符零次或无限次扩展abc_表示 ab、abc、abcc、abccc 等

        ``左右表达式的任意一个`abcdef`表示 abc、def
        $匹配字符串结尾abc$表示 abc 且在一个字符串结尾

        ( )分组标记内部只能使用(abc)表示 abc,`(abcdef)`表示 abc、def
        D非数字


        d数字,等价于0-9


        S可见字符


        s空白字符(空格、换行、制表符等等)


        W非单词字符


        w单词字符,等价于[a-z0-9A-Z_]


        匹配字符串开头^abc表示 abc 且在一个字符串的开头

        {m,n}扩展前一个字符 m 到 n 次ab{1,2}c表示 abc、abbc

        {m}扩展前一个字符 m 次ab{2}c表示 abbc

        {m,}匹配前一个字符至少m 次


        前一个字符 0 次或 1 次扩展abc?regulargreedy 모드와 동일합니다. 그리고 비 욕심 모드?

        Quantifier
        🎜🎜그리디 모드🎜🎜🎜일반 규칙에서는 횟수를 나타내는 수량자는 기본적으로 탐욕적이며 최대 길이와 최대한 일치합니다. 예를 들어 a*는 역방향으로 일치합니다. 첫 번째 경기부터 a까지 a가 하나도 남지 않을 때까지 가능한 한 많은 a를 시도합니다. 🎜🎜🎜Non-greedy 모드🎜🎜🎜Non-greedy 모드가 되려면 수량자 뒤에 ?를 추가하세요. Non-greedy는 최소 길이를 찾아 조건을 충족한다는 의미입니다. 🎜🎜🎜Greedy & Non-greedy 특징🎜🎜 🎜그리디 모드와 비그리디 모드 모두 해당 기능을 완성하기 위해 🎜백트래킹🎜이 필요합니다. 🎜🎜🎜배타 모드🎜🎜🎜배타 모드는 그리디 모드와 매우 유사하며, 해당 기능이 충족되면 종료됩니다. 일치가 실패하면 역추적이 수행되지 않아 시간이 절약됩니다. 🎜🎜작성: 수량자 뒤에 +를 사용하세요🎜🎜장점과 단점: 단독 모드는 성능이 좋고 일치 시간과 CPU 리소스를 줄일 수 있지만 다음과 같은 경우에는 일치를 달성할 수 없습니다. < thead>🎜🎜욕심 모드🎜🎜a{1,3}ab🎜🎜aaab🎜🎜match🎜🎜🎜비 욕심 모드🎜🎜a{1,3}?ab🎜🎜aaab🎜🎜 match🎜🎜🎜독점 모드🎜🎜a{1,3}+ab🎜🎜aaab🎜🎜does not match🎜🎜🎜🎜🎜a{1,3}+ab는 aaab 문자열과 일치하고, a{1,3 }+는 이전 a 세 개를 모두 사용하며 역추적이 없습니다🎜🎜🎜일반적인 정규 매칭🎜🎜
        🎜일반텍스트결과
        🎜🎜.🎜🎜는 단일 문자를 나타냅니다 🎜 🎜🎜🎜🎜🎜🎜 🎜🎜🎜🎜🎜[ ]🎜🎜단일 문자에 대한 범위를 제공하는 문자 세트🎜🎜[abc]는 a, b, c, [a-z]를 나타냅니다. a-z🎜🎜의 단일 문자를 나타냅니다. 🎜🎜🎜🎜🎜🎜🎜[^ ]🎜🎜단일 문자에 대한 제외 범위를 제공하는 비문자 집합🎜🎜[^abc]을 나타냅니다. a, b, c가 아닌 단일 문자🎜 🎜🎜🎜🎜🎜🎜🎜🎜_🎜🎜이전 문자는 0번 또는 무한번 확장됩니다🎜🎜abc_는 ab, abc를 의미합니다 , abcc, abccc 등 🎜🎜🎜🎜🎜🎜🎜🎜 🎜`🎜🎜`🎜🎜왼쪽 및 오른쪽 표현 중 하나 🎜🎜`abc🎜🎜def`는 abc, def🎜🎜를 의미합니다. 🎜$🎜🎜문자열 끝과 일치🎜🎜abc$</ code>는 abc를 의미하고 문자열 끝에서는 🎜🎜🎜🎜🎜🎜🎜🎜<tr>🎜( )🎜🎜만 사용할 수 있습니다. 그룹화 태그 내 🎜🎜<code>(abc)는 abc를 의미하고 `(abc 🎜🎜def)`는 abc를 의미하며 def🎜🎜🎜🎜🎜🎜D🎜🎜non-number🎜🎜🎜🎜 🎜🎜🎜🎜🎜🎜🎜🎜d🎜🎜숫자, 0-9🎜에 해당 🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜S🎜🎜보이는 문자🎜 🎜🎜🎜🎜🎜🎜🎜🎜 🎜🎜🎜s🎜🎜공백 문자(공백, 줄 바꿈, 탭 등) 🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜W🎜🎜단어가 아닌 문자 🎜🎜🎜 🎜🎜🎜🎜 🎜🎜🎜🎜🎜일치 문자열의 시작🎜🎜^abc은 abc를 의미하며 문자열의 시작 부분에 있습니다 🎜🎜🎜🎜🎜🎜🎜🎜🎜{m,n}🎜🎜이전 문자 확장 m n번🎜🎜ab{1,2}c는 abc, abbc🎜🎜🎜 🎜🎜🎜🎜🎜🎜{m}🎜🎜이전 문자를 m번 확장합니다. 🎜🎜ab{2}c는 abbc🎜🎜🎜🎜🎜🎜🎜🎜🎜{m ,}🎜🎜이전 문자와 최소 m번 일치함을 의미합니다. 🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜< tr>🎜? 🎜🎜이전 문자는 0번 또는 1번 확장됩니다🎜🎜abc?는 ab, abc를 의미합니다🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜

        单元测试

        概念:前端自动化测试领域的, 用来验证独立的代码片段能否正常工作

        1、可以直接用 Node 中自带的 assert 模块做断言:如果当前程序的某种状态符合 assert 的期望此程序才能正常执行,否则直接退出应用。

        function multiple(a, b) {
            let result = 0;
            for (let i = 0; i < b; ++i)
                result += a;
            return result;
        }
        
        const assert = require(&#39;assert&#39;);
        assert.equal(multiple(1, 2), 3));
        로그인 후 복사

        2、常见单测工具:Jest,使用示例

        const sum = require(&#39;./sum&#39;);
        
        describe(&#39;sum function test&#39;, () => {
          it(&#39;sum(1, 2) === 3&#39;, () => {
            expect(sum(1, 2)).toBe(3);
          });
          
          // 这里 test 和 it 没有明显区别,it 是指: it should xxx, test 是指 test xxx
          test(&#39;sum(1, 2) === 3&#39;, () => {
            expect(sum(1, 2)).toBe(3);
          });
        })
        로그인 후 복사

        babel原理和用途

        babel 用途

        • 转义 esnext、typescript 到目标环境支持 js (高级语言到到低级语言叫编译,高级语言到高级语言叫转译)
        • 代码转换(taro)
        • 代码分析(模块分析、tree-shaking、linter 等)

        bebel 如何转换的?

        对源码字符串 parse 生成 AST,然后对 AST 进行增删改,然后输出目标代码字符串

        转换过程

        • parse 阶段:首先使用 @babel/parser将源码转换成 AST

        • transform 阶段:接着使用@babel/traverse遍历 AST,并调用 visitor 函数修改 AST,修改过程中通过@babel/types来创建、判断 AST 节点;使用@babel/template来批量创建 AST

        • generate 阶段:使用@babel/generate将 AST 打印为目标代码字符串,期间遇到代码错误位置时会用到@babel/code-frame

        3년간의 인터뷰 경험 공유: 프론트엔드 인터뷰의 4단계와 3가지 결정 요인

        好的,以上就是我对三年前端经验通过面试题做的一个总结了,祝大家早日找到心仪的工作~

        【推荐学习:web前端开发编程基础视频教程

        관련 라벨:
        원천:juejin.cn
        본 웹사이트의 성명
        본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
        인기 튜토리얼
        더>
        최신 다운로드
        더>
        웹 효과
        웹사이트 소스 코드
        웹사이트 자료
        프론트엔드 템플릿
        연산자설명 인스턴스🎜🎜
        w 🎜🎜단어 문자 등 가격은 [a-z0-9A-Z_]🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜🎜