1 纯JS获取scrolltop值
document.body 和 document.documentElement 区别:
- document.body 返回的是 body节点 即<body>
- document.documentElement 返回的是 html 节点 即<html>
在chrome中 获取 scrollTop 只能用 docume.body.scrollTop;
在IE中 没有doctype声明 使用 document.body.scrollTop;有doctype声明的使用document.documentElement.scrollTop;
SO... 兼容性写法 :
const scrollTop = document.documentElement.scrollTop || docume.body.scrollTop
2 详述JS闭包原理和意义
闭包是指有权访问另一个函数作用域中的变量和函数。创建闭包的常见方式,就是在一个函数内部创建另一个函数。
举个例子
1 var name = "visiliki" 2 function user() { 3 function getName () { 4 console.log(name) 5 } 6 getName() 7 } 8 user()
在 getName 函数中获取 name,首先在 getName 函数的作用域中查找 name,未找到,进而在 user 函数的作用域中查找,同样未找到,继续向上回溯,发现在全局作用域中存在 name,因此获取 name 值并打印。
这里很好理解,即变量都存在在指定的作用域中,如果在当前作用中找不到想要的变量,则通过作用域链向在父作用域中继续查找,直到找到第一个同名的变量为止(或找不到,抛出 ReferenceError 错误)。
这是 js 中作用域链的概念,即子作用域可以根据作用域链访问父作用域中的变量,那如果相反呢,在父作用域想访问子作用域中的变量呢?——这就需要通过闭包来实现。
闭包就是跨作用域访问变量 —— 内部作用域可以保持对外部作用域中变量的引用从而使得(更)外部作用域可以访问内部作用域中的变量。
为什么需要闭包?
局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。
特点
占用更多内存
不容易被释放
何时使用?
变量既想反复使用,又想避免全局污染
如何使用?
定义外层函数,封装被保护的局部变量。
定义内层函数,执行对外部函数变量的操作。
外层函数返回内层函数的对象,并且外层函数被调用,结果保存在一个全局的变量中。
3. 深拷贝浅拷贝是什么
深浅拷贝的区别只适用于array【数组】与object【对象】
浅拷贝
相当于使两个数组指针指向相同的地址,任一个数组元素发生改变,影响另一个。
注意:当内存销毁的时候,只想对象的指针,必须重新定义,才能够使用
代码如下:
1 var a = {x:0} 2 var b = a 3 console.log(b) //{x:0} 4 b.x = 3 5 console.log(b) //{x:3} 6 console.log(a) //{x:3}
浅拷贝是一个传址,也就是把a的值赋给b的时候同时也把a的址赋给了b,当b(a)的值改变的时候,a(b)的值同时也会改变
深拷贝
两数组指针指向不同的地址,数组元素发生改变时不会相互影响
深拷贝的几种方法
JSON内置方法
1 var a = {x:0} 2 var b=JSON.parse(JSON.stringify(a)) 3 console.log(b) //{x:0} 4 b.x = 1 5 console.log(b) //{x:1} 6 console.log(a) //{x:0}
该方法是用json.parse()将对象转化为字符串,然后再用json.stringify()转回对象json字符串转换为对象的时候,会自己去构建新的内存地址存放数据
递归实现
1 function copy(obj) { 2 //首先确定递归的回调,最终达到对象或者数组的末端,达到深拷贝的要求 3 var newObj; 4 if (obj instanceof Array) { //确定类型 5 newObj = []; //创建一个空的数组 6 var i = obj.length; 7 while (i--) { 8 newObj[i] = copy(obj[i]); //递归回调 9 } 10 return newObj 11 } else if (obj instanceof Object) { //确定类型 12 newObj = {}; //创建一个空的对象 13 for (var k in obj) { //为这个对象添加一个新的属性 14 newObj[k] = copy(newObj[k]) //递归回调 15 } 16 return newObj //结束函数完成深拷贝 17 } else { 18 return obj //结束函数完成深拷贝 19 } 20 }
4. ES6的作用域
块级作用域let
作用域是一个变量的有效范围,也就是声明一个变量以后,这个变量在什么场合可以使用。以前的JS只有全局作用
域,还有一个函数作用域。
1 var name = 'visiliki'; 2 while (true) { 3 var name = 'violet'; 4 console.log(name) //violet 5 break 6 } 7 console.log(name) //violet 8 let name = 'soybean'; 9 while (true) { 10 let name = 'milk'; 11 console.log(name); //milk 12 break 13 } 14 console.log(name) //soybean
常量const
使用const可以声明一个常量,一旦声明,常量的值就不能改变
const PI = Math.PI PI = 23 //Identifier 'PI' has already been declared
注意,const限制的是常量分配值,而这个常量的值又是不可更改的。
5. 详述promise异步机制
promise是异步编程的一种解决方案,
promise是一个JS内置对象,这个对象接受一个函数作为参数,函数中又会传入两个函数,第一个是成功后调用的函数,第二个是失败后调用的函数。
1 function Promise(executor){ //executor执行器 2 let self = this; 3 self.status = 'pending'; //等待态 4 self.value = undefined; // 表示当前成功的值 5 self.reason = undefined; // 表示是失败的值 6 function resolve(value){ // 成功的方法 7 if(self.status === 'pending'){ 8 self.status = 'resolved'; 9 self.value = value; 10 } 11 } 12 function reject(reason){ //失败的方法 13 if(self.status === 'pending'){ 14 self.status = 'rejected'; 15 self.reason = reason; 16 } 17 } 18 executor(resolve,reject); 19 } 20 21 Promise.prototype.then = function(onFufiled,onRejected){ 22 let self = this; 23 if(self.status === 'resolved'){ 24 onFufiled(self.value); 25 } 26 if(self.status === 'rejected'){ 27 onRejected(self.reason); 28 } 29 } 30 module.exports = Promise;
cted 可以理解为失败的状态
- 构造一个promise实例需要给promise构造函数传入一个参数,传入的参数需要两个形参,两个形参都是function类型的函数,分别是resolve和reject
- promise上还有then方法,then方法就是用来指定promise对象的状态改变时确定执行的操作,resolve时执行第一个函数(onFulfilled),reject时执行第二个函数(onRejected)
- 当状态变为resolve时便不能再变为reject,反之同理
6.如何实现跨域访问
什么叫做跨域
默认情况下,XHR对象只能访问与包含它的页面位于同一个域中的资源,当协议,域名,端口有任何一个不同,都会被当作是不同的域。
对于端口和协议的不同,只能通过后台来解决,前端要解决的是域名不用的问题。
如何跨域
- Cors(跨源资源共享)
使用自定义的HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
实现此功能非常简单,只需由服务器发送一个响应标头即可。
CORS的兼容性写法:
function createCORSRequest(method, url){ var xhr = new XMLHttpRequest(); //非IE浏览器 if ("withCredentials" in xhr){ xhr.open(method, url, true); //IE浏览器 } else if (typeof XDomainRequest != "undefined"){ vxhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; } var request = createCORSRequest("get", "http://www.somewhere-else.com/page/"); if (request){ request.onload = function(){ //对request.responseText 进行处理 }; request.send(); }
2 JSONP()
在js中,我们虽然不萌直接用XMLHttpRequest请求不同域上的数据时,但是在页面上引用不同域上的js脚本文件却是可以的,jsonp就是根据这个特性来实现的
jsonp由两个部分组成,回调函数和数据。回调函数时当响应来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。
1 <script type="text/javascript"> 2 function dosomething(jsondata){ 3 //处理获得的json数据 4 } 5 </script> 6 <script src="http://example.com/data.php?callback=dosomething"></script>
第一个script标签定义可一个处理数据的函数,第二个script载入了一个js文件,http://example.com/data.php是一个数据所在的地址,但是因为时当作js引入的,所以http://example.com/data.php返回的必须是一个能够执行的js文件,最后载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数引入。
JQuery支持jsonp的实现方式 (只能够实现get请求)
1 $.ajax({ 2 url:'http://www.baidu.com/login' , 3 type: 'Get' , 4 dataType:'jsonp', //请求方式为jsonp 5 jsonpCallback: 'callback', 6 data:{ 7 'username': 'visiliki' 8 } 9 })