闭包、跨域、this指向问题

2022-02-14  本文已影响0人  px1012
1.闭包是什么?用let怎么实现闭包?有什么优点和缺点?

闭包的定义:闭包就是指有权访问另一个函数作用域中变量的函数
优点:① 能够读取函数内部的变量;②外部函数调用对象后其变量对象本应该被销毁,但闭包的存在使我们仍然可以访问外部函数的变量对象
缺点:①函数的作用域及其所有变量都会在函数执行结束后被销毁。但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止。所以内存消耗很大。
闭包的缺点就是常驻内存会增大内存使用量,并且使用不当很容易造成内存泄露。②闭包只能取得包含函数中的任何变量的最后一个值。
应用闭包的主要场合是:设计私有的方法和变量。
先看一个基本的闭包

function lazy_sum(arr) {
    var sum = function () {
        return arr.reduce(function (x, y) {
            return x + y;
        });
    }
    return sum;
}
var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()
f(); // 15

封装一个私有变量(用JavaScript创建一个计数器)

function create_counter(initial) {
    var x = initial || 0;
    return {
        inc: function () {
            x += 1;
            return x;
        }
    }
}
var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13

在返回的对象中,实现了一个闭包,该闭包携带了局部变量x,并且,从外部代码根本无法访问到变量x。换句话说,闭包就是携带状态的函数,并且它的状态可以完全对外隐藏起来。

用(function(j){})会产生函数级的作用域。
而用 let 声明的就是块作用域,和函数级的作用域一样都可以用于形成闭包
具体看下面的例子:

 var arr=[];
     for(var i=0;i<10;i++){
          arr.push(()=>i)
}
console.log(arr[2]())   //10
var arr=[];
     for(let i=0;i<10;i++){
     arr.push(()=>i)
}
console.log(arr[2]())   //2
js中本地存储有哪些?有什么不同?

cookie、localStorage、sessionStorage
相同点:都保存在浏览器端;
不同点:
①传递方式不同
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。
sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
②数据大小不同
(cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下。) ​ 存储大小限制也不同,cookie数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很小的数据,如会话标识。
sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
③数据有效期不同
sessionStorage:仅在当前浏览器窗口关闭前有效,自然也就不可能持久保持;
localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;
cookie只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭。
④作用域不同
sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;
localStorage 在所有同源窗口中都是共享的;
cookie也是在所有同源窗口中都是共享的。

跨域 参考

1)什么是跨域?
广义的来说:跨域是指一个域下的文档或脚本试图去请求另一个域下的资源。
其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。
2)什么是同源策略?
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
CSRF(Cross-site request forgery)跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。尽管听起来像跨站脚本([XSS]),但它与XSS非常不同,XSS利用站点内的信任用户,而CSRF则通过伪装成受信任用户的请求来利用受信任的网站。
跨域解决方案
1、 通过jsonp跨域

根据浏览器同源策略,所谓同源就是协议、主机、端口号都相同时成为同源。a 域的js不能直接访问 b域名的信息,但是script 标签的src属性可以跨域引用文件,jsonp是请求之后后台包装好一段json,并且把数据放在一个callback函数,返回一个js文件,动态引入这个文件,下载完成js之后,会去调用这个callback,通过这样访问数据。

跨域资源共享(CORS)
普通跨域请求:只服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求:前后端都需要设置。

2、 document.domain + iframe跨域 3、 location.hash + iframe4、 window.name + iframe跨域 5、 postMessage跨域 6、 跨域资源共享(CORS)7、 nginx代理跨域 8、 nodejs中间件代理跨域 9、 WebSocket协议跨域
Access-Control-Allow-Credentials 响应头会使浏览器允许在 Ajax 访问时携带 Cookie
对 XMLHttpRequest 设置其 withCredentials 参数,才能实现携带 Cookie 的目标
vue中跨域解决方法

方法1.后台更改header
header('Access-Control-Allow-Origin:*');//允许所有来源访问
header('Access-Control-Allow-Method:POST,GET');//允许访问的方式 2.使用http-proxy-middleware 代理解决(项目使用vue-cli脚手架搭建)
例如请求的url:“http://f.apiplus.cn/bj11x5.json
1、打开config/index.js,在proxyTable中添写如下代码:
proxyTable: {
'/api': { //使用"/api"来代替"http://f.apiplus.c"
target: 'http://f.apiplus.cn', //源地址
changeOrigin: true, //改变源
pathRewrite: {
'^/api': 'http://f.apiplus.cn' //路径重写
}
}
}
getData () {
axios.get('/api/bj11x5.json', function (res) {
console.log(res)
})
通过这中方法去解决跨域,打包部署时还按这种方法会出问题。解决方法如下:
let serverUrl = '/api/' //本地调试时
// let serverUrl = 'http://f.apiplus.cn/' //打包部署上线时
export default {
dataUrl: serverUrl + 'bj11x5.json'
}

3.nginx反向代理

nginx反向代理接口跨域
跨域原理: 同源策略是浏览器的安全策略,不是HTTP协议的一部分。服务器端调用HTTP接口只是使用HTTP协议,不会执行JS脚本,不需要同源策略,也就不存在跨越问题。
实现思路:通过nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域登录。

image.png
postMessage

用法:postMessage(data,origin)方法接受两个参数
data: html5规范支持任意基本类型或可复制的对象,但部分浏览器只支持字符串,所以传参时最好用JSON.stringify()序列化。
origin: 协议+主机+端口号,也可以设置为"*",表示可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。

this的指向问题 参考
1、在全局范围内,this指向全局对象(浏览器下指window对象)
2、对象函数调用时,this指向当前对象
3、全局函数调用时,应该是指向调用全局函数的对象。
4、使用new关键字实例化对象时,this指向新创建的对象
5、当用apply和call上下文调用的时候指向传入的第一个参数
改变this指向的方法:
1)使用箭头函数;

箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象),而不是执行时的对象, 定义它的时候,可能环境是window; 箭头函数可以方便地让我们在 setTimeout ,setInterval中方便的使用this
2)在函数内部使用_this=this;
3)使用apply、call、bind
4)new实例化一个对象;

上一篇下一篇

猜你喜欢

热点阅读