promise
sync - await
闭包
作用域 & 作用域链
作用域是定义变量的区域,它有一套访问变量的规则,这套规则来管理浏览器引擎如何在当前作用域以及嵌套的作用域中根据变量(标识符)进行变量查找。
作用域的多层嵌套中查找自由变量的过程是作用域链的访问机制。而层层嵌套的作用域,通过访问自由变量形成的关系叫做作用域链。
闭包定义
闭包是一个函数,闭包生成时,捕获附近的值。 汤姆大叔翻译的关于闭包的文章中的定义,ECMAScript中,闭包指的是:
1、从理论角度:所有的函数。因为它们都在创建的时候就将上层上下文的数据保存起来了。哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。
2、从实践角度:以下函数才算是闭包:
即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)
在代码中引用了自由变量 leetcide playground
this apply call bind
谈谈你对this、call、apply和bind的理解
在浏览器里,在全局范围内this 指向window对象;
在函数中,this指向它的执行上下文;
构造函数中,this指向new出来的那个新的对象;
call、apply、bind中的this被强绑定在指定的那个对象上;
箭头函数中this比较特殊,箭头函数this为父作用域的this,不是调用时的this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来;
apply、call、bind 原生API实现
原型与原型链
JavaScript 原型,原型链? 有什么特点?
深入理解原型链
可参考彻底理解原型链
所有的函数都以function Function()为构造函数,因此,所有函数(包括function Function()和function Object())的__proto__都指向Function.prototype这个对象,这个对象中定义了所有函数都共有的方法,比如call()、apply()等。
Object.prototype就是原型链的终点,函数也是对象了,它就是继承自对象的
BOM & DOM
Document Object Model(文档对象模型),就是把「文档」当做一个「对象」来看待。 相应的,Browser Object Model(浏览器对象模型),即把「浏览器」当做一个「对象」来看待。 Dom相当于把html页面结构解析成一个对象,提供一个接口API,让你去操作所有的节点。其实就是document对象。Bom基本上就是指当前窗口对象。
- document
- location
- screen
- navigator
事件
捕获阶段–事件从 window 开始,然后向下到每个元素,直到到达目标元素事件或event.target。 目标阶段–事件已达到目标元素。 冒泡阶段–事件从目标元素冒泡,然后上升到每个元素,直到到达 window。
正则
//(1)匹配 16 进制颜色值
var color = /#([0-9a-fA-F]{6}|[0-9a-fA-F]{3})/g;
//(2)匹配日期,如 yyyy-mm-dd 格式
var date = /^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/;
//(3)匹配 qq 号
var qq = /^[1-9][0-9]{4,10}$/g;
//(4)手机号码正则
var phone = /^1[34578]\d{9}$/g;
//(5)用户名正则
var username = /^[a-zA-Z\$][a-zA-Z0-9_\$]{4,16}$/;
//(6)Email正则
var email = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
//(7)身份证号(18位)正则
var cP = /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/;
//(8)URL正则
var urlP= /^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/;
// (9)ipv4地址正则
var ipP = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
// (10)//车牌号正则
var cPattern = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/;
// (11)强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):var pwd = /^(?=.\d)(?=.[a-z])(?=.[A-Z]).{8,10}$/
ajax
//1:创建Ajax对象
// XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。
var xhr = window.XMLHttpRequest?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');// 兼容IE6及以下版本
//2:配置 Ajax请求地址
xhr.open('get','index.xml',true);
//3:发送请求
xhr.send(null); // 严谨写法
//4:监听请求,接受响应
xhr.onreadysatechange=function(){
if(xhr.readySates==4&&xhr.status==200 || xhr.status==304 )
console.log(xhr.responsetXML)
}
立即执行
模块化编程
CommonJS、AMD、CMD、 ES6
深浅拷贝
可参考深浅拷贝
- 二者区别:如果其中一个对象改变了这个地址,就会影响到另一个对象。
Object.assign()
Array.prototype.slice()
{...a} // 对象解构
深拷贝
JSON.parse(JSON.stringify(object))
缺点:
* 会忽略undefined Symbol
* 不能序列化函数
* 不能解决循环引用的对象
* 不能正确处理 new Date()
* 不能处理正则
手写deepClone playground TODO async & await 节流和防抖
柯里化
一个currying的函数首先会接受一些参数,接受了这些参数之后,该函数并不会立即求值,而是继续返回另外一个函数
柯里化的简单实现
var currying = function (fn) {
var args = [];
//储存传到curring函数中的除了fn之外的其他参数,并储存到args函数中
args = [...arguments].slice(1);
return function () {
if (arguments.length === 0) {
return fn.apply(this, args);
} else {
//将fn中的参数展开,然后再储存到args数组中
[].push.apply(args, arguments);
}
}
};
commonjs 和 ES6 的区别
- 值拷贝和值引用
- 运行时加载,编译时输出
- 单个和多个
CSS解析器
- 从右到左 解析结果和DOM tree生成render Tree
浏览器缓存
- 强制缓存
- 协商缓存 ** expires ** Cache-Control
- 内缓存
- 磁盘缓存
浏览器如何渲染页面
-
解析HTML,创建DOM树
-
解析CSS
-
将CSS 和 DOM树合并,构建渲染树
-
重绘和重排 其中,重绘和重排
-
添加、删除、更新DOM节点
-
通过display: none隐藏一个DOM节点-触发重排和重绘
-
通过visibility: hidden隐藏一个DOM节点-只触发重绘,因为没有几何变化
-
移动或者给页面中的DOM节点添加动画
-
添加一个样式表,调整样式属性
-
用户行为,例如调整窗口大小,改变字号,或者滚动。
让我们来看一些例子:
var bstyle = document.body.style; // cache
bstyle.padding = "20px"; // 重排+重绘
bstyle.border = "10px solid red"; // 另一次重排+重绘
bstyle.color = "blue"; // 没有尺寸变化,只重绘
bstyle.backgroundColor = "#fad"; // 重绘
bstyle.fontSize = "2em"; // 重排+重绘
// 新的DOM节点 - 重排+重绘
document.body.appendChild(document.createTextNode('dude!'));
茴香豆有几种写法
arguments
function sideEffecting(arr) {
arr[0] = arr[2];
}
function bar(a, b, c) {
c = 10;
sideEffecting(arguments);
console.log(a + b + c); // 21
}
bar(1, 1, 1);
函数提前声明
function bar(){
return foo;
foo = 100;
var foo;
// function foo(){}
var foo = 11;
}
console.log(bar());
隐式类型转换
== 先调用toString ,再调用toValue
闭包-词法作用域
词法作用域简单的理解就是函数的上下文是在声明是确定的,而不是在调用时确定的。这里不想对这两个名词作过多的解释,我们知道js/ruby/python等主流的语言都是词法作用域就好,因为与之相对的动态作用域有许多的问题,所以现在的语言基本都是词法作用域的。
函数上下文就简单的理解为函数执行的环境好了,在这个环境中保存了函数执行所需的变量。 判断 this 指向,最简单的方法,就是看谁在调用那个方法; 词法作用域正好相反,在哪里定义就决定了它能访问的作用域 可参考闭包-词法作用域