function foo() {
console.log( a );
}
function bar() {
var a = 3;
foo();
}
var a = 2;
bar() //2
作用域的查找不是从函数执行的那行代码查找( foo() ), 而是从函数被定义的时候的那行代码去查找, 当foo被执行的时候, 它直接去全局找到了2
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 数据类型。
缺点:不能细分为谁谁的实例
因为在JavaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
这个bug是初版本的JavaScript中留下的,扩展一下其他五种标识位:
000 对象
1 整型
010 双精度类型
100字符串
110布尔类型
js引擎在执行代码之前,会在堆内存中创建一个全局对象GO
a.该对象所有作用域都可以访问
b.里面会包含Date、Array、String、Number、setTimeout、setInterval等等
c.其中还有一个window属性指向自己;
js引擎内部有一个执行上下文栈,他是执行代码的调用栈
执行全局的代码块,构建一个GEC全局执行上下文,会被放在调用栈中执行
GEC全局执行上下文包含两部分内容:
1.在执行代码之前,会将全局定义的变量、函数放到全局对象GO里,但不会赋值(这个过程也叫做变量的作用域提升)
2.在代码执行过程中,对变量进行赋值,或者执行其他的函数
在执行的过程中执行到一个函数时,就会根据函数体创建一个函数执行上下文(简称FEC),并且压入到调用栈中
FEC函数执行上下文包括三部分内容:
原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存。
大概就是当变量进入到某个环境中的时候就把这个变量标记一下,比如标记为“进入环境”,当离开的时候就把这个变量的标记给清除掉,比如是“离开环境”。而在这后面还有标记的变量将被视为准备删除的变量。
function test(){
var a= 10;//被标记,进入环境;
var b= 20;//被标记,进入环境;
}
test(); //执行完成,a,b被标记离开环境,被回收
引用计数(reference counting):当一个对象有一个引用指向它时,那么这个对象的引用就+1,当一个对象的引用为0时,这个对象就可以被毁掉;
缺点: 当两个对象循环引用的时候,引用计数无计可施。如果循环引用多次执行的话,会造成崩溃等问题。所以后来被标记清除法取代。
我的理解是:闭包就是能够读取其他函数内部变量的函数
总结: 一个普通的函数function,如果它可以访问外层作用于的自由变量,那么这个函数就是一个闭包;
优点:一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。延伸了变量的作用范围
1.避免命名冲突
2.解决循环绑定引发的索引问题
3.可以使用函数内部的变量,使变量不会被垃圾回收机制回收
缺点:值不能清除,会导致浏览器内存溢出,需要手动清除
应用:
**循环注册点击事件:**点击li输出当前li的索引号
1.如果用正常的for循环来写,function是异步函数,点击才会执行,for循环时同步任务,会立马执行,执行完再++
所以每个li的索引值都是所有li的长度
2.解决办法,创建立即执行函数()()
可以调用函数
可以改变this指向
只能接受数组形式的传参数
不会调用函数,但是可以改变函数内部的this指向
返回的是原函数改变this之后产生的新函数
这个链接存在于构造函数、实例、和原型对象之间,构成了原型链
promise的构造函数接收一个函数,并且传入两个参数:resolve,reject分别表示异步操作成功后的回调函数和失败后的回调函数
原型上有.then/.catch等方法
Promise.all:接收一个promise对象数组,待全部完成后,一起执行sucess,.then方法接受的datas是一个数组,依次包含多个promise的返回值
**Promise.race:**数组中只要有一个完成,就执行sucess
Es6:await/async
JavaScript的模块化,常用的就是CommonJS和ES6的模块化。
Node中对CommonJS进行了支持和实现,在node中每一个js文件都是一个单独的模块,CommonJS规范的核心变量:**exports、module.exports、require;**因此可以使用这些变量来很方便的进行模块化开发
模块化的核心就是导入导出,Node对其进行的实现
1.exports和module.exports可以负责对模块中的内容进行导出;
2.require函数可以帮助我们导入其他模块(自定义模块、系统模块、第三方库模块)中的内容;
module.exports = {}
exports = module.exports
//以在Node中真正用于导出的其实根本不是exports,而是module.exports;
exports.name = name
//为什么exports也可以导出呢?
//这是因为module对象的exports属性是exports对象的一个引用;
导入格式如下:require(X)
ES Module模块采用export和import关键字来实现模块化
采用ES Module将自动采用严格模式:use strict
exports关键字字将一个模块中的变量、函数、类等导出;
import关键字负责从另外一个模块中导入内容
export {sum as barSum} from './bar.js'
var:可以重复声明;无法限制修改;没有块级作用域
let:可以重复声明;变量可以修改;块级作用域
const:不能重复声明;常量不可修改;块级作用域,但是const定义的对象属性是可以改变的
因为对象是引用类型的,P中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。
forEach/filter/find/every/some/set
第一个用途:字符串拼接。将表达式嵌入字符串中进行拼接,用 `` 和${}
来界定。
includes` `repeat
// includes:判断是否包含然后直接返回布尔值
let str = 'hahah';
console.log(str.includes('y')); // false
// repeat: 获取字符串重复n次
let s = 'he';
console.log(s.repeat(3)); // 'hehehe'
Object.assign 拷贝的是对象的属性的引用,而不是对象本身。
1.JSON.parse(JSON.stringify())
这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。
这是因为 JSON.stringify()
方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数
2.写递归
递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。
满足下列条件之一就可触发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
对象,就是定义该函数时所在的作用域指向的对象,而不是使用时所在的作用域指向的对象。
* 删除不必要的代码和注释包括空格,尽量做到最小化文件。
* 可以利用 GZIP 压缩文件。
* 结合 HTTP 缓存文件。
**防抖:**debounce,去抖动。策略是当事件被触发时,设定一个周期延迟执行动作,若期间又被触发,则重新设定周期,直到周期结束,执行动作。
防抖的应用场景很多:
**节流:**固定周期内,只执行一次动作,若有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。
节流的应用场景:
同源策略指的是:协议,域名,端口相同,同源策略是一种安全协议,指一段脚本只能读取来自同一来源的窗口和文档的属性
视图(View):用户界面,是处理数据显示的部分,
控制器(Controller):业务逻辑,是处理用户交互部分
模型(Model):数据保存,主要负责在数据库中存取数据。
模式:
M:保存了每个页面中单独的数据
VM:相当于一个调用者,分割了M和V,每当V层想要获取保存后的数据时,都要由VM做中间处理
V:每个页面的html结构
同源:
浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。所以,当域名、协议、端口都相同时,视为属于同域。同域之间相互请求资源,就是同源。
跨域:
当协议,端口,域名中任何一个不相同的时候,都算做不同域。不同域之间相互请求资源,就是属于跨域。
JSONP
CORS “跨域资源共享”(Cross-origin resource sharing)
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
postMessage
Window.postMessage API的功能是允许程序员跨域在两个窗口/frames间发送数据信息。基本上,它就像跨域的ajax,但是它不是浏览器和服务器之间的交互,它是两个客户端之间的通信。
共同点:都是保存在浏览器端,且同源的。
不同点:
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 地址,
在发送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或某些临时的错误时;
回流必将引起重绘,重绘不一定会引起回流。
会导致回流的操作:
* 页面首次渲染
* 浏览器窗口大小发生改变
* 元素尺寸或位置发生改变元素内容变化(文字数量或图片大小等等)
* 元素字体大小变化
* 添加或者删除可见的 DOM 元素
* 激活 CSS 伪类(例如:hover)
* 查询某些属性或调用某些方法
* 一些常用且会导致回流的属性和方法
clientWidth、clientHeight、clientTop、clientLeftoffsetWidth、offsetHeight、offsetTop、offsetLeftscrollWidth、scrollHeight、scrollTop、scrollLeftscrollIntoView()、scrollIntoViewIfNeeded()、getComputedStyle()、
getBoundingClientRect()、scrollTo()
CSS
将页面中的img标签src指向一张小图片或者src为空,然后定义data-src(这个属性可以自定义命名,我才用data-src)属性指向真实的图片。src指向一张默认的图片,否则当src为空时也会向服务器发送一次请求。可以指向loading的地址。注意,图片要指定宽高。
<img src="default.jpg" data-src="666.jpg" />
当载入页面时,先把可视区域内的img标签的data-src属性值负给src,然后监听滚动事件,把用户即将看到的图片加载。这样便实现了懒加载。