首页

js垃圾回收和内存泄露、js异步之宏任务和微任务

前端达人

js垃圾回收

标记清除 

       当变量进入环境时,在函数中声明一个变量,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为“离开环境”

引用计数 

        就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用值赋给该变量时,则这个值的引用次数为1。如果同一个值又被赋值给另一个变量,则该值的引用次数加1。相反,如果这个值引用的变量又取得了另外一个值,则这个值的引用次数减 1。当这个值的引用次数变成 0 时,则说明没有办法再访问这个值了,因此就可以将其占用的内存空间回收、当下次再运行时,它就会释放引用次数为 0 的值所占用的内存

内存泄漏:

        不用的内存,没有及时释放,就叫做内存泄漏

js中的内存泄漏:

1. 循环引用

        一个DOM对象被一个Javascript对象引用,同时又引用其它的Javascript对象,这个DOM对象可能会引发内存泄露。这个DOM对象的引用不会在脚本停止的时候被垃圾回收。要想破坏循环引用,就将引用DOM元素的对象赋值为null

2. 闭包

        在闭包中引入闭包外部的变量时,当闭包结束此对象无法被垃圾回收

3. DOM泄露

        当原有dom被移除时,子节点引用没有被移除则无法回收

4. Timers 计(定)时器泄露

js异步之宏任务(marcroTask)和微任务(microTask)

        宏任务包括:setTimeout、 setInterval、 Ajax 和 DOM事件
        微任务:Promise、 async/await
        微任务宏任务的执行时间要

异步和单线程

        异步单线程相辅相成的,js是一门单线程脚本语言,所以需要异步来辅助

事件循环

        同步进入主线程异步进入任务队列,主线程内的任务执行完毕为空,就去任务队列读取对应的函数,进入主线程执行

执行顺序:
        一:先执行所有的同步任务(log)
        二:执行完毕再去执行第一个宏任务
        三:执行第一个宏任务时,先看有没有需要执行的‘微任务,如果有就执行,没有就执行‘宏任务’        








蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


用Express搭建服务器

前端达人

用Express搭建服务器

之前一直是用axios请求rap2模拟的接口,想试着用express自己写一个简单的,然后连下MySQL数据库。

0、准备工作

  • 安装node
  • 初始化项目:新建一个文件夹,在里面
    npm init -y 
            
    • 1
  • 安装express
    npm install express 
            
    • 1

1、第一个小栗子(发布服务)Express 中文网

  • 新建www.js文件,把这段代码写进去,然后直接node www.js启动服务,然后在浏览器访问http://localhost:3000就可以看到后端返回的Hello World!啦。
     const express = require('express') const app = express() const port = 3000 app.get('/', (req, res) => { //这里面可以先从数据库获取数据,然后返回给前端 res.send('Hello World!') }) app.listen(port, () => { console.log(`Example app listening at http://localhost:${port}`) }) 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

2、前端axios.get请求

  • 发布服务之后就可以用axios请求啦,请求的代码如下:(但是会有问题,解决方法见 第3节
     axios.get('http://localhost:3000').then((res) => { console.log(res); }); 
            
    • 1
    • 2
    • 3
    • 4

3、前端axios.get请求的跨域问题

  • 第2节介绍了如何用axios请求后台服务,但是在本地访问上面的http://localhost:3000,如果不是同一端口的话会出现跨域不能请求的问题。解决方法是在www.js文件中加上下面这段:
 //加了这句之后就可以跨域请求了??? app.use(function (req, res, next) { res.header('Access-Control-Allow-Origin', '*'); //允许所有来源访问 res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS'); //允许访问的方式 next(); }); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 这样你就可以在本地其他端口的项目上访问3000端口啦

4、后端post接口

app.post('/post', (req, res) => { console.log(JSON.stringify(req.body));//前端发送给后端的数据 res.send('ok');//返回给前端的数据 }); 
  • 1
  • 2
  • 3
  • 4

5、前端axios.post请求

 axios.post(`http://localhost:3000/post`, "向后端发送的数据").then(res => { console.log("后端返回的数据res=>", res); }); 
  • 1
  • 2
  • 3
  • 这样你在前端就可以向后端发送请求信息,后端接收并验证之后再把数据返回给前端就好了。
  • 但是,这样还是会有点问题,第6节解决。

6、 在express中获取post请求数据(本节原文链接)

  1. express没有内置的POST请求API,但是有听说将body-parser(详情) 内置到express中了。但是我试了直接使用不了。所以还是直接安装第三方包

  2. 使用第三方包body-parser

    npm i body-parser 
            
    • 1
  3. app.js

    //1引包 const bodyParser=require('body-parser') //2配置 // 配置模板引擎和 body-parser 一定要在 app.use(router) 挂载路由之前 // parse application/x-www-form-urlencoded app.use(bodyParser.urlencoded({ extended: false })) // parse application/json app.use(bodyParser.json()) 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
  • 至此使用express搭建的简易服务器就好了,后续可以再连接数据库进行增删查改。

转载整合自(文中链接) 参考链接:
Express 中文网
在express中获取post请求数据(原文链接)
body-parser(详情)






蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


Web各大地图开发

前端达人

Web各大地图开发

介绍

想必大家对地图都不陌生,都使用过地图吧,有了地图我们也就不用在把回家的路径牢牢地记住了,只需要在地图上搜索下就能进行导航了,

而且在打车的时候也都使用的是地图,…地图作用范围很广很广这里就不在多介绍了直接进入主题.

目前市面上主流的地图有:

  1. 高德地图

    https://lbs.amap.com/ 开发者平台

  2. 百度地图

    https://lbsyun.baidu.com/ 开发者平台

  3. 腾讯地图

    https://lbs.qq.com/ 开发者平台

  4. 天地图

    https://www.tianditu.gov.cn/ 开发者平台

以上就是我们常用的地图,也是可以免费调用的地图不收费,但是有次数限制都够用,基本所有的地图开发都要先申请为开发者后才能进行地图的开发

虽然高德很火很厉害,但是我公司让我用天地图开发,所以下面的案例大致演示天地图的开发的流程,其他平台的地图开发流程基本都类似.

只要掌握一个地图的开发那么其他地图开发就是小儿科了…

开发地图需要的准备

  1. 进入天地图页面

  2. 注册账号

  3. 申请成为开发者

    开发者分为: 个人开发者和企业开发者 根据情况自行选择

  4. 然后根据需求创建应用-生成应用key

  5. 入门Dome

    实例代码:

    http://lbs.tianditu.gov.cn/api/js4.0/guide.html 以下代码的内容介绍

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <title>HELLO WORLD</title> <script type="text/javascript" src="http://api.tianditu.gov.cn/api?v=4.0&tk=9e70e9aa0be51fe8ad220e1c4b5d5aa5"></script> <script> var map; var zoom = 12; function onLoad() { map = new T.Map('mapDiv'); map.centerAndZoom(new T.LngLat(116.40769, 39.89945), zoom); //39.897019,116.323003 } </script> </head> <body onLoad="onLoad()"> <div id="mapDiv" style="position:absolute;width:100%; height:900px"></div> </body> </html> 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    地图级别 也就是地图加载后显示的缩放级别

    缩放级别1~2 那么就是洲级别 (亚洲 ,美洲…)

    缩放级别3~4 那么就是国家级别

    缩放级别5~6 那么就是省级别

    缩放级别7~8 那么就是市级别

    缩放级别9~10 那么就是区级别

    缩放级别11~12 那么就是县级别

    …以此类推 最多缩放18级别(街道级别)

    上案例效果图:

各种需求进行开发

页面

http://lbs.tianditu.gov.cn/api/js4.0/examples.html 基本日常所需的实例,稍微改动就能使用了

上面实例无法满足你的要求或者需要添加特殊操作,那么能在下面AOI文档中能找到具体实例代码里的每一个方法使用详细,然后在根据业务需求进行修改就行了

http://lbs.tianditu.gov.cn/api/js4.0/class.html

接口服务

在天地图中提供了几个服务接口用来获取一些数据的地方 ,但是注意有每日调用配额限制的(控制台可以查看次数限制)

http://lbs.tianditu.gov.cn/server/search.html

比如:客户想查询或者快速定位某一个区域或者街道的位置,但是自己通过地图一点一点的找太麻烦了那么就可以通过接口的方式直接获取到想要的数据,

查询: 北京市延庆区延庆镇莲花池村前街50夕阳红养老院的坐标

http://api.tianditu.gov.cn/geocoder?ds={"keyWord":"北京市延庆区延庆镇莲花池村前街50夕阳红养老院"}&tk=9e70e9aa0be51fe8ad220e1c4b5d5aa5

接口返回的数据:

{“msg”:“ok”,“location”:{“score”:40,“level”:“地名地址”,“lon”:116.002677524,“lat”:40.4509903540001,“keyWord”:“北京市延庆区延庆镇莲花池村前街50夕阳红养老院”},“searchVersion”:“6.0.0”,“status”:“0”}

响应接口

参数值 参数说明 参数类型 备注(值域)
status 返回状态 string 0:正常返回,101:结果为空,404:出错。
msg 返回信息 string OK:正常,其他异常。
location 地址信息 json 地址信息

location

参数值 参数说明 参数类型 备注(值域)
lon 坐标点显示经度 Double 必须返回。
lat 坐标点显示纬度 Double 必须返回。
level 类别名称 string 非必须返回。
typeRound 附近相似点 Array 开启周边查询必需返回。

然后在代码里通过

 map.centerAndZoom(new T.LngLat(116.41593, 39.92313), 16); 
  • 1

从新设置下地图显示的位置,以及缩放比例就行了.

标注案例

在很多项目都要求把客户提供的公司…在地图上标注出来并且显示对应的描述,

在天地图提供的实例中是默认鼠标点击显示,然后点击消失,实际中这样太麻烦了我们稍作修改,改变为鼠标悬浮显示,鼠标离开消失

修改后的代码

<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>天地图-地图API-范例-多个点的信息窗口</title> <script type="text/javascript" src="http://api.tianditu.gov.cn/api?v=4.0&tk=9e70e9aa0be51fe8ad220e1c4b5d5aa5"></script> <style type="text/css"> body, html{width: 100%;height: 100%;margin:0;font-family:"微软雅黑";} #mapDiv{height:900px;width:100%;} input,p { margin-top: 10px; margin-left: 5px; font-size: 14px; } </style> <script> var map var zoom = 15; function onLoad() { var data_info = [[116.417854,39.921988,"地址:北京市东城区王府井大街88号乐天银泰百货八层"], [116.406605,39.921585,"地址:北京市东城区东华门大街"], [116.412222,39.912345,"地址:北京市东城区正义路甲5号"] ]; //初始化地图对象 map = new T.Map("mapDiv"); //设置显示地图的中心点和级别 map.centerAndZoom(new T.LngLat(116.41593, 39.92313), zoom); for(var i=0;i<data_info.length;i++){ var marker = new T.Marker(new T.LngLat(data_info[i][0],data_info[i][1])); // 创建标注 var content = data_info[i][2]; map.addOverLay(marker); // 将标注添加到地图中 addClickHandler(content,marker); } function addClickHandler(content,marker){ // 改为鼠标悬浮显示 marker.addEventListener("mouseover",function(e){ openInfo(content,e)} ); //添加鼠标离开后关闭提示框 marker.addEventListener("mouseout",function(e){ map.closeInfoWindow() } ); } function openInfo(content,e){ var point = e.lnglat; marker = new T.Marker(point);// 创建标注 var markerInfoWin = new T.InfoWindow(content,{offset:new T.Point(0,-30)}); // 创建信息窗口对象 map.openInfoWindow(markerInfoWin,point); //开启信息窗口 } } </script> </head> <body onLoad="onLoad()"> <div id="mapDiv"></div> <p>为多个点添加多个点的信息窗口</p> </body> </html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

如果客户不知道自己公司…的坐标,我们可以通过-客户给的名称,进行自动搜索地理位置然后进行标注实现

<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <meta name="keywords" content="天地图"/> <title>天地图-地图API-范例-地理编码</title> <style type="text/css">body,html{width:100%;height:100%;margin:0;font-family:"Microsoft YaHei"}#mapDiv{width:100%;height:400px}input,b,p{margin-left:5px;font-size:14px}</style> <script type="text/javascript" src="http://api.tianditu.gov.cn/api?v=4.0&tk=9e70e9aa0be51fe8ad220e1c4b5d5aa5"></script> <script> var map; var zoom = 3; var geocoder; function onLoad() { //初始化地图对象 map=new T.Map("mapDiv"); //设置显示地图的中心点和级别 map.centerAndZoom(new T.LngLat(116.40969,39.89945),zoom) //创建对象 geocoder = new T.Geocoder(); //根据国家名称自动搜索,对应的坐标,然后插入标注 var list=["美国","中国","阿拉伯联合酋长国"]; for (let string of list) { geocoder.getPoint(string,searchResult); } } function searchResult(result){ console.log("经纬度: "+result.location.lat + ',' + result.location.lon) if(result.getStatus() == 0){ //创建标注对象 var marker = new T.Marker(result.getLocationPoint()); //向地图上添加标注 map.addOverLay(marker); var markerInfoWin = new T.InfoWindow("信息窗口"); marker.addEventListener("click", function () { marker.openInfoWindow(markerInfoWin); });// 将标注添加到地图中 }else{ alert(result.getMsg()); } } </script> </head> <body onLoad="onLoad()"> <div id="mapDiv"></div> <p>本示例演示如何使用地理编码接口获得坐标信息。</p> </body> </html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

vue 引入天地图

  • index.html 中引入天地图在线 API
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0"> <title>vue-tdt-demo</title> <!-- 引入天地图在线 API --> <script src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥" type="text/javascript"></script> </head> <body> <div id="app"></div> <!-- built files will be auto injected --> </body> </html> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • components 文件夹中新建 TdtMap.vue 组件

mounted() 中初始化天地图

<template> <div :id="tdtMapDivID" class="divTdtMap"></div> </template> <script> export default { name: 'TdtMap', data() { return { tdtMapDivID: "tdtMapDivID_"+this._uid, tdtMap: {} } }, created() { }, mounted(){ // 初始化天地图 this.initTdtMap() }, watch: { }, methods: { // 初始化天地图 initTdtMap(){ this.tdtMap = new T.Map(this.tdtMapDivID) this.tdtMap.centerAndZoom(new T.LngLat(116.40769, 39.89945), 12) }, } } </script> <style scoped> .divTdtMap { margin: 0px; padding: 0px; width: 100%; height: 80vh; z-index: 0; } </style> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 测试组件,新建 test.vue

导入 组件、注册 组件和 使用 组件

<template> <!-- 使用组件 --> <TdtMap></TdtMap> </template> <script> /* 导入组件 */ import TdtMap from './components/TdtMap' export default { name: 'TdtMap', components: { /* 注册组件 */ TdtMap, }, data() { return { } }, created() { }, mounted(){ }, watch: { }, methods: { }, } </script> <style scoped> </style> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

隐藏天地图LOGO

 document.getElementsByClassName("tdt-control-copyright tdt-control")[0].style.display = 'none' 
  • 1











































蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


函数作用域和立即执行函数

前端达人

变量作用域

  • JavaScript是函数级作用域编程语言:变量只在其定义时所在的function内部有意义。

全局变量

  • 如果不将变量定义在任何函数的内部,此时这个变量就是全局变量,它在任何函数内都可以被访问和更改。

遮蔽效应

  • 如果函数中也定义了和全局同名的变量,则函数内的变量会将全局的变量“遮蔽”。

注意考虑变量声明提升的情况

  • 这个程序的运行结果是什么呢?

形参也是局部变量

  • 这个程序的运行结果是什么呢?

局部函数

  • 先来认识函数的嵌套:一个函数内部也可以定义一个函数。和局部变量类似,定义在一个函数内部的函数是局部函数。

作用域链

  • 在函数嵌套中,变量会从内到外逐层寻找它的定义。

不加var将定义全局变量

  • 在初次给变量赋值时,如果没有加var,则将定义全局变量。

什么是闭包

  • JavaScript中函数会产生闭包(closure)。闭包是函数本身和该函数声明时所处的环境状态的组合。

  •  函数能够“记忆住”其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量。

观察闭包现象

  • 在JavaScript中,每次创建函数时都会创建闭包。
  • 但是,闭包特性往往需要将函数“换一个地方”执行,才能被观察出来。

闭包非常实用

  • 闭包很有用,因为它允许我们将数据与操作该数据的函数关联起来。这与“面向对象编程”有少许相似之处。
  • 闭包的功能:记忆性、模拟私有变量。

闭包用途1 - 记忆性 

  • 当闭包产生时,函数所处环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。这就是闭包的记忆性。

闭包的记忆性举例

  • 创建体温检测函数checkTemp(n),可以检查体温n是否正常,函数会返回布尔值。
  • 但是,不同的小区有不同的体温检测标准,比如A小区体温合格线是37.1℃,而B小区体温合格线是37.3℃,应该怎么编程呢?

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <script>
  10. function createCheckTemp(standardTemp) {
  11. function checkTemp(n) {
  12. if (n <= standardTemp) {
  13. console.log('你的体温正常');
  14. } else {
  15. console.log('你的体温偏高');
  16. }
  17. }
  18. return checkTemp;
  19. }
  20. // 创建一个checkTemp函数,它以37.1度为标准线
  21. var checkTemp_A = createCheckTemp(37.1);
  22. // 再创建一个checkTemp函数,它以37.3度为标准线
  23. var checkTemp_B = createCheckTemp(37.3);
  24. checkTemp_A(37.2);
  25. checkTemp_B(37.2);
  26. </script>
  27. </body>
  28. </html>

闭包用途2 - 模拟私有变量

  • 在Java、C++等语言中,有私有属性的概念,但是JavaScript中只能用闭包来模拟。

  • 题目:请定义一个变量a,要求是能保证这个a只能被进行指定操作(如加1、乘2),而不能进行其他操作,应该怎么编程呢?

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Document</title>
  7. </head>
  8. <body>
  9. <script>
  10. // 封装一个函数,这个函数的功能就是私有化变量
  11. function fun() {
  12. // 定义一个局部变量a
  13. var a = 0;
  14. return {
  15. getA: function () {
  16. return a;
  17. },
  18. add: function () {
  19. a++;
  20. },
  21. pow: function () {
  22. a *= 2;
  23. }
  24. };
  25. }
  26. var obj = fun();
  27. // 如果想在fun函数外面使用变量a,唯一的方法就是调用getA()方法
  28. console.log(obj.getA());
  29. // 想让变量a进行加1操作
  30. obj.add();
  31. obj.add();
  32. obj.add();
  33. console.log(obj.getA());
  34. obj.pow();
  35. console.log(obj.getA());
  36. </script>
  37. </body>
  38. </html>

使用闭包的注意点

  • 不能滥用闭包,否则会造成网页的性能问题,严重时可能导致内存泄露
  • 所谓内存泄漏是指程序中己动态分配的内存由于某种原因未释放或无法释放。

立即执行函数IIFE

  • IIFE(Immediately Invoked Function Expression,立即调用函数表达式)是一种特殊的JavaScript函数写法,一旦被定义,就立即被调用。

形成IIFE的方法

  • 函数不能直接加圆括号被调用。

  • 函数必须转为“函数表达式”才能被调用。

IIFE的作用1 - 为变量赋值

  • 为变量赋值:当给变量赋值需要一些较为复杂的计算时(如if语句),使用IIFE显得语法更紧凑。

IIFE的作用2-将全局变量变为局部变量

  • IIFE可以在一些场合(如for循环中)将全局变量变为局部变量,语法显得紧凑。








蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

Web API介绍及DOM对象(一)

前端达人

目录

一、API 和 Web API

1.API 

2.Web API  

3.API 和 Web API总结 

二、DOM 介绍 

1. DOM树 

三、获取元素方法 

1.getElementById()

2.getElementsByTagName

  2.1element.getElementsByTagName() 

3.HTML5 新增的方法获取

3.1 document.getElementsByClassName('类名')

3.2 document.querySelector('选择器')

3.3 document.querySelectorAll('选择器')

4.获取 body 、html 元素 

四、事件和样式操作 

1.事件概述

2.执行事件的步骤 

2.1 常见的鼠标事件 

3. 操作元素 

3.1 改变元素内容

3.2 修改元素属性

3.3 修改表单元素的属性

3.4 修改样式属性


一、API 和 Web API

1.API 

 API( Application Programming Interface,应用程序编程接口)
是一些预先定义的函数,目的是提供应用程序
与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
简单理解: API是给程序员提供的一种工具,以便能更轻松的实现想要完成的功能

2.Web API  

Web API是浏览器提供的一套操作浏览器功能和页面元素的API( BOM和DOM)。

比如我们想要浏览器弹出一个警示框,直接使用alert( '弹出');

3.API 和 Web API总结 

1. API是为我们程序员提供的一个接口,帮助我们实现某种功能,我们会使用就可以,不必纠结内部如何实现
2. Web API主要是针对于浏览器提供的接口,主要针对于浏览器做交互效果
3. Web API 一般都有输入和输出(函数的传参和返回值) ,Web API很多都是方法(函数)
4.学习Web API可以结合学习内置对象方法的思路学习

二、DOM 介绍 

文档对象模型( Document Object
Model ,简称DOM) ,是W3C组织推荐的处理可扩展标记语言( HTML或者XML )的标准编程接口
W3C已经定义了一系列的DOM接口,通过这些DOM接口可以改变网页的内容、结构和样式 

1. DOM树 

  •  文档:一个页面就是一个文档,DOM中使用 document表示
  • 元素:页面中的所有标签都是元素,DOM中使用 element表示
  • 节点:网页中的所有内容都是节点(标签、属性、文本、注释等),DOM中使用 node表示

DOM把以上内容都看作是对象 

三、获取元素方法 

1.getElementById()

 使用 getElementById( ) 方法可以获取带有ID的元素对象


  1. <div id="time" >2019-9-9 </div>
  2. <script>
  3. var timer = document.getElementById('time');
  4. console.dir(timer);
  5. </script>
  6. //返回结果为<div id= "time">2019-9-9</div>这一整个标签

 注意:
1.因为我们文档页面从上往下加载,先得有标签所以我们script 写到标签的下面
2. get 获得element 元素 by 通过驼峰命名法
3.参数 id 是大小写敏感的字符串
4.返回的是一个元素的对象
5. console.dir 打印我们返回的元素对象更好的查看里面的属性和方法

2.getElementsByTagName

 使用getElementsByTagName()方法可以返回带有指定标签名的对象的集合
 document.getElementsByTagName('标签名');


  1. <ul>
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. </ul>
  8. <script>
  9. var lis = document.getElementsByTagName('li');
  10. console.log(lis);
  11. </script>

 1. 返回的是 获取过来元素对象的集合  以伪数组的形式存储的

 2. 我们想要依次打印里面的元素对象我们可以采取遍历的方式  
   for(var i = 0; i < lis.length; i++) {
       console.log(lis[i]);
    }

 3. 得到元素对象是动态的,标签里面的内容变了,得到的内容就变了.

  2.1element.getElementsByTagName() 

element.getElementsByTagName()  可以得到这个元素里面的某些标签 


  1. <ul id = "nav">
  2. <li>1</li>
  3. <li>2</li>
  4. <li>3</li>
  5. <li>4</li>
  6. <li>5</li>
  7. </ul>
  8. <script>
  9. var nav = document.getElementById('nav');
  10. var navLis = nav.getElementsByTagName('li');
  11. </script>

3.HTML5 新增的方法获取

3.1 document.getElementsByClassName('类名')

根据类名返回元素对象集合  


  1. <div class="box" >123</div>
  2. <script>
  3. var boxs = document.getElementsByClassName('box');
  4. </script>

3.2 document.querySelector('选择器')

 根据指定选择器返回第一个元素对象
 注意:里面的选择器需要加符号 类选择器:.box   id选择器: #box


  1. var firstBox = document.querySelector('.box');
  2. var nav = document.querySelector('#nav');
  3. var firstBox = document.querySelector('li');

3.3 document.querySelectorAll('选择器')

返回指定选择器的所有元素对象集合 


  1. var allBox = document.querySelectorAll('.box');
  2. //返回所有 class 名为 box 的标签

4.获取 body 、html 元素 


  1. var body = document.body ;
  2. // 返回 body 元素对象
  3. var htmlEle = document.documentElement;
  4. // 返回 html 元素对象

四、事件和样式操作 

1.事件概述

JavaScript 使我们有能力创建动态页面,而事件是可以被JavaScript侦测到的行为

简单理解:触发---响应机制

网页中的每个元素都可以产生某些可以触发 JavaScript 的事件,例如,我们可以在用户点击某按钮时产生一个事件,然后去执行某些操作
 

 事件是有三部分组成   事件源  事件类型  事件处理程序  

  1. 事件源  事件被触发的对象     比如按钮
  2. 事件类型   如何触发   比如鼠标点击触发
  3. 事件处理程序  通过一个函数赋值的方式  完成

2.执行事件的步骤 

1. 获取事件源

2. 注册事件(绑定事件)

3. 添加事件处理程序(采用函数赋值形式)
 

2.1 常见的鼠标事件 

鼠标事件 触发条件
onclick 鼠标点击左键触发
onmouseover 鼠标经过触发
onmouseout 鼠标离开触发
onfocus 获取鼠标焦点触发
onblur 失去鼠标焦点触发
onmousemove 鼠标移动触发
onmouseup 鼠标弹起触发
onmousedown 鼠标按下触发

3. 操作元素 

JS的 DOM 操作可以改变网页内容、结构和样式,我们可以利用 DOM 操作元素来改变元素里面的内容、属性等。注意一下都是属性 

3.1 改变元素内容

① element.innerText 

可用于获取标签中的内容。此时获取的是从起始位置到终止位置的内容,但它去除 html 标签, 同时空格和换行也会去掉

获取到 p 标签再打印 p 标签中的内容
var p = document.querySelector('p');
console.log(p.innerText);

② element.innerHTML

获取内容时,获取的是起始位置到终止位置的全部内容,包括 html 标签, 同时保留空格和换行

获取到 p 标签再打印 p 标签中的内容
var p = document.querySelector('p');
console.log(p.innerHTML);

普通标签使用,表单不能用

3.2 修改元素属性

  src 、href、id 、 alt 、title

案例:点击不同按钮显示不同图片


  1. <title>Document</title>
  2. <style>
  3. img {
  4. width: 300px;
  5. margin-top: 20px;
  6. }
  7. </style>
  8. </head>
  9. <body>
  10. <button id="but1">按钮1</button>
  11. <button id="but2">按钮2</button>
  12. <br>
  13. <img src="../images/objpic07.jpg" alt="" title="图片1">
  14. <script>
  15. var item1 = document.getElementById('but1');
  16. var item2 = document.getElementById('but2');
  17. var img = document.querySelector('img');
  18. item1.onclick = function() {
  19. img.src = '../images/objpic07.jpg';
  20. img.title = '图片1';
  21. }
  22. item2.onclick = function() {
  23. img.src = '../images/objpic08.jpg';
  24. img.title = '图片2';
  25. }
  26. </script>
  27. </body>

3.3 修改表单元素的属性

可操作的表单元素的属性: type 、value、 checked、 selected、 disabled

按下按钮修改表单框 里面的内容,通过修改 value
input.value 等于 this.value  因为 this指向的是事件函数的调用者   

案例:仿京东显示隐藏密码

 


  1. <title>Document</title>
  2. <style>
  3. .box {
  4. position: relative;
  5. width: 400px;
  6. border-bottom: 1px solid #ccc;
  7. margin: 100px auto;
  8. }
  9. .box input {
  10. width: 370px;
  11. height: 30px;
  12. border: 0;
  13. outline: none;
  14. }
  15. .box img {
  16. position: absolute;
  17. top: 2px;
  18. right: 2px;
  19. width: 24px;
  20. }
  21. </style>
  22. </head>
  23. <body>
  24. <div class="box">
  25. <label for="">
  26. <img src="../images/close.png" alt="" id="pic">
  27. </label>
  28. <input type="password" id="item">
  29. </div>
  30. <script>
  31. var item = document.getElementById('item');
  32. var pic = document.getElementById('pic');
  33. var flag = 0;
  34. pic.onclick = function() {
  35. if(flag == 0) {
  36. item.type = 'text';
  37. this.src = '../images/open.png';
  38. flag = 1;
  39. } else {
  40. item.type = 'password';
  41. this.src = '../images/close.png';
  42. flag = 0;
  43. }
  44. }
  45. </script>
  46. </body>

3.4 修改样式属性

① element.style 行内样式操作

② element.className 类名样式操作

行内样式案例:显示与隐藏文本操作(当Input获取焦点,文本框初始内容消失,失去焦点,内容出现) 


  1. <title>Document</title>
  2. <style>
  3. input {
  4. color: #999;
  5. outline: none;
  6. height: 24px;
  7. }
  8. </style>
  9. </head>
  10. <body>
  11. <input type="text" value="手机">
  12. <script>
  13. var item = document.querySelector('input');
  14. item.onfocus = function() {
  15. if(this.value == '手机') {
  16. this.value = '';
  17. }
  18. this.style.color = '#333';
  19. this.style.border = '1px solid pink';
  20. }
  21. item.onblur = function() {
  22. if(this.value == '') {
  23. this.value = '手机';
  24. }
  25. this.style.color = '#999';
  26. this.style.border = '1px solid black';
  27. }
  28. </script>
  29. </body>

 类名样式案例:密码框验证信息(提示输入6~16位密码,不满或超出提示错误,正确则提示正确)


  1. <title>Document</title>
  2. <style>
  3. .box {
  4. width: 400px;
  5. margin: 100px auto;
  6. }
  7. input {
  8. outline: none;
  9. }
  10. .pic {
  11. height: 15px;
  12. display: inline-block;
  13. line-height: 15px;
  14. text-indent: 18px;
  15. font-size: 13px;
  16. color:blue;
  17. background: url(../images/mess.png) no-repeat;
  18. }
  19. .wrong {
  20. background: url(../images/wrong.png) no-repeat;
  21. color: red;
  22. }
  23. .right {
  24. background: url(../images/right.png) no-repeat;
  25. color: green;
  26. }
  27. </style>
  28. </head>
  29. <body>
  30. <div class="box">
  31. <input type="password" class="ipt">
  32. <p class="pic">请输入6~16位的密码</p>
  33. </div>
  34. <script>
  35. var item = document.querySelector('.ipt');
  36. var item2 = document.querySelector('.pic');
  37. item.onblur = function() {
  38. if(this.value.length < 6 || this.value.length > 16) {
  39. item2.className = 'pic wrong';
  40. item2.innerHTML = '您输入的位数不对要求6~16位';
  41. } else {
  42. item2.className = 'pic right';
  43. item2.innerHTML = '您输入的正确!';
  44. }
  45. }
  46. </script>
  47. </body>





蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

写大事件项目的get,post类型的接口

前端达人

1.准备工作:npm下载相关包

1.1初始化npm得到package.json文件 (不初始化也可以之前初始化的文件获得package.json文件)

npm init --yes

1.2 express包   

npm i express 

1.3 multer 包

npm i multer

2.创建server文件:在同级文件夹下创建server文件(文件名可以自定义)

3.登录接口部分

 3.1 登录接口代码


  1. const express = require('express')
  2. //将这个express的方法赋值给app
  3. const app = express()
  4. //引入multer这个包
  5. const multer = require('multer')
  6. //上传的文件会保存在这个目录下
  7. const upload = multer({ dest: 'uploads/' })
  8. //使用中间件
  9. app.use(express.urlencoded());
  10. app.use(express.json());
  11. //登录接口
  12. app.post('/api/login', (req, res) => {
  13. if (req.body.username && req.body.password) {
  14. res.json({
  15. "status": 0,
  16. "message": "登录成功",
  17. })
  18. // res.send(req.body)
  19. console.log('req.body', req.body)
  20. } else {
  21. res.json({
  22. "status": 1,
  23. "message": "登录失败",
  24. })
  25. // res.send(req.body)
  26. console.log('req.body', req.body)
  27. }
  28. // res.send()
  29. })
  30. app.listen(8023, () => {
  31. console.log('8023端口运行成功,已经跑起来了...');
  32. })

3.2 终端运行代码

 3.3 在Postman中测试发送请求,填写必要参数返回结果:

3.4  在Postman中测试发送请求,不填写必要参数返回结果:

4. 获取接口部分:

4.1  获取接口代码


  1. //引入express框架
  2. const express = require('express')
  3. //将这个express的方法赋值给app
  4. const app = express()
  5. //引入multer这个包
  6. const multer = require('multer')
  7. //上传的文件会保存在这个目录下
  8. const upload = multer({ dest: 'uploads/' })
  9. //使用中间件
  10. app.use(express.urlencoded());
  11. app.use(express.json());
  12. //获取接口
  13. app.get('/my/user/userinfo', (req, res) => {
  14. if (req.body.Authorization) {
  15. res.json({
  16. "status": 0,
  17. "message": "获取成功",
  18. "data": {
  19. "id": 1,
  20. "username": "leopard",
  21. "nickname": "little-leopard",
  22. "email": "laotang@qq.com",
  23. "user_pic": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAe"
  24. }
  25. })
  26. console.log('req.body', req.body)
  27. } else {
  28. res.json({
  29. "status": 1,
  30. "message": "获取失败",
  31. })
  32. console.log('req.body', req.body)
  33. }
  34. })
  35. app.listen(8023, () => {
  36. console.log('8023端口运行成功,已经跑起来了...');
  37. })

4.2 在终端运行

4.3 在Postman中测试发送请求,填写必要参数返回结果:

 

4.4 在Postman中测试发送请求,不填写必要参数返回结果:

5.post接口上传图片

 5.1 上传图片代码


  1. //引入express框架
  2. const express = require('express')
  3. //将这个express的方法赋值给app
  4. const app = express()
  5. //引入multer这个包
  6. const multer = require('multer')
  7. //上传的文件会保存在这个目录下
  8. const upload = multer({ dest: 'uploads/' })
  9. //使用中间件
  10. app.use(express.urlencoded());
  11. app.use(express.json());
  12. app.post('/my/user/avatar', upload.single('avatar'), (req, res) => {
  13. console.log(req.file);
  14. if (req.file) {
  15. res.json({
  16. "status": 0,
  17. "message": "上传图片成功"
  18. })
  19. console.log('req.body', req.body)
  20. } else {
  21. res.json({
  22. "status": 1,
  23. "message": "上传图片失败"
  24. })
  25. console.log('req.body', req.body)
  26. }
  27. })
  28. app.listen(8023, () => {
  29. console.log('8023端口运行成功,已经跑起来了...');
  30. })

5.2 Postman上传图片测试

 5.3终端查看



蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
作者:
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务


JS 如何实现占位符

前端达人

占位符

–首先了解一下占位符的概念。占位符就是先占住一个固定的位置,等着你再往里面添加内容的符号,广泛用于计算机中各类文档的编辑。
–格式占位符(%)是在C/C++语言中格式输入函数,如 scanf、printf 等函数中使用。其意义就是起到格式占位的意思,表示在该位置有输入或者输出。
那么在JS中,如何实现占位符呢。

JS操作

首先可以说明在js中,是没有占位符这一个概念的,那我们怎么实现该功能,这个时候就可以自己定义一个方法,去实现该功能。

String.format = function() { //字符串中赋值变量 if (arguments.length == 0) return null; var str = arguments[0]; for ( var i = 1; i < arguments.length; i++) { var re = new RegExp('\\{' + (i - 1) + '\\}', 'gm'); str = str.replace(re, arguments[i]); } return str; }; //使用方法 const h = 1; const l = 2; var key = String.format("{0}-{1}",h,l); console.log(key); //key:"1-2" 
            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17


























蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

node.js案例,写一个简单的get请求,请求有50%的概率,要求数据在一个json文件中

前端达人

  • 案例目标:实现GET的主要属性为req.method,并且生成随机数

  1. 使用nodejs,实现一个Ajax的get请求方式
  2. 将lib里的data.json文件请求获取出来
  3. data里面的数据为
    
                            
    1. {
    2. "success":[
    3. {
    4. "data": "你赢了",
    5. "message":"请求成功",
    6. "code": "200"
    7. }
    8. ],
    9. "fail":[
    10. {
    11. "data": "你输了",
    12. "message":"请求失败",
    13. "code": "200"
    14. }
    15. ]
    16. }
  •  案例准备

  •  案例代码

    
                            
    1. // 1.定义核心模块 http fs path
    2. const http = require('http')
    3. const fs = require('fs')
    4. const path = require('path')
    5. // 2.创建服务
    6. const server = http.createServer((req, res) => {
    7. // 2.1 如果url地址为/getList 执行代码
    8. // -req.method 为请求类型
    9. // 生成随机数,大于0.5为0,小于为1
    10. let render = Math.random() > 0.5 ? 0 : 1
    11. // console.log(render)
    12. // 2.2 拼接字符串,为读取数据传参
    13. // -__dirname为获取的目录地址
    14. // -lib为存放数据的名字,data.json为读取的文件
    15. const filepath = path.join(__dirname, 'lib', 'data.json')
    16. // -console.log('拼接的地址', filepath)
    17. if (render === 0 && req.url === '/getList' && req.method === 'GET') {
    18. // 2.3 读取data文件
    19. fs.readFile(filepath, 'utf8', (err, data) => {
    20. // - 打印错误信息
    21. if (err) {
    22. console.log('错误日志', err)
    23. return
    24. }
    25. // 读取的为json数据,设置请求头,如果不设置,则打印乱码信息
    26. res.setHeader('content-type', 'application/json;charset=utf8')
    27. // - 返回数据
    28. let jsonArr = JSON.parse(data)['success']
    29. let jsonStr = JSON.stringify(jsonArr)
    30. res.end(jsonStr)
    31. })
    32. } else if (render === 1 && req.url === '/getList' && req.method === 'GET') {
    33. fs.readFile(filepath, 'utf8', (err, data) => {
    34. // - 打印错误信息
    35. if (err) {
    36. console.log('错误日志', err)
    37. return
    38. }
    39. // 读取的为json数据,设置请求头,如果不设置,则打印乱码信息
    40. res.setHeader('content-type', 'application/json;charset=utf8')
    41. // - 返回数据
    42. let jsonArr = JSON.parse(data)['fail']
    43. let jsonStr = JSON.stringify(jsonArr)
    44. res.end(jsonStr)
    45. })
    46. }
    47. })
    48. // 3.启动服务
    49. // 8111为端口号,默认8000,尽量使用8开头,如果使用其他,咋不会正常运行,会报错
    50. server.listen(8111, () => {
    51. // 服务提示信息,运行代码后的提示
    52. console.log('端口1111已经开启')
    53. })











蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

JavaScript作用域和闭包

前端达人


前言

深入了解闭包和作用域链就需先了解函数预编译的过程


一、预编译

JavaScript:运行三部曲:
语法分析–预编译–解释执行
预编译:
发生在函数执行的前一刻。
函数声明整体提升,变量只声明提升。
1.函数预编译的过程:
1.创建AO对象Activation Object(执行期上下文,其作用就是我们理解的作用域,函数产生的执行空间库)
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined
3.将实参值与形参统一
4.找到函数声明,将函数名作为属性名,值为函数体。
例:

function test (a, b){ console.log(a); c = 0; var c; a = 3; b = 2; console.log(b); function b (){}; function d (){}; console.log(b); } test(1); /*答案:1,2,2
答题过程:找形参和变量声明,将变量和形参名作为 AO 属性名,值为 undefined, AO{
 a : 1,
 b : undefined,
 c : undefined
}
函数声明 function b(){}和 function d(){},AO{
 a : 1,
 b : function b(){},
 c : undefined,
 d : function d(){}
}
执行 console.log(a);答案是 1
执行 c = 0;变 AO{
 a : 1,
 b : function b(){},
 c : 0,
 d : function d(){}
}
var c 不用管,因为 c 已经在 AO 里面了
执行 a = 3;改 AO{
 a : 3,
 b : function b(){},
 c : 0,
 d : function d(){}
}
执行 b = 2;改 AO{
 a : 3,
 b : 2,
 c : 0,
 d : function d(){}
}
执行 console.log(b);答案是 2
function b () {}和 function d(){}已经提过了,不用管
执行 console.log(b);答案是 2*/ 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

2.全局预编译它和函数预编译步骤一样,但它创造的是GO(全局对象):
1.生成了一个 GO 的对象 Global Object(window 就是 GO
2.找变量声明…
3.找函数声明…

任何全局变量都是 window 上的属性
变量没有声明就赋值了,归 window 所有,就是在 GO 里面预编译。
例 :

function test(){ var a = b =123; console.log(window.b); } test(); 答案 a 是 undefined,b 是 123 先生成 GO{ b : 123 } 再有 AO{ a : undefined } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

想执行全局,先生成 GO,在执行 test 的前一刻生成 AO
函数里找变量,因为GO和AO有几层嵌套关系,近的优先,从近的到远的, AO里有就看 AO,AO 没有才看 GO。所以函数局部变量和全局变量同名,函数内只会用局部。

二、作用域精讲

作用域定义:变量(变量作用于又称上下文)和函数生效(能被访问)的区域
全局、局部变量
作用域的访问顺序:函数外面不能用函数里面的。里面的可以访问外面的,外面的不能访问里面的,彼此独立的区间不能相互访问。

1.[[scope]]: 每个 javascript 函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供 javascript 引擎存取,[[scope]]就是其中一个。[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合。

2.执行期上下文: 当函数在执行的前一刻,会创建一个称为执行期上下文的内部对象(AO)。
一个执行期上下文定义了一个函数执行时的环境,函数每次执行时对应的执行上下文都是独一无二的,所以多次调用一个函数会导致创建多个执行上下文,当函数执行完毕,执行上下文被销毁。

3.作用域链:[[scope]]中所存储的执行期上下文对象的集合(GO和AO),这个集合呈链式链接,我们把这种链式链接叫做作用域链。

4.查找变量: 在哪个函数里面查找变量,就从哪个函数作用域链的顶端依次向下查找(先查自己的AO,再查父级的AO,一直到最后的GO)。
函数类对象,我们能访问 test.name
test.[[scope]]隐式属性——作用域

作用域链图解:

function a (){ function b (){ var bb = 234; aa = 0; } var aa = 123; b(); console.log(aa) } var glob = 100; a(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

0 是最顶端,1 是次顶端,查找顺序是从最顶端往下查
在这里插入图片描述
在全局预编译中函数a定义时,它的[[scope]]属性中有GO对象。
在这里插入图片描述
在函数a执行前先函数预编译,创建自己的AO对象,并存储在[[scope]]属性上,与之前存储的GO成链式。同时函数b被创建定义。
在这里插入图片描述
在b被创建时,它生成的[[scope]]属性直接存储了父级的[[scope]],它有了父级的AO和GO。
在这里插入图片描述
b函数执行前预编译,生成自己的AO,存储在[[scope]]属性中。

详解过程: 注意[[scope]]它是数组,存储的都是引用值。
b 中 a 的 AO 与 a 的 AO,就是同一个 AO,b 只是引用了 a 的 AO,GO 也都是同一个。
function b(){}执行完,干掉的是 b 自己的 AO(销毁执行期上下文)(去掉连接线),下次 function b 被执行时,产生的是新的 b 的 AO。b 执行完只会销毁自己的 AO,不会销毁 a 的 AO。会退回到b被定义时(仍有父级的AO和GO)。
function a(){}执行完,会把 a 自己的 AO 销毁【也会把 function b的[[scope]]也销毁】,只剩 GO(回归到 a 被定义的时候),等下次 function a再次被执行时,会产生一个全新的 AO,里面有一个新的 b 函数。。。。。。周而复始。

思考一个问题:如果 function a 不被执行,下面的 function b 和 function c 都是看不到的(也不会被执行,被折叠)。只有 function a 被执行,才能执行 function a 里面的内容a();不执行,根本看不到 function a (){}里面的内容,但我们想在a函数外面调用b函数怎么办呢,于是闭包出现了。

三、闭包

闭包的定义

当内部函数被保存到外部时,将会生成闭包。但凡是内部的函数被保存到外部,一定生成闭包。
闭包的问题:闭包会导致原有作用域链不释放,作用域中的局部变量一直被使用着,导致该作用域释放不掉,造成内存泄露(就是占有过多内存,导致内存越来越少,就像泄露了一样)
例:

function a(){ function b(){ var b=456; console.log(a); console.log(b); } var a=123; return b; } var glob = a(); glob(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

答案 123,456。
function a(){ }是在 return b 之后才执行完,才销毁。而return b 把 b(包括 a 的 AO)保存到外部了(放在全局)当 a 执行完砍掉自己的 AO 时(砍掉对AO存储地址的指针),因为b还保存着对a的AO的引用,所以内存清除机制不会清除掉a的AO, b 依然可以访问到 a 的 AO。

闭包的作用:

1.实现共有变量

function test(){ var num=100; function a(){ num++; } function b(){ num--; } return [a,b]; } var myArr=test(); myArr[0](); myArr[1](); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

答案 101 和 100。
思考过程:说明两个用的是一个 AO。
myArr[0]是数组第一位的意思,即 a,myArr0;就是执行函数 a 的意思;
myArr[1]是数组第二位的意思,即 b,myArr1; 就是执行函数 b 的意思。
test doing test[[scope]] 0:testAO
1:GO
a defined a.[[scope]] 0 : testAO
1 : GO
b defined b.[[scope]] 0 : testAO
1 : GO
return[a, b]将 a 和 b 同时被定义的状态被保存出来了
当执行 myArr0;时
a doing a.[[scope]] 0 : aAO
1 : testAO
2 : GO
当执行 myArr1;时
b doing b.[[scope]] 0 : bAO
1 : a 运行后的 testAO
2 : GO
a 运行后的 testAO, 与 a doing 里面的 testAO 一模一样
a 和 b 连线的都是 test 环境,对应的一个闭包

2.可以做缓存(存储结构)

function eater(){ var food=""; var obj={ eat : function (myFood){ console.log("i am eating"+food); food =""; }, push : function (myFood){ food = myFood; } } return obj; } var eater1 = eater(); eater1.push("banana"); eater1.eat(); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

答案 i am eating banana,eat 和 push 操作的是同一个 food
在 function eater(){里面的 food}就相当于一个隐式存储的机构
obj 对象里面是可以有 function 方法的,也可以有属性,方法就是函数的表现形式

3.可以实现封装,属性私有化
只能调用函数方法,不能修改函数的属性。

4.模块化开发,防止污染全局变量


























蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn
免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

React 组件中的事件处理、组件(受控、非受控)、函数柯里化

前端达人

事件处理

在React中获取虚拟组件中的标签的值

  1. 使用组件的 refs属性
  2. 在虚拟组件的标签中定义事件,在事件中通过 箭头函数 获取标签的值
  3. 使用事件对象——event

事件处理:

  • 通过onXxx属性指定事件处理函数(注意大小写)
    • React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 ———为了更好的兼容性
    • React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————为了高效
  • 通过event.target得到发生事件的DOM元素对象 ———不要过度使用ref

使用event.target属性:

//创建组件 class Demo extends React.Component{ myRef = React.createRef() //展示输入框的数据 showData = (event)=>{ alert(event.target.value); } render(){ return( <div> <input onBlur={this.showData} type="text" placeholder="失去焦点提示数据"/> </div> ) } } //渲染组件到页面 ReactDOM.render(<Demo/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

React事件处理和Dom事件处理区别:

1、在 语法 上的不同点:

  • React事件名采用驼峰命名法,即事件名首字母大写。如onclick(Dom)——onClick(React)

  • 响应事件的函数在React中以 对象方式 赋值,Dom是以 字符串方式 赋值

    <button onclick= ' clickMe( ) '>提交</button> ——Dom方式 <button onClick={ clickMe( ) }>提交</button> ——React方式 
            
    • 1
    • 2

2、在阻止事件的默认行为有区别:React事件是合成的,DOM事件是原生

  • Dom:返回false
  • React:显示的调用事件对象event.preventDefault

React事件处理函数

  • 1、使用ES6的箭头函数

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } handleClick=()=>{ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick}>点我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
  • 2、在组件中定义事件处理函数

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } this.handleClick=this.handleClick.bind(this); } handleClick(){ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick}>点我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 注:这种方法的好处是每次render渲染都不会重新创建一个回调函数,没有额外的性能损失,但是如果在一个组件中有很多的事件函数时这种在构造函数中绑定this的方法会显得繁琐
  • 3、在给事件赋值时绑定this

    class MyComponent extends React.Component{ constructor(props){ super(props); this.state={ number:0 } } handleClick(){ ++this.state.number; console.log(this.state.number); } render(){ return( <div> <button type='button' onClick={this.handleClick.bind(this)}>点我</button> </div> ) } } ReactDOM.render(<MyComponent/>,document.getElementById('example')); 
            
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 注:但是此方法在每次render时都会重新创建一个新的函数,性能有一定的损失,但在事件处理函数需要传参数时,这种方法就比较好

事件流

在该示例中,3个div嵌套显示,并且每个元素上均绑定onClick事件。当用户点击红色区域的div元素时,可以看到,控制台先后输出了child -> parent -> ancestor,这是因为在React的事件处理系统中,默认的事件流就是冒泡。

const style={ child:{ width:'100px', height:'100px', background:'red' }, parent:{ width:'150px', height:'150px', background:'blue' }, ancestor:{ width:'200px', height:'200px', background:'green' } } class Example extends React.Component{ render(){ return( <div onClickCapture={()=> console.log('ancestor')} style={style.ancestor}> <div onClickCapture={ ()=> console.log('parent')} style={style.parent}> <div onClickCapture={ ()=> console.log('child')} style={style.child}></div> </div> </div> ) } } ReactDOM.render(<Example/>,document.getElementById('example')); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

在这里插入图片描述

  • React默认的事件触发方式:冒泡方式
  • 若将事件触发改为捕获方式:需要在事件名后带上 Capture 后缀
<div onClickCapture={()=> console.log('ancestor')} style={style.ancestor}> <div onClickCapture={ ()=> console.log('parent')} style={style.parent}> <div onClickCapture={ ()=> console.log('child')} style={style.child}></div> </div> </div> 
  • 1
  • 2
  • 3
  • 4
  • 5

事件委托

在合成事件系统中,所有的事件都是绑定在document元素上,即虽然在某个React元素上绑定了事件,但是,最后事件都委托给document统一触发。因此,在合成事件中只能阻止合成事件中的事件传播

React 阻止的事件流,并没有阻止真正DOM元素的事件触发,还是按照冒泡的方式,层层将事件交给上级元素进行处理,最后事件传播到docuement,触发合成事件,在合成事件中,child触发时,e.stopPropagation() 被调用,合成事件中的事件被终止。因此,合成事件中的stopPropagation无法阻止事件在真正元素上的传递,它只阻止合成事件中的事件流。相反,如果绑定一个真正的事件,那么,合成事件则会被终止。

  • 默认事件流是冒泡的,所有事件统一由document触发,在React中阻止冒泡方法是调用e.stopPropagation()
  • React的合成事件是可以找到原生的事件对象
  • React中的合成事件中只有一个全局对象event,该对象不是原生的event,但通过它可以获得event对象的部分属性。每个事件触发完后React的全局对象event就会被清空,因此不能在异步操作使用

事件类型:
在这里插入图片描述

收集表单数据

非受控组件

表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值(使用 ref 从DOM获取表单值),即不受React控制改变表单元素提交的值的方式,称为:“非受控组件”

class Login extends React.Component{ handleSubmit = (event)=>{ event.preventDefault() //阻止表单提交 const {username,password} = this alert(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用户名:<input ref={c => this.username = c} type="text" name="username"/> 密码:<input ref={c => this.password = c} type="password" name="password"/> <button>登录</button> </form> ) } } //渲染组件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

受控组件

在HTML中,标签<input><textarea><select>的值的改变通常是根据用户输入进行更新。在React中,可变状态通常保存在组件的状态属性中,并且只能使用 setState() 更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,以这种由React控制的输入表单元素而改变其值的方式,称为:“受控组件”。

class Login extends React.Component{ //初始化状态 state = { username:'', //用户名 password:'' //密码 } //保存用户名到状态中 saveUsername = (event)=>{ this.setState({username:event.target.value}) } //保存密码到状态中 savePassword = (event)=>{ this.setState({password:event.target.value}) } //表单提交的回调 handleSubmit = (event)=>{ event.preventDefault() //阻止表单提交 const {username,password} = this.state alert(`你输入的用户名是:${username},你输入的密码是:${password}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用户名:<input onChange={this.saveUsername} type="text" name="username"/> 密码:<input onChange={this.savePassword} type="password" name="password"/> <button>登录</button> </form> ) } } //渲染组件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

受控和非受控元素都有其优点,根据具体情况选择

特征 非受控制 受控
一次性检索(例如表单提交)
及时验证 ×
有条件的禁用提交按钮 ×
执行输入格式 ×
一个数据的几个输入 ×
动态输入 ×

函数柯里化

高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。

  1. 若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数
  2. 若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数

常见的高阶函数有:Promise、setTimeout、arr.map()等等

函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

function sum(a){ return(b)=>{ return (c)=>{ return a+b+c } } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

函数柯里化的实现

class Login extends React.Component{ //初始化状态 state = { username:'', //用户名 password:'' //密码 } //保存表单数据到状态中 saveFormData = (dataType)=>{ return (event)=>{ this.setState({[dataType]:event.target.value}) } } //表单提交的回调 handleSubmit = (event)=>{ event.preventDefault() //阻止表单提交 const {username,password} = this.state alert(`你输入的用户名是:${username},你输入的密码是:${password}`) } render(){ return( <form onSubmit={this.handleSubmit}> 用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/> 密码:<input onChange={this.saveFormData('password')} type="password" name="password"/> <button>登录</button> </form> ) } } //渲染组件 ReactDOM.render(<Login/>,document.getElementById('test')) 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

































蓝蓝设计建立了UI设计分享群,每天会分享国内外的一些优秀设计,如果有兴趣的话,可以进入一起成长学习,请扫码蓝小助,报下信息,蓝小助会请您入群。欢迎您加入噢~~希望得到建议咨询、商务合作,也请与我们联系。

分享此文一切功德,皆悉回向给文章原作者及众读者.

转自:csdn 免责声明:蓝蓝设计尊重原作者,文章的版权归原作者。如涉及版权问题,请及时与我们取得联系,我们立即更正或删除。

蓝蓝设计www.lanlanwork.com )是一家专注而深入的界面设计公司,为期望卓越的国内外企业提供卓越的UI界面设计、BS界面设计 、 cs界面设计 、 ipad界面设计 、 包装设计 、 图标定制 、 用户体验 、交互设计、 网站建设 平面设计服务

日历

链接

个人资料

蓝蓝设计的小编 http://www.lanlanwork.com

存档