事件捕获阶段、处于目标阶段、事件冒泡阶段
原理:事件委托的原理是事件冒泡。
优势:减少事件注册,大量降低内存消耗;对于新增子元素不需要重新绑定事件,对动态DOM尤其适用。
缺点:容易产生事件误判,即给不需要触发事件的元素绑定了事件
var oUl = document.getElementById('test');
oUl.addEventListener('click', function(e){
var ev = e || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName == 'LI'){
console.log(target.getAttribute('node-type'))
}
},true)
jQuery中事件绑定有四种方式:on、bind、live和delegate。
$("#clickme").on("click",function(){
console.log("clicked");
})
$("#clickme").bind("click",function(){
console.log("clicked");
});
$("#clickme").live("click",function(){
console.log("clicked");
})
$("#clickme").delegate("a","click",function(){
console.log("clicked");
})
$("#clickme").click(function(){
console.log("clicked");
})
$("#clickme").one('click',function(){
console.log("clicked");
})
类型不同
null表示一个空对象指针,类型为object;
undefined表示未被初始化的变量(声明的变量没有被赋值),类型为undefined。
转换为数值返回值不同
null 转换为数值类型结果为0;
undefined转化为数值型返回NaN。
二者不完全相等
null == undefined //true
null === undefined //false
原型链是针对构造函数的。
如我先创建了一个函数A,然后通过new A()创建了函数B,此时B就会继承A的属性和方法。示例如下,当我访问B函数的name属性时,发现B中并没有声明这个属性,那么就会向上查找,在A中发现了name属性并返回,这个向上查找的过程叫做原型链。
Object——>A()——>B()
function A(){
this.name = "Amy",
this.age = 1
}
var B = new A()
console.log(B.name);
作用域链是针对变量的。
当A函数中声明了B函数,访问B函数的某个变量未被找到,就会向A函数中查找,这个向上查找的过程叫做作用域链。作用域链是由内向外逐层产生的且不可逆,一直会找到全局作用域。
var a = 1;
function A(){
var a = 2;
function B(){
console.log(a);
}
c();
}
B(); //2
var num = 100;
var obj = {
num:200,
inner:{
num:300,
print:function(){
console.log(this.num);
}
}
}
obj.inner.print(); //300
var func=obj.inner.print;
func(); //100
(obj.inner.print)(); //300
(obj.inner.print=obj.inner.print())() //300
var num = 100;
function print(){
console.log(num);
var num;
}
print(); //undefined
函数作用域内num变量声明被提升,但是未被初始化所以返回undefined。
(function(num){
console.log(num);
var num = 10;
})(100) //100
函数被频繁的调用会对性能造成大的影响,函数节流即利用定时器控制函数不被频繁调用。
如window.onresize事件、mousemove事件
window.onresize = function throttle(){
var timer = null;
clear(timer);
timer = setTimeOut(function(){
console.log(123);
},100)
}
基础数据类型:null、undefined、number、boolean、string、symbol
引用数据类型:object、function
/**
* 返回变量的具体类型名称
* @param obj 待判断的变量
*/
function getType(obj){
var typeName = Object.prototype.toString.call(obj);
if( typeName == "[object Object]"){
return typeName = obj.constructor.name;
}else{
return typeName.slice(8,-1);
}
}
var A=function(name){
this.username=name;
}
A.prototype={
fun1:function(){},
fun2:function(){}
}
var B = new A();
对于const a = new Foo();,new干了以下事情
const o = new Object();//创建了一个新的空对象o
o.__proto__ = Foo.prototype;//让这个o对象的` __proto__`指向函数的原型`prototype`
Foo.call(o);//this指向o对象
a = o;//将o对象赋给a对象
1.instanceof 判断一个对象是否是由某个类型创建出来的
obj instanceof Array = true //则表示是数组
2.Object.prototype.toString()方法
Object.prototype.toString.call(arr) == [object Array]
3.Array.prototype.isPrototypeOf(obj) //判断指定对象是否存在于另一对象的原型链中
Array.prototype.isPrototypeOf(obj) == true
4.Obejct.getPrototypeOf(arr) == Array.prototype
Object.getPrototypeOf(arr)== Array.prototype //返回对象__proto__指向的原型prototype
5.最简单的方法(存在兼容)
Array.isArray(arr) == true
这个方法的思路是,使用 ES6 中的 Array.filter() 遍历数组,并结合 indexOf 来排除重复项
function distinct(arr) {
return arr.filter((item, index)=> {
return arr.indexOf(item) === index
})
}
最容易理解的方法,外层循环遍历元素,内层循环检查是否重复,当有重复值的时候,可以使用 push(),也可以使用 splice()
function distinct(arr) {
for (let i=0, len=arr.length; i
双重for循环的升级版,外层用 for…of 语句替换 for 循环,把内层循环改为 includes()。先创建一个空数组,当 includes() 返回 false 的时候,就将该元素 push 到空数组中。类似的,还可以用 indexOf() 来替代 includes()
function distinct(arr) {
let arr = a.concat(b)
let result = []
for (let i of arr) {
!result.includes(i) && result.push(i)
}
return result
}
首先使用 sort() 将数组进行排序,然后比较相邻元素是否相等,从而排除重复项。
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return;
}
arr = arr.sort()
var arrry= [arr[0]];
for (var i = 1; i < arr.length; i++) {
if (arr[i] !== arr[i-1]) {
arrry.push(arr[i]);
}
}
return arrry;
}
ES6 新增了 Set 这一数据结构,类似于数组,但 Set 的成员具有唯一性,基于这一特性,就非常适合用来做数组去重了
function distinct(arr) {
return Array.from(new Set([...arr]))
}
首先创建一个空对象,然后用 for 循环遍历,利用对象的属性不会重复这一特性,校验数组元素是否重复。
function distinct(arr) {
let result = []
let obj = {}
for (let i of arr) {
if (!obj[i]) {
result.push(i)
obj[i] = 1
}
}
return result
}
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) {
if (array .indexOf(arr[i]) === -1) {
array .push(arr[i])
}
}
return array;
}
var a = 10;
a.pro = 10;
console.log(a.pro + a); //NaN
var s = "hello";
s.pro = "world";
console.log(s.pro + s) //undefinedhello
var test = 1;
function test(index){
console.log(index);
index = 3;
}
test(2); //报错 类型错误,test不是一个函数
同步就是上一件事情没有完成,继续处理上一件事情,只有上一件事情完成了,才会做下一件事情。JS中大部分都是同步编程。
异步规划要做一件事情,但是不是当前立马去执行这件事情,需要等一定的时间,这样的话,我们不会等着他执行,而是继续执行下面的操作,只有当下面的事情都处理完成了,才会返回头处理之前的事情;如果下面的事情并没有处理完成,不管之前的事情有没有到时间,都需要等待”。
在JS中,异步编程只有四种情况:
进程代表CPU所能处理的单个任务。任一时刻,CPU只能处理一个进程。
一个进程可以包含多个线程
var syb = Symbol('obj');
var person = {
name :'tino',
say: function(){
console.log('hi');
},
ok: syb,
un: undefined
}
var copy = JSON.parse(JSON.stringify(person))
// copy
// {name: "tino"}
function deepCopy(obj) {
var result = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
if (typeof obj[key] === 'object' && obj[key]!==null) {
result[key] = deepCopy(obj[key]); //递归复制
} else {
result[key] = obj[key];
}
}
}
return result;
}
1、域名解析
域名解析的过程:
1).查询浏览器自身DNS缓存
2).若上面没有查找到,则搜索操作系统自身的dns缓存
3).若上面没有找到,则尝试读取hosts文件
4).若上面没有找到,向本地配置的首选DNS服务器发送请求
5).win系统 如果上面没有找到,操作系统查找NetBIOS name cache
6).win系统 如果上面没有找到,查询wins服务器
7).win系统 如果上面没有找到,广播查找
8).win系统 如果上面没有找到,读取LMHOSTS文件
若以上多没有找到,解析失败
2、 TCP三次握手
3、浏览器向服务器发送http请求
一旦建立了TCP连接,Web浏览器就会向Web服务器发送请求命令。
4、浏览器发送请求头信息
浏览器发送其请求命令之后,还要以头信息的形式向Web服务器发送一些别的信息,之后浏览器发送了一空白行来通知服务器,它已经结束了该头信息的发送。
5、服务器处理请求
服务器软件收到http请求,确定执行什么(ASP.net PHP RUBY JAVA等)来处理他。读取参数并进行逻辑操作后,生成指定的数据。
6、服务器做出应答
客户机向服务器发出请求后,服务器会客户机回送应答,HTTP/1.1 200 OK ,应答的第一部分是协议的版本号和应答状态吗
7、服务器发送应答头信息
正如客户端会随同请求发送关于自身的信息一样,服务器也会随同应答向用户发送关于它自己的数据及被请求的文档。
8、服务器发送数据
Web服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。
9、TCP连接关闭
一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码:
Connection:keep-alive
TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。
1、物 理 层(Physical Layer)
要传递信息就要利用一些物理媒体,如双纽线、同轴电缆等,但具体的物理媒体并不在OSI的7层之内,有人把物理媒体当作第0层,物理层的任务就是为它的上一层提供一个物理连接,以及它们的机械、电气、功能和过程特性。 如规定使用电缆和接头的类型,传送信号的电压等。在这一层,数据还没有被组织,仅作为原始的位流或电气电压处理,单位是比特。
2、 数 据 链 路 层(Data Link Layer)
数据链路层负责在两个相邻结点间的线路上,无差错的传送以帧为单位的数据。每一帧包括一定数量的数据和一些必要的控制信息。和物理层相似,数据链路层要负责建立、维持和释放数据链路的连接。在传送数据时,如果接收点检测到所传数据中有差错,就要通知发方重发这一帧。
3、 网 络 层(Network Layer)
在计算机网络中进行通信的两个计算机之间可能会经过很多个数据链路,也可能还要经过很多通信子网。网络层的任务就是选择合适的网间路由和交换结点, 确保数据及时传送。网络层将数据链路层提供的帧组成数据包,包中封装有网络层包头,其中含有逻辑地址信息- -源站点和目的站点地址的网络地址。
4、 传 输 层(Transport Layer)
该层的任务时根据通信子网的特性最佳的利用网络资源,并以可靠和经济的方式,为两个端系统(也就是源站和目的站)的会话层之间,提供建立、维护和取消传输连接的功能,负责可靠地传输数据。在这一层,信息的传送单位是报文。
5、 会 话 层(Session Layer)
这一层也可以称为会晤层或对话层,在会话层及以上的高层次中,数据传送的单位不再另外命名,统称为报文。会话层不参与具体的传输,它提供包括访问验证和会话管理在内的建立和维护应用之间通信的机制。如服务器验证用户登录便是由会话层完成的。
6、 表 示 层(Presentation Layer)
这一层主要解决拥护信息的语法表示问题。它将欲交换的数据从适合于某一用户的抽象语法,转换为适合于OSI系统内部使用的传送语法。即提供格式化的表示和转换数据服务。数据的压缩和解压缩, 加密和解密等工作都由表示层负责。
7、 应 用 层(Application Layer)
应用层确定进程之间通信的性质以满足用户需要以及提供网络与用户应用软件之间的接口服务。
上面我们简单的说明了7层体系的OSI参考模型,为了方便起见,我们常常把上面的7个层次分为低层与高层。低层为1-4层,是面向通信的,高层为5~7层,是面向信息处理的。
4层,自底向上依次为网络接口层、网络层、传输层和应用层。
TCP特点:面向连接、传输可靠(保证数据正确性,保证数据顺序)、用于传输大量数据(流模式)、速度慢,建立连接需要开销较多(时间,系统资源)。
主要为以下四点: