前端js知识点梳理记录

词法作用域

function foo() {
        console.log( a ); 
    }

    function bar() {
        var a = 3;
        foo();
    }

    var a = 2;

    bar() //2

作用域的查找不是从函数执行的那行代码查找( foo() ), 而是从函数被定义的时候的那行代码去查找, 当foo被执行的时候, 它直接去全局找到了2

null 和 undefined的区别

null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义。

所以设置一个值为 null 是合理的,如
objA.valueA = null;
但设置一个值为 undefined 是不合理的,如
objA.valueA = undefined; // 应该直接使用 delete objA.valueA;

任何一个存在引用的变量值为undefined都是一件错误的事情。

这样判断一个值是否存在,就可以用
objA.valueA === undefined // 不应使用 null 因为 undefined == null,而 null 表示该值定义为空值

基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象。

数据类型的判断方式

答:
1.typeof

缺点:typeof null的值为Object,无法分辨是null还是Object
2.instanceof

缺点:只能判断某对象是否存在于目标对象得的原型链上
3.constructor
4.Object.prototype.toString.call()

一种最好的基本类型检测方式 Object.prototype.toString.call() ;它可以区分 null 、 string 、

boolean 、 number 、 undefined 、 array 、 function 、 object 、 date 、 math 数据类型。

缺点:不能细分为谁谁的实例

为什么typeof null 是Object?

因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object

这个bug是初版本的JavaScript中留下的,扩展一下其他五种标识位:

000 对象

1 整型

010 双精度类型

100字符串

110布尔类型

什么是作用域,什么是作用域链?

  • 规定变量和函数的可使用范围称作作用域
  • 每个函数都有一个作用域链,查找变量或者函数时,需要从局部作用域到全局作用域依次查找,这些作用域的集合称作作用域链

js执行过程:

1.初始化全局对象:

  • js引擎在执行代码之前,会在堆内存中创建一个全局对象GO

    a.该对象所有作用域都可以访问

    b.里面会包含Date、Array、String、Number、setTimeout、setInterval等等

    c.其中还有一个window属性指向自己;

2.执行上下文栈ECS(调用栈)

js引擎内部有一个执行上下文栈,他是执行代码的调用栈

  • 执行全局的代码块,构建一个GEC全局执行上下文,会被放在调用栈中执行

  • GEC全局执行上下文包含两部分内容:

    1.在执行代码之前,会将全局定义的变量、函数放到全局对象GO里,但不会赋值(这个过程也叫做变量的作用域提升)

    2.在代码执行过程中,对变量进行赋值,或者执行其他的函数

3.如果遇到函数

  • 在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(简称FEC),并且压入到调用栈中

  • FEC函数执行上下文包括三部分内容:

    1. 在解析函数时,会创建一个(AO)AO中包含形参、arguments、函数定义和指向函数对象、定义的变量;
    2. 作用域链:由VO(在函数中就是AO对象)和父级VO组成,查找时会一层层查找
    3. :this绑定的值
    • 执行阶段:变量赋值、函数表达式赋值,使变量对象编程活跃对象

执行栈:

  • 首先栈特点:先进后出
  • 当进入一个执行环境,就会创建出它的执行上下文,然后进行压栈,当程序执行完成时,它的执行上下文就会被销毁,进行弹栈。
  • 栈底永远是全局环境的执行上下文,栈顶永远是正在执行函数的执行上下文
  • 只有浏览器关闭的时候全局执行上下文才会弹出

js垃圾回收两种

原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。

  • 标记清理这个法是设置一个根对象(root object),垃圾回收器会定期从这个根开始,找所有从根开始有引用到的对象,对于哪些没有引用到的对象,就认为是不可用的对象;

大概就是当变量进入到某个环境中的时候就把这个变量标记一下,比如标记为“进入环境”,当离开的时候就把这个变量的标记给清除掉,比如是“离开环境”。而在这后面还有标记的变量将被视为准备删除的变量。

function test(){
  var a= 10;//被标记,进入环境;
  var b= 20;//被标记,进入环境;
}
test(); //执行完成,a,b被标记离开环境,被回收
  • 引用计数(reference counting):当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被毁掉;

  • 缺点: 当两个对象循环引用的时候,引用计数无计可施。如果循环引用多次执行的话,会造成崩溃等问题。所以后来被标记清除法取代。

闭 包

我的理解是:闭包就是能够读取其他函数内部变量的函数

总结: 一个普通的函数function,如果它可以访问外层作用于的自由变量,那么这个函数就是一个闭包;

优点:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。延伸了变量的作用范围

​ 1.避免命名冲突

​ 2.解决循环绑定引发的索引问题

​ 3.可以使用函数内部的变量,使变量不会被垃圾回收机制回收

缺点:值不能清除,会导致浏览器内存溢出,需要手动清除

应用:

  • 设计模式中的单例模式
  • for循环中的保留i的操作
  • 防抖和节流
  • 函数柯里化

**循环注册点击事件:**点击li输出当前li的索引号

1.如果用正常的for循环来写,function是异步函数,点击才会执行,for循环时同步任务,会立马执行,执行完再++

所以每个li的索引值都是所有li的长度

2.解决办法,创建立即执行函数()()

this指向

  1. 普通函数:指向window
  2. 对象里的方法:指向对象
  3. 构造函数:指向创建出来的实例
  4. 箭头函数:指函数定义位置的上下文this
  5. 绑定事件:btn.onclick = function(){} 指向btn,函数的调用者
  6. 定时器:window
  7. 立即执行函数:windoow

call,apply,bind

  • call:
    • 可以调用函数
    • 可以改变this指向
    • call可以实现继承
  • apply:

​ 可以调用函数

​ 可以改变this指向

​ 只能接受数组形式的传参数

  • bind:

​ 不会调用函数,但是可以改变函数内部的this指向

​ 返回的是原函数改变this之后产生的新函数

讲一下原型链

  1. 只要创建一个函数,就会为其创建一个protoype属性,这个属性指向该函数的原型对象
  2. 所有原型对象都会自动获得一个constructor属性,这个属性指向prototype所在函数的指针
  3. 创建一个自定义的构造函数后,其原型对象默认只会取得constructor属性,其他方法都是从Object上继承来的
  4. 当调用构造函数创造一个新实例后
  5. 该实例内部包含一个指针 proto 指向该构造函数的原型对象

这个链接存在于构造函数、实例、和原型对象之间,构成了原型链

promise的一些用法 异步编程的一种方案

promise的构造函数接收一个函数,并且传入两个参数:resolve,reject分别表示异步操作成功后的回调函数和失败后的回调函数

原型上有.then/.catch等方法

Promise.all:接收一个promise对象数组,待全部完成后,一起执行sucess,.then方法接受的datas是一个数组,依次包含多个promise的返回值

**Promise.race:**数组中只要有一个完成,就执行sucess

Es6:await/async

模块化:

JavaScript的模块化,常用的就是CommonJS和ES6的模块化。

1.commonJS

Node中对CommonJS进行了支持和实现,在node中每一个js文件都是一个单独的模块,CommonJS规范的核心变量:**exports、module.exports、require;**因此可以使用这些变量来很方便的进行模块化开发

模块化的核心就是导入导出,Node对其进行的实现

​ 1.exports和module.exports可以负责对模块中的内容进行导出;

​ 2.require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容;

  • exports导出

module.exports = {}
exports = module.exports

//以在Node中真正用于导出的其实根本不是exports,而是module.exports;
exports.name = name
//为什么exports也可以导出呢?
//这是因为module对象的exports属性是exports对象的一个引用;

  • require导入

​ 导入格式如下:require(X)

  • commonJs的缺点:

  1. CommonJS加载模块是同步的,只有等到对应的模块加载完毕,当前模块中的内容才能被运行;那么对于浏览器来说,浏览器加载js文件需要先从服务器将文件下载下来,之后再加载运行;采用同步的就意味着后续的js代码都无法正常运行,即使是一些简单的DOM操作;
  2. **所以在浏览器中,我们通常不使用CommonJS规范:**当然在webpack中使用CommonJS是另外一回事;因为它会将我们的代码转成浏览器可以直接执行的代码;

2.ES Module

ES Module模块采用export和import关键字来实现模块化

采用ES Module将自动采用严格模式:use strict

  • exports关键字

​ exports关键字字将一个模块中的变量、函数、类等导出;

  • import关键字

​ import关键字负责从另外一个模块中导入内容

  • export和import结合使用

export {sum as barSum} from './bar.js'

es6常用的方法

  • 变量

var:可以重复声明;无法限制修改;没有块级作用域

let:可以重复声明;变量可以修改;块级作用域

const:不能重复声明;常量不可修改;块级作用域,但是const定义的对象属性是可以改变的

因为对象是引用类型的,P中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。

  • 数组方法

forEach/filter/find/every/some/set

  • import导入模块、export导出模块

  • class、extends、super

  • 箭头函数 :指函数定义位置的上下文this

  • Object.assign();

  • template string (模板字符串)

第一个用途:字符串拼接。将表达式嵌入字符串中进行拼接,用 `` 和${}来界定。

includes` `repeat
// includes:判断是否包含然后直接返回布尔值
let str = 'hahah';
console.log(str.includes('y')); // false

// repeat: 获取字符串重复n次
let s = 'he';
console.log(s.repeat(3)); // 'hehehe'

数组去重

  • set方法 […new Set(arr)]

  • forEach和indexOf方法

  • includes方法

深浅拷贝

  • 浅拷贝

Object.assign 拷贝的是对象的属性的引用,而不是对象本身。

  • 深拷贝

1.JSON.parse(JSON.stringify())

这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。

这是因为 JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数

2.写递归

递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。

不同的浏览器分辨率适配

  • em 单位是参照元素自身文字大小来设置尺寸,例如一个 p 标签的 font-size是 20px,1em就等于20px,这时如果想设置两个字的缩进,就可以设置text-indent为2em;
  • rem 是参照根节点 html 标签的文字大小来设置尺寸,其它元素相关尺寸都用 rem,所有元素就都有了统一参照标准,改变 html 文字大小,就会改变所有用 rem 单位设置的尺寸。

media方式

BFC(块级格式化上下文)

  • 触发条件或者说哪些元素会生成BFC:

    满足下列条件之一就可触发BFC

    【1】根元素

    【2】float的值不为none

    【3】overflow的值不为visible(hidden、auto、scroll)

    【4】display的值为inline-block、table-cell、table-caption、flex

    【5】position的值为absolute或fixed

通过改变高度塌陷的父盒子的属性值,使其成为BFC,以此来包含子浮动盒子。margin问题

常见的布局形式

定位布局,浮动布局,响应式布局 使用媒体查询(CSS3 Media Queries),,流式布局将屏幕分成12列来实现响应式的,flex布局

盒子模型

box-sizing:1.content-box:w3c盒子模型:总宽度= width+margin+padding+border

​ 2.border-box:ie盒子模型: 总宽度 = width+margin (width中包括:padding+border)

箭头函数this指向

箭头函数体内的this对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。

前端优化

  • 优化 DOM

* 删除不必要的代码和注释包括空格,尽量做到最小化文件。
* 可以利用 GZIP 压缩文件。
* 结合 HTTP 缓存文件。

防抖和节流

  • **防抖:**debounce,去抖动。策略是当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。

    防抖的应用场景很多:

    • 输入框中频繁的输入内容,搜索或者提交信息;
    • 频繁的点击按钮,触发某个事件;
    • 监听浏览器滚动事件,完成某些特定操作;
    • 用户缩放浏览器的resize事件;
  • **节流:**固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。

    节流的应用场景:

    • 监听页面的滚动事件;
    • 鼠标移动事件;
    • 用户频繁点击按钮操作;
    • 游戏中的一些设计;

同源策略

同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性

MVC和MVVM

  • MVC

    视图(View):用户界面,是处理数据显示的部分,

    控制器(Controller):业务逻辑,是处理用户交互部分

    模型(Model):数据保存,主要负责在数据库中存取数据。

    模式:

    1. View 传送指令到 Controller
    2. Controller 完成业务逻辑后,要求 Model 改变状态
    3. Model 将新的数据发送到 View,用户得到反馈
  • MVVM

    M:保存了每个页面中单独的数据

    VM:相当于一个调用者,分割了M和V,每当V层想要获取保存后的数据时,都要由VM做中间处理

    V:每个页面的html结构

关于跨域的三种方法JSONP、CORS、postMessage

同源:

浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。所以,当域名、协议、端口都相同时,视为属于同域。同域之间相互请求资源,就是同源。

跨域:

当协议,端口,域名中任何一个不相同的时候,都算做不同域。不同域之间相互请求资源,就是属于跨域。

JSONP

  • 首先,先向后台通过函数传送一个参数,例如:
  • 然后,后台接收到这个参数之后,解析函数并将数据包裹在函数中,发送给前端。json({“a”:“12”,“b”:“45”,“c”:“56”}).
  • 前端将返回的数据当做js代码来执行。用户只用定义好函数,就可以在函数内部使用参数。

CORS “跨域资源共享”(Cross-origin resource sharing)

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

postMessage

Window.postMessage API的功能是允许程序员跨域在两个窗口/frames间发送数据信息。基本上,它就像跨域的ajax,但是它不是浏览器和服务器之间的交互,它是两个客户端之间的通信。

nginx代理跨域
  • nginx模拟一个虚拟服务器,因为服务器与服务器之间是不存在跨域的,
  • 发送数据时 ,客户端->nginx->服务端
  • 返回数据时,服务端->nginx->客户端

请描述一下 cookies,sessionStorage 和 localStorage 的区别

  • 共同点:都是保存在浏览器端,且同源的。

  • 不同点:

    1.cookie 数据始终在同源的 http 请求中携带(即使不需要),即 cookie 在浏览器和服务器间来回传递。

    ​ 而 sessionStorage 和 localStorage 不会自动把数据发给服务器,仅在本地保存。

    2.cookie 数据还有路径(path)的概念,可以限制 cookie 只属于某个路径下。

    3.存储大小限制也不同,cookie 数据不能超过 4k,同时因为每次 http 请求都会携带 cookie,所以 cookie 只适合保存很小的数据,如会话标识。

    ​ sessionStorage 和 localStorage 虽然也有存储大小的限制,但比 cookie 大得多,可以达到 5M 或更大。

    4.数据有效期不同,sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;

    ​ localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;

    ​ cookie 只在设置的 cookie 过期时间之前一直有效,即使窗口或浏览器关闭。

    5.作用域不同,sessionStorage 在不同的浏览器窗口中不共享,即使是同一个页面;

    ​ cookie 和 localStorage 在所有同源窗口中都是共享的。

从敲入 URL 到渲染完成的整个过程,包括 DOM 构建的过程,说的约详细越好

  • 用户输入 url 地址,

  • 在发送http请求前,解析域名寻找 IP 地址

  • 浏览器向服务器发送 http 请求,建立tcp链接,建立三次握手,

  • 如果服务器段返回以 301 之类的重定向,浏览器根据相应头中的 location 再次发送请求

  • 服务器端接受请求,处理请求生成 html 代码,返回给浏览器,这时的 html 页面代码可能是经过压缩的

  • 浏览器接收服务器响应结果,如果有压缩则首先进行解压处理,紧接着就是页面解析渲染

  • 解析渲染该过程主要分为以下步骤:解析 HTML、构建 DOM 树、DOM 树与 CSS 样式进行附着构造呈现树

  • 布局

  • 绘制 前端给用户进行展示

  • 最后浏览器TCP的连接既四次挥手,完成整个过程

四次握手

TCP握手协议 :在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。

1、第一次握手:建立连接时,客户端发送syn链接请求报文包(syn=j)到服务器,并进入SYN_SEND状态,等待服务器确认; SYN:同步序列编号(Synchronize Sequence Numbers)

2、第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK确认保文包,此时服务器进入SYN_RECV状态;

3、第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。

完成三次握手,客户端与服务器开始传送数据。

所谓的三次握手(three times handshake;three-way handshaking)即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。

为了提供可靠的传送,TCP在发送新的数据之前,以特定的顺序将数据包的序号,并需要这些包传送给目标机之后的确认消息。TCP总是用来发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。

【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

答:因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉Client端,“你发的FIN报文我收到了”。只有等到我Server端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四步握手。

常见状态码

**200 OK:**表示从客户端发送给服务器的请求被正常处理并返回;

**301 Moved Permanently:**永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;

**302 Found:**临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL

**400 Bad Request:**表示请求报文中存在语法错误;

**404 Not Found:**表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;

**500 Inter Server Error:**表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;

重绘/回流

回流必将引起重绘,重绘不一定会引起回流。

  • 重绘:当页面中元素样式的改变并不影响它在文档流中的位置时(例如:color、background-color、visibility 等),浏览器会将新样式赋予给元素并重新绘制它,这个过程称为重绘。
  • 回流:当 Render Tree 中部分或全部元素的尺寸、结构、或某些属性发生改变时,浏览器重新渲染部分或全部文档的过程称为回流。

会导致回流的操作:

* 页面首次渲染
* 浏览器窗口大小发生改变
* 元素尺寸或位置发生改变元素内容变化(文字数量或图片大小等等)
* 元素字体大小变化
* 添加或者删除可见的 DOM 元素
* 激活 CSS 伪类(例如:hover)
* 查询某些属性或调用某些方法
* 一些常用且会导致回流的属性和方法
clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftscrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、
getBoundingClientRect()、scrollTo()

如何避免:

CSS

  • 避免使用 table 布局。
  • 尽可能在 DOM 树的最末端改变 class。
  • 避免设置多层内联样式。
  • 将动画效果应用到 position 属性为 absolute 或 fixed 的元素上。
  • 避免使用 CSS 表达式(例如:calc())

图片懒加载

原理

将页面中的img标签src指向一张小图片或者src为空,然后定义data-src(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src指向一张默认的图片,否则当src为空时也会向服务器发送一次请求。可以指向loading的地址。注意,图片要指定宽高。

<img src="default.jpg" data-src="666.jpg" />

当载入页面时,先把可视区域内的img标签的data-src属性值负给src,然后监听滚动事件,把用户即将看到的图片加载。这样便实现了懒加载。

for-in/for-of的区别

map和forEach的区别

你可能感兴趣的:(前端,javascript,es6)