js知识碎片整合

1、let、const、var的区别

  1. var定义的变量,没有块的概念,可以跨块访问, 不能跨函数访问。
  2. let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
  3. const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改
    作用域:
    全局作用域、函数作用域、块作用域( { } ,if语句和 for语句里面的{ })
{
	var a=1;let b=2;const c=3;
}
console.log(a)  //1
console.log(b)  //ReferenceError: b is not defined
console.log(c)  //ReferenceError: c is not defined
const obj={name:'obj'}
obj.name='change'
console.log(obj)  //{name:'change'}

上面定义不是说const定义的变量不能修改吗,为什么上面的代码却实现了呢?
因为对象是引用类型的,obj中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。

obj={name:'otherObj'};  //修改指针,指向另一个对象
console.log(obj) //Identifier 'obj' has already been declared

2、箭头函数

ES6标准新增了一种新的函数:Arrow Function(箭头函数)。
为什么叫Arrow Function?因为它的定义用的就是一个箭头:

()=>console.log('arrow function')
//相当于
function (){
	console.log('arrow function')
}
//返回对象时需要用小括号包起来,因为大括号被占用解释为代码块了
()=>{
	return ({name:'value'})	
}

箭头函数有两种格式

  • 只包含一个表达式,这时花括号和return都省略了。
  • 包含多条语句,这时花括号和return都不能省略。

this
箭头函数看上去是匿名函数的一种简写,但实际上,箭头函数和匿名函数有个明显的区别:箭头函数内部的this是词法作用域,由上下文确定。

var obj={
	value:'obj',
	getValue: function () {
        var v = this.value; // obj
        var func = function () {
            return this.value; // this指向window,返回undefined
        };
        return func();
    }
}
//使用箭头函数
var obj={
	value:'obj',
	getValue: function () {
        var v = this.value; // obj
        var func = ()=>{
            return this.value; // this指向obj,返回obj
        };
        return func();
    }
}

this总是指向词法作用域,也就是外层调用者obj;也就是用了箭头函数之后,this固定,不在改变,所以,用call()或者apply()调用箭头函数时,无法对this进行绑定,即传入的第一个参数被忽略。

var obj={
	value:'obj',
	getValue: function () {
        var v = this.value; // obj
        var func = ()=>{
            return this.value; 
        };
        return func.call({value:'unchange'});  //返回 obj
 //不能通过call方法,将func中this的对象指向{value:'unchange'},
    }
}

同样,箭头函数不能用new,也不能使用arguments

var Person = (name) => {
    this.name = name
}
var p = new Person('小明')  //Person is not a constructor

var func = () => {
    console.log(arguments)
}
func('hi')   //arguments is not defined

3、Promise.then的第二个参数与catch的区别

promise.then的第二个参数以及catch都是用来捕获处理异常:

new Promise((resolve,reject)=>{
	reject('wrong')
}).then((data)=>{
	console.log('执行成功')
},(error)=>{
	console.log(error)     //wrong
})
//catch
new Promise((resolve,reject)=>{
	reject('wrong')
}).then((data)=>{
	console.log('执行成功')
}).catch((error)=>{
	console.log(error)     //wrong
})

当Promise的状态为resolve或者reject之后再抛出错误是不能够捕获到的。因为 Promise 的状态一旦改变,就永久保持该状态,不会再变了。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch语句捕获。
在promise的链式调用中,then的第二个参数就处理不了了,就得用catch。

function taskA() { 
    console.log("Task A");
    throw new Error('test')
}
function taskB() {
    console.log("Task B");
}
function onRejected(error) {
    console.log("Catch Error: ", error);
}
Promise.resolve()
.then(taskA,()=>onRejected)
.then(taskB,()=>onRejected)  //Task A  没有捕获到异常,但是也不会输入Task B
//Promise 内部有未捕获的错误,会直接终止进程
Promise.resolve()
.then(taskA)
.then(taskB)
.catch(onRejected) //Task 同时输出异常

4、promise.all应用场景

如果不理解什么是promise.all,可查看我之前的js Promise详解

因为promise.all返回的结果是一个数组(里面包含了多个promise实例reslove的结果),因此主要应用在处理多个并行的异步操作。

5、Promiseasync/await的区别

  1. 与Promise对比简洁干净
    与Promise需要使用then()函数来处理Promise返回的结果,而async/await则直接在代码按顺序上处理结果。
  2. Promise 中不能自定义使用 try/catch 进行错误捕获,但是在 Async/await 中可以像处理同步代码处理错误
  3. async/await使得嵌套将会变得简单

6、Ajax的原理

(1)创建对象
var xhr = new XMLHttpRequest();   //主流浏览器
var xhr = new ActiveXObject('Microsoft.XMLHTTP')  //IE5,IE6
(2)打开请求
xhr.open('GET', 'example.txt', true);
(3)发送请求
xhr.send(); 发送请求到服务器
(4)接收响应
xhr.onreadystatechange =function(){}
(1)当readystate值从一个值变为另一个值时,都会触发readystatechange事件。
(2)当readystate==4时,表示已经接收到全部响应数据。
(3)当status ==200时,表示服务器成功返回页面和数据。
(4)如果(2)(3)内容同时满足,则可以通过xhr.responseText,获得服务器返回的内容。

在AJAX实际运行当中,对于访问XMLHttpRequest(XHR)时并不是一次完成的,而是分别经历了多种状态后取得的结果,对于这种状态在AJAX中共有5种,分别是。
0 - (未初始化)还没有调用send()方法
1 - (载入)已调用send()方法,正在发送请求
2 - (载入完成)send()方法执行完成,
3 - (交互)正在解析响应内容
4 - (完成)响应内容解析完成,可以在客户端调用了
对于上面的状态,其中“0”状态是在定义后自动具有的状态值,而对于成功访问的状态(得到信息)我们大多数采用“4”进行判断。

7、深拷贝

最简单的方式:

JSON.parse(JSON.stringify(obj))
var a=[1,2,3]
var b=JSON.parse(JSON.stringify(a))
console.log(b)

复杂方式:
思想:将object对象赋值给对象,对象中保存的其实的该object对象的指针,不是object对象,在对对象的值进行更改时,更改的是指针对象object的值,所有引用该指针的对象的值都会改变。因此想出在复制对象时将对象中的所有值进行判断之后才进行复制。

function deepClone (obj) {  
    if(typeof obj !== "object" && typeof obj !== 'function'){
        return obj;
    }
    var o = Array.isArray(obj) ? [] : {}; 
    for(i in obj) {  
        if(obj.hasOwnProperty(i)){ 
            o[i] = typeof obj[i] === "object" ? deepClone(obj[i]) : obj[i];
        } 
    } 
    return o;
}

8、图片懒加载

实现懒加载的关键就是,在图片没有进入可视区域时,先不给的src赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给src赋值。可减少页面首次加载时间过长,减少服务器的并发数。

懒加载的实现

window.onload=()=>{  //方法用于在网页加载完毕后立刻执行的操作,即当 HTML 文档加载完毕后,立刻执行某个方法
  var imgs=document.querySelectorAll('img')
  var n=0;
  lazyLoad()
  function getTop(e){   //获取元素顶部到页面顶部的距离
    return e.offsetTop
  }
  function lazyLoad(){
    var scrollTop=document.documentElement.scrollTop||document.body.scrollTop  //滚动条距离顶部高度
    var clientHeight=document.documentElement.clientHeight        //可视区高度
    for(let i=n;i<imgs.length;i++){
      if(getTop(imgs[i])<(scrollTop+clientHeight)){
        if(imgs[i].getAttribute("src")=='./img/default.png'){
          imgs[i].src = imgs[i].getAttribute("data-src")
        }
        n=i+1
      }
    }
  }
  window.onscroll=()=>{
    debounce(lazyLoad,3000)  //停止scroll3s后才能再次调用lazyload函数
  }
}
let timeout=null
const debounce=(cb,wait)=>{       //防抖,
if(timeout!==null) clearTimeout(timeout)  
  timeout=setTimeout(()=>{
    timeout=null
    cb&&cb()  
  },wait)
}

9、防抖

防抖(debounce):当持续触发事件时,一定时间段内没有再触发事件,事件处理函数才会执行一次,如果设定的时间到来之前,又一次触发了事件,就重新开始延时。

let timeout=null
const debounce=(fn,wait)=>{       //防抖,
if(timeout!==null) clearTimeout(timeout)  
  timeout=setTimeout(()=>{
    timeout=null
    fn&&fn()  
  },wait)
}
window.addEventListener('scroll', debounce(sayHi, 300))
function sayHi(){
  console.log('hi')
} 

10、节流

当持续触发事件时,保证一定时间段内只调用一次事件处理函数。类似控制阀门一样定期开放的函数,也就是让函数执行一次后,在某个时间段内暂时失效,过了这段时间后再重新激活。

let throttle=(fn,delay)=>{
  let exec=true   
  return function(){
    if(!exec){
      return false
    }
    exec=false
    setTimeout(()=>{
      fn()
      exec=true
    },delay)
  }
}
 window.addEventListener('scroll', throttle(sayHi, 3000));
 function sayHi(){
  console.log('hi')
} 

11、js实现bind机制

function _bind(fn,context){
  return function(){
    return fn.apply(context,arguments)
  }
}
_bind(a,b)

Function.prototype._bind=function(context,...res){
  let self=this
  return function(...arg){
    return self.apply(context,[...res,...arg])
  }
}
a._bind(b)

12、apply、call、bind的区别

相同点: apply、call、bind都是用来修改this的指向。
不同点:
1、apply、call的返回值取决于目标函数的返回值,是立即调用的,而bind的返回值则是原函数的拷贝,供以后调用。
2、apply接收两个参数,函数运行的作用域(this),另一个是参数数组。call不一定接受两个参数,第一个参数也是函数运行的作用域(this),但是传递给函数的参数必须列举出来。
3、bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值。

13、手写一个Cookie
Cookie中保存的信息都是文本信息,在客户端和服务器端交互过程中,cookie信息被附加在HTTP消息头中传递,cookie的信息由键/值对组成。

function setCookie(name,value,expireDay){
  var exp=new Date()
  exp.setTime(exp.getTime()+24*60*60*1000*expireDay)
  document.cookie=name+'='+value+';expires='+exp;
}
function getCookie(name){
	var arr,reg=new RegExp("(^| )"+name+"=([^;]*)(;|$)");
	if(arr=document.cookie.match(reg))
		return arr[2];
	else
		return null;
}
function delCookie(name){
	var exp = new Date();
	exp.setTime(exp.getTime() - 1);
	var cookieValue=getCookie(name);
	if(cookieValue!=null)
		document.cookie= name + "="+cookieValue+";expires="+exp;
}

14、cookie、session的区别

cookie和session都是用来跟踪浏览器用户身份的会话方式。
区别:
1、cookie保存在浏览器端,session保存在服务器端。
2、单个cookie保存的数据不能超过4kb;session大小没有限制
3、cookie不是很安全,别人可以分析存放在本地的Cookie并进行Cookie欺骗,考虑到安全应当使用session。
4、cookie只能保存字符串类型,以文本的方式;session通过类似与Hashtable的数据结构来保存,能支持任何类型的对象(session中可含有多个对象)

15、cookie、sessionStorage、localStorage区别

相同点:都存储在客户端
不同点:

  1. 存储大小
    · cookie数据大小不能超过4k。
    · sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
  2. 有效时间
    · localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;
    · sessionStorage 数据在当前浏览器窗口关闭后自动删除。
    · cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  3. 数据与服务器之间的交互方式
    · cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端
    · sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。

16、token

传统身份验证:
由于HTTP是一种没有状态的协议,它并不知道是谁访问了我们的应用。一般采用在服务端存储为登录的用户生成的 Session ,这些 Session 可能会存储在内存,磁盘,或者数据库里。我们可能需要在服务端定期的去清理过期的 Session 。

使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。
Token 是在服务端产生的,如果前端使用用户名/密码向服务端请求认证,服务端认证成功,那么在服务端会返回 Token 给前端。前端可以在每次请求的时候带上 Token 证明自己的合法地位
token具有以下优点:
1、token 完全由应用管理,所以它可以避开同源策略
2、token 可以避免 CSRF 攻击
3、token 可以是无状态的,可以在多个服务间共享

17、typeof的返回值

string,boolean,number,undefined,function,object

18、事件委托

利用事件冒泡的原理,让最具体的子元素的所触发的事件,冒泡到他最不具体(最外边)的元素代替执行

19、阻止事件冒泡

ie:阻止冒泡ev.cancelBubble = true;非IE ev.stopPropagation();

20、闭包

闭包就是能够读取其他函数内部变量的函数,使得函数不被GC回收,如果过多使用闭包,容易导致内存泄露。

21、JSONP

JSONP,全称为json with padding,解决老版本浏览器跨域数据访问问题,原理是web页面调用JS文件不受浏览器同源策略限制,所以通过script标签可以进行跨域请求,流程如下:

首先前端设置好回调参数,并将其作为URL的参数

服务器端收到请求后,通过该参数获取到回调函数名,并将数据放在参数中返回

收到结果后因为是script标签,所以浏览器当做脚本运行。

22、函数声明与函数表达式的区别

在Javscript中,解析器在向执行环境中加载数据时,对函数声明和函数表达式并非是一视同仁的,解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问),至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解析执行。

23、JavaScript事件流

“事件冒泡”:事件开始由最具体的元素接受,然后逐级向上传播

“事件捕捉”:事件由最不具体的节点先接收,然后逐级向下,一直到最具体的

“DOM事件流”:三个阶段:事件捕捉,目标阶段,事件冒泡

24、null和undefined的区别

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时为NaN。
当声明的变量还未被初始化时,变量的默认值为undefined。
null用来表示尚未存在的对象,undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。
用法:
null表示"没有对象",即该处不应该有值

  • 作为函数的参数,表示该函数的参数不是对象。
  • 作为对象原型链的终点。

undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。

  • 变量被声明了,但没有赋值时,就等于undefined。
  • 调用函数时,应该提供的参数没有提供,该参数等于undefined。
  • 对象没有赋值的属性,该属性的值为undefined。
  • 函数没有返回值时,默认返回undefined。

25、new操作符

var p1 = {};
p1.__proto__ =  Function.prototype;
Person.call(p1);
  1. 声明一个空对象,因为实例本身就是一个对象。
  2. 将实例本身的__proto__属性指向构造函数的原型,p1新增了构造函数prototype对象上挂载的属性和方法。
  3. 将构造函数的this指向替换成p1,再执行构造函数,p1新增了构造函数本地的属性和方法。

26、基本数据类型、引用类型

基本数据类型:undefined、null、Boolean、Number、String、Symbol(es6新增)
复杂数据类型:Object
引用类型:Object、Array、Function
基本包装类型:Number、String、Boolean

会持续整合…

发布了20 篇原创文章 · 获赞 33 · 访问量 3246

猜你喜欢

转载自blog.csdn.net/qq_42880714/article/details/104518541