前端及开发文章及欣赏

replace与replaceAll的区别

seo达人

概述



replace的参数是char和CharSequence,即可以支持字符的替换,也支持字符串的替换(CharSequence即字符串序列的意思,说白了也就是字符串)



replaceAll的参数是regex,即基于规则表达式的替换,比如:可以通过replaceAll("\d", “*”)把一个字符串所有的数字字符都换成星号



相同点



相同点:都是全部替换,即把源字符串中的某一字符或字符串全部换成指定的字符或字符串



不同点



不同点:replaceAll支持正则表达式,因此会对参数进行解析(两个参数均是),如replaceAll("\d", “"),而replace则不会,replace("\d","”)就是替换"\d"的字符串,而不会解析为正则



另外还有一个不同点:“\”在java中是一个转义字符,所以需要用两个代表一个。例如System.out.println( “\” ) ;只打印出一个""。但是“\”也是正则表达式中的转义字符,需要用两个代表一个。所以:\被java转换成\,\又被正则表达式转换成\,因此用replaceAll替换“\”为"\",就要用replaceAll("\","\\"),而replace则replace("\","\")



如果只想替换第一次出现的,可以使用replaceFirst(),这个方法也是基于规则表达式的替换,但与replaceAll()不同的是,只替换第一次出现的字符串




HTTP响应状态代码----成功响应(200–299)

seo达人

HTTP响应状态码

200 OK

201 Created

202 Accepted

203 Non-Authoritative Information

204 No Content

205 Reset Content

206 Partial Content

207 Multi-Status (WebDAV)

226 IM Used (HTTP Delta encoding)

200 OK

请求成功。成功的含义取决于HTTP方法:



GET:资源已被提取并在消息正文中传输。

HEAD:实体标头位于消息正文中。

POST:描述动作结果的资源在消息体中传输。

TRACE:消息正文包含服务器收到的请求消息

PUT 和 DELETE 的请求成功通常并不是响应200 OK的状态码而是 204 No Content 表示无内容(或者 201 Created表示一个资源首次被创建成功)。



201 Created

表示请求已经被成功处理,并且创建了新的资源。

这通常是在POST请求,或是某些PUT请求之后返回的响应。

新的资源在应答返回之前已经被创建。同时新增的资源会在应答消息体中返回,其地址是原始请求的路径或者是 Location 首部的值。



202 Accepted

表示服务器端已经收到请求消息,但是尚未进行处理。

但是稍后无法通过 HTTP 协议给客户端发送一个异步请求来告知其请求的处理结果。该状态码适用于将请求交由另外一个进程或者服务器来进行处理,或者是对请求进行批处理的情形。



203 Non-Authoritative Information

表示服务器已成功处理了请求,但返回的实体头部元信息不是在原始服务器上有效的确定集合,而是来自本地或者第三方的拷贝。

当前的信息可能是原始版本的子集或者超集。例如,包含资源的元数据可能导致原始服务器知道元信息的超集。

使用此状态码不是必须的,而且只有在响应不使用此状态码便会返回200 OK的情况下才是合适的。



204 No Content

表示该请求已经成功了,但是客户端客户不需要离开当前页面。

默认情况下 204 响应是可缓存的。一个 ETag 标头包含在此类响应中。



使用惯例是:



在 PUT 请求中进行资源更新,但是不需要改变当前展示给用户的页面,那么返回 204 No Content。

如果创建了资源,则返回 201 Created 。

如果应将页面更改为新更新的页面,则应改用 200 。

205 Reset Content

用来通知客户端重置文档视图,比如清空表单内容、重置 canvas 状态或者刷新用户界面。



与204响应一样,该响应也被禁止包含任何消息体,且以消息头后的第一个空行结束。



206 Partial Content

服务器已经成功处理了部分 GET 请求。



类似于 FlashGet 或者迅雷这类的 HTTP 下载工具都是使用此类响应实现断点续传或者将一个大文档分解为多个下载段同时下载。



该请求必须包含 Range 头信息来指示客户端希望得到的内容范围,并且可能包含 If-Range 来作为请求条件。



如果只包含一个数据区间,那么整个响应的 Content-Type 首部的值为所请求的文件的类型,同时包含 Content-Range 首部。



示例:



HTTP/1.1 206 Partial Content

Date: Wed, 15 Nov 2015 06:25:24 GMT

Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT

Content-Range: bytes 21010-47021/47022

Content-Length: 26012

Content-Type: image/gif



... 26012 bytes of partial image data ...



包含多个数据区间,那么整个响应的Content-Type首部的值为multipart/byteranges,其中一个片段对应一个数据区间,并提供 Content-Range 和 Content-Type 描述信息。



示例:



HTTP/1.1 206 Partial Content

Date: Wed, 15 Nov 2015 06:25:24 GMT

Last-Modified: Wed, 15 Nov 2015 04:58:08 GMT

Content-Length: 1741

Content-Type: multipart/byteranges; boundary=String_separator



--String_separator

Content-Type: application/pdf

Content-Range: bytes 234-639/8000



...the first range...

--String_separator

Content-Type: application/pdf

Content-Range: bytes 4590-7999/8000



...the second range

--String_separator--



207 Multi-Status (WebDAV)

代表之后的消息体将是一个XML消息,并且可能依照之前子请求数量的不同,包含一系列独立的响应代码。由WebDAV(RFC 2518)扩展的状态码.



226 IM Used (HTTP Delta encoding)

服务器已经完成了对资源的 GET 请求,并且响应是对当前实例应用的一个或多个实例操作结果的表示。






Vue 中 axios 拦截器的封装

seo达人

在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json、客户端防御cSRF等。

一 . 安装



npm install axios;

1

二 . 引入

在项目的src目录中,新建一个request文件夹,然后在里面新建一个http.js和一个api.js文件。http.js文件用来封装我们的axios,api.js用来统一管理我们的接口。

三 . 开始封装



在http.js中引入axios . vue及其他

import Axios from 'axios'; // 引入axios

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

1

2

3

http.js文件全部代码如下:



import Axios from 'axios';

import store from '../store';

import { Message, Loading, Notification } from 'element-ui'

import vue from 'vue';

// 环境的切换

if (process.env.NODE_ENV == 'development') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

else if (process.env.NODE_ENV == 'production') {

  Axios.defaults.baseURL = "http://10.230.39.58:33390/devops";

}

// request请求拦截器

Axios.defaults.withCredentials = true

vue.prototype.$axios = Axios

//请求超时时间

// Axios.defaults.timeout = 100000;

Axios.defaults.headers.get['Content-Type'] = "application/json"

Axios.interceptors.request.use(config => {

  const Basic = sessionStorage.getItem("basicParam")

  if (Basic) {

    config.headers.Authorization = Basic ${Basic};

  } else {

    console.log("无校验值");

  }

  return config;

}, error => {

  Promise.reject(error);

})

// respone返回拦截器

Axios.interceptors.response.use(

  response => {

    if (response.data.code !== 200) {

      Notification.error({

        title: '错误',

        message: response.data.message

      });

    }

    return response.data;

  }, error => {

    // Notification.error({

    //   title: '错误',

    //   message: '系统异常'

    // });

    console.log('err' + error);// for debug

    return Promise.reject(error);

  }

)



export default Axios;



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

api.js文件全部代码如下:



import axios from 'axios';

/

  封装get方法

 
@param url

  @param data

 
@returns {Promise}

 */



export function fetch(url, params = {}) {

  return new Promise((resolve, reject) => {

    axios.get(url, {

      params: params

    })

      .then(response => {

        resolve(response.data);

      })

      .catch(err => {

        reject(err)

      })

  })

}





/*

 
封装post请求

  @param url

 
@param data

  @returns {Promise}

 
/



export function _post(url, data = {}) {

  return new Promise((resolve, reject) => {

    axios.post(url, data)

      .then(response => {

        console.log(response,

          "response");



        resolve(response);

      }, err => {

        reject(err)

      })

  })

}



/

  • 封装patch请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function patch(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.patch(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    /**
  • 封装put请求
  • @param url
  • @param data
  • @returns {Promise}

    */



    export function put(url, data = {}) {

      return new Promise((resolve, reject) => {

        axios.put(url, data)

          .then(response => {

            resolve(response.data);

          }, err => {

            reject(err)

          })

      })

    }



    在main.js中引入api.js



    import { _post, fetch, patch, put } from './utils/api'

    //定义全局变量

    Vue.prototype.$post = post;

    Vue.prototype.$fetch = fetch;

    Vue.prototype.$patch = patch;

    Vue.prototype.$put = put;

    1

    2

    3

    4

    5

    6

    最后在组件里直接使用



     this.$post('/api/v2/movie/top250')

          .then((response) => {

            console.log(response)

          })

          



    其他方法用法相同




v-for生成多个div并给div中的组件绑定值

seo达人

实际业务比较复杂不便展示,写一个简单的demo记录此功能



 



遍历此div:



<div v-for="item in demoArray">

    <input type="text" v-model="item.name">

    <el-switch class="exio-switch" v-model="item.status" active-text="开" inactive-    text="关" active-color="#13ce66"></el-switch>

    <button @click="showInfo(item)">查看</button>

</div>

js代码:



new Vue({

    el: '#app',

    data() {

        return {

            demoArray: [],

        };

    },

    created() {

        // 生成模拟数据

        for (let i = 0; i < 5; i++) {

            let e = {};

            e.name = "div"+i;

            e.status = true;

            this.demoArray.push(e);

        }

    },

    methods: {

        showInfo(item) {

            console.log(item.name);

            console.log(item.status);

        }

    }

})

页面展示:







修改一条数据:







验证双向绑定结果:







为了解决不确定数量的数据(数据来源可能是接口等)的展示和操作,将每条数据作为元素放在数组中,通过数组中元素的属性来进行双向绑定。



整理的仓促,emmm,收工




模拟购物数据实时流处理——实时数据大屏

seo达人

项目介绍

本项目总体分为



平台搭建

模拟数据源生成

实时流数据处理

实时数据大屏

这几个部分,我将分成几个博客分别介绍这些部分的工作,本文主要介绍最后一个部分,实时数据大屏。

前面的几篇文章已经将平台的搭建,数据模拟生成,流数据处理部分做了详细的介绍,这篇文章主要是对前面所做的工作进行一个升华,关分析出数据不够直观,而能将所做的东西更加直观的表达出来就需要进行可视化了,下面我将为大家介绍可视化部分的工作



平台搭建,具体可以看平台搭建

模拟数据源生成,具体可以看模拟数据源生成

实时流数据处理,具体可以看实时流数据处理

项目下载地址下载



环境介绍

首先还是对环境介绍一下,这部分主要使用的将是html,php,js,css等做网站所需要的一些语言及工具,由于需要进行异步数据加载,所以还需要一个本地的服务器,本文使用的是phpstudy,主要是这个工具还集成了mysql,能简化不少我们的工作,当然如果自己拥有服务器,那完全是可以将这个部署在服务器上面的



首先我们先要安装phpstudy,这里不对具体的安装过程进行介绍,安装完成后我们可以进入网站的根目录



在这个目录下新建一个目录即可作为我们的网站目录了



然后我们可以使用phpstudy带的站点域名管理为我们的网站设置一个域名,其中的网站目就是我们刚刚创建的网站目录



在hosts里面是需要加入IP和域名的映射的,如:



127.0.0.1 www.sshstudy3.com

1

这样就可以在浏览器里面通过访问域名来访问我们要做的网站了



接下来我们需要去创建数据库,打开phpMyAdmin,我们可以进入数据库管理界面



这里的账号密码默认都是root



进入后我们可以看到如下界面



在这里可以创建数据库,或者进行数据库的访问等,不再赘述



到这里基本需要使用到的环境就基本完成了,接下来就是代码的部分


JavaScript之递归 详解!

seo达人

首先了解一下递归的定义:



递归:递归函数自己调用自己,且函数内部必须有结束条件、否则就是一个死循环;



 递归案例:求 n 的阶乘 (循环 || 递归)



阶乘公式先了解一下:







即n的阶乘 =  n(n-1)的阶乘,如归使用for循环来做这件事件就很简单:



    //for循环

    function fact(n) {

        let end = 1;

        for (var i = 1; i <= n; i++) {

            end
= i

        }

        return end

    }

    console.log(fact(5)) //5的阶乘 120

再看看递归的做法:



    //递归

    function fact(n) {

        if (n === 1) {

            return 1 //结束条件

        }

        return n fact(n - 1) //此处的fact函数相当于当前队列的阶乘

    }

    console.log(fact(5)) //5的阶乘

解析: 公式 n
(n-1)!  则函数内部只需要返回 n该函数 n-1,



即 n
(n-1)!  == nfact(n-1)  







 看一下内部队列顺序,当形参为5时 阶乘为 5
fact(n-1),直至形参n = 1时,fact函数有了返回值 1,有了结束条件后整个函数结束自掉,返回阶乘结果。



递归的优点:递归的实现明显要比循环简单得多。



递归的缺点:



1、效率低:递归由于是函数自己掉自己,而函数调用是有时间和空间的消耗的:每一次函数调用,都需要在内存栈中分配空间以保存参数、返回地址以及临时变量,而往栈中压入数据和弹出数据都需要时间。



2、性能差:调用栈可能会溢出,每次函数调用会在内存栈中分配空间,而每个进程的栈的容量是有限的,当调用的层次太多时,就会超出栈的容量,从而导致栈溢出。 



总结:对于JavaScript而言,能用循环解决的事情、尽量不要考虑递归、 慎用! 


一个 npm 包的坎坷“续命”之生

seo达人

如果说 npm 的大新闻,莫过于之前的 left-pad 撤包事件,event-stream 投毒事件,Ant Design 彩蛋事件。使得很多前端开发者又开始重新思考 npm 生态时候真的存在问题?



今天我们文章的主角是 memwatch,一个用来帮助我们检查 Node.js 是否存在内存泄漏的库,和这个库传奇的一生。



2012 年 02 月 06 日,一位 Mozilla 的工程师 lloyd 创建了这个库,并写了一篇博文“Is My NodeJS Program Leaking?”(我的 Node.js 程序是否存在内存泄漏?)。这个包最初被命名为 gcstats,代码上传到了 github。



6 月 27 日,npm 包改名为 memwatch,发布 0.1.1 版。



7 月 4 日,lloyd 为这个库添加了开源许可协议:WTFPL,发布 0.1.2 版。很多人对这个开源许可协议可能比较陌生,WTFPL 的全称是 Do What The Fuck You Want To Public License,中文译名:你他妈的想干嘛就干嘛公共许可证。也许就是这份协议开启了 memwatch 库不寻常的一生。



2013 年 3 月 14 日,作者 lloyd 提交了最后一次代码,发布了 0.2.2 版本。支持的 Node.js 版本为 0.6.0。随后这个库再也没有更新过。



从作者的博文和推文可以看到,作者在 2014 年离开了 Mozilla。而从作者的 github 动态更可以看出,作者应该是转入了 golang 阵营。



2014 年 6 月 28 日,作者的一位前同事 deepak1556 fork 了这个库,增加了对 Node.js 0.11 的支持,并发起了合并请求。但是作者并没有回复,也没有合并此次请求。此时距离原作者放弃这个库也已经过去一年多了。



2015 年 2 月 7 日,marcominetti 又 fork 了 deepak1556 的库,增加了对 Node.js 0.12 的支持,并向原库发起了合并请求,同样没有得到作者的任何回复。于是 marcominetti 决定自立门户,于是将 memwatch 改名为 memwatch-next 发布到了 npm。



2017 年 1 月 27 日,如同前两位维护者一样,marcominetti 也最终放弃了继续更新这个库。到此时,此库支持的 Node.js 版本为 4、5、6。



2018 年 5 月 6 日,eduardbcom 又 fork 了 marcominetti 的库,增加了 Node.js 9 的支持,并且放弃了对 Node.js 9 以下所有版本的支持。改名为 node-memwatch 并发布到了 npm。随后再也没有更新过代码。



2018 年 7 月 17 日,一位开发者 dyatko 又 fork 了 eduardbcom 的库,增加了对 Node.js 8 的支持,并向原库发起了合并请求,同样没有得到作者的任何回复。



但在此次 pr 的评论中,另一位开发者说,airbnb 也 fork 了 marcominetti 的库,并改名为 @airbnb/node-memwatch 发布到了 npm。



有了大厂接手,也算是这个库最终的归宿吧。







相关阅读



开发者对 npm 公司不满,unpublish 了自己的所有模块



月下载量千万的 npm 包被黑客篡改,Vue 开发者可能正在遭受攻击



驳《我不是很懂 Node.js 社区的 DRY 文化》



机器人伪装成人类在 GitHub 上为开源项目修复 bug




两栏布局

seo达人

两列布局的几种方法

html结构

 <div class="content">

      <div class="content-left">

        左侧固定200px

      </div>

      <div class="content-right">

        右侧自适应

      </div>

 </div>



1.通过float和margin-left

 / 清除浏览器默认边距 /

      {

        margin: 0;

        padding: 0;

      }



      .content{

        overflow: hidden;

      }

      /
脱离文档流 /

      .content-left {

        float: left;

        width: 200px;

        height: 200px;

        background: red;

      }



      .content-right {

        /
通过margin-left将左边位置空出 /

        margin-left: 200px;

        background: blue;

        height: 200px;

      }



2.通过 position: absolute;绝对定位

 /
清除浏览器默认边距 /

     
{

        margin: 0;

        padding: 0;

      }



      .content {

        overflow: hidden;

        position: relative;

      }

      / 脱离文档流 /

      .content-left {

        position: absolute;

        top: 0;

        left: 0;

        width: 200px;

        height: 200px;

        background: red;

      }



      .content-right {

        / 通过margin-left将左边位置空出 /

        margin-left: 200px;

        background: blue;

        height: 200px;

      }



3.通过flex弹性布局

/ 清除浏览器默认边距 /

      {

        margin: 0;

        padding: 0;

      }



      .content {

        overflow: hidden;

        display: flex;

      }

      .content-left {

          /
除了width: 200px;还可以flex-basis: 200px; /

        width: 200px;

        height: 200px;

        background: red;

      }



      .content-right {

          /
flex:1;将剩余空间分给它 /

        flex: 1;

        background: blue;

        height: 200px;

      }



4.通过 display: table;表格布局

 /
清除浏览器默认边距 /

     
{

        margin: 0;

        padding: 0;

      }



      .content {

        overflow: hidden;

        display: table;

        / 必须给父级定宽不然自适应盒子没定宽只会由内容撑开 /

        width: 100%;

      }

      .content-left {

        display: table-cell;

        width: 200px;

        height: 200px;

        background: red;

      }



      .content-right {

        display: table-cell;

        background: blue;

        height: 200px;

      }



5.通过inline-block和calc()函数

 / 清除浏览器默认边距 /

      {

        margin: 0;

        padding: 0;

      }



      .content {

        /
必须加font-size=0;把inline-block默认间距去掉,

        不过设置后里面文字不显示了可以给里面块设置font-size:20px;

        或者把两个块之间的换行删掉也能去掉间距/

        font-size: 0;

        overflow: hidden;

      }

      .content-left {

        font-size: 20px;

        display: inline-block;

        width: 200px;

        height: 200px;

        background: red;

      }



      .content-right {

        font-size: 20px;

        display: inline-block;

        background: blue;

        height: 200px;

        /
注意calc里的运算符两边要有空格 /

        width: calc(100% - 200px);

      }



6.通过float和calc()函数,左右两块都要浮动

 /
清除浏览器默认边距 /

     
{

        margin: 0;

        padding: 0;

      }



      .content {

        overflow: hidden;

      }

      .content-left {

        float: left;

        width: 200px;

        height: 200px;

        background: red;

      }

      .content-right {

        float: left;

        background: blue;

        height: 200px;

        / 注意calc里的运算符两边要有空格 /

        width: calc(100% - 200px);

      }



7.使用grid布局

 / 清除浏览器默认边距 /

      {

        margin: 0;

        padding: 0;

      }



      .content {

        overflow: hidden;

        display: grid;

        grid-template-columns: 200px 1fr;

        /
grid布局也有列等高的默认效果。需要设置: align-items: start;。 /

        align-items: start;

      }

      .content-left {

        height: 200px;

        background: red;

        /
grid布局还有一个值得注意的小地方和flex不同:在使用margin-left的时候,

        grid布局默认是box-sizing设置的盒宽度之间的位置。

        而flex则是使用两个div的border或者padding外侧之间的距离。 */

        box-sizing: border-box;

        grid-column: 1;

      }

      .content-right {

        background: blue;

        height: 200px;

        box-sizing: border-box;

        grid-column: 2;

      }



如何复制网页上不能复制的文本!!!

seo达人

   我们经常需要引用(白嫖)一些网页上的文字,但是豆丁网,百度文库等等设置的有复制权限,我们无法直接复制,或者复制文字有上限,提示付费。

    这里介绍几种,都是些花里胡哨的白嫖方案:

1.手机扫描:

    拿着手机,用手机QQ的文字扫描直接去识别问题,遇上好识别的文章短的直接就识别,但是这种方法遇到文章比较长的就十分麻烦。可以针对那些选中



2.魔鬼牵引:

    原来在计蒜客就这样搞,选中网站上的文字,然后用鼠标一直拖到别的页面,或者一个记事本什么的,屡试不爽。



3.侧边翻译:

    侧边翻译,火狐或者谷歌下载一些插件,比如说侧边翻译,这个东西小巧玲珑,选中文字侧边翻译之后你就可以对文本进行复制了。



4.原始查看法:

    在浏览器中直接F12,打开浏览器查看,就下面这个东西,浏览器你要复制的文本就在这里面,里面封装的html语言,你可以搜索你需要找的文字,然后可以直接复制,如果想要复制多一点你也可以直接把里面的html语言拿出来解析到自己的网页里面,然后再进行复制。





5.氪金法:

    没别的,充钱就完事了。



6.某巨巨提供:

    下载一个ocr工具,类似qq扫描的功能。






详解函数和变量的声明提升

seo达人

详细解读—函数和变量的声明提升

一 - 声明提升常见面试题

☛我们先以几道面试题开头来引入,

☛大家可以先给自己做出一个答案,然后再看文章的思路捋一捋哟。



来一道基础的吧~



var a="Hello";  

function test(){  

  alert(a); 

  var a="World";

  alert(a);

}

test();



难度+1



var a = 1;

function outer(){ 

  a = 2; 

  function inner(){       

      alert(a); 

      a = 4; 

  } 

  inner();



outer(); 

alert(a);



继续加油



(function(){

  f1(); 

  f2();

  var f1 = function(){};

  function f2(){

      alert(1);

  }

})();



最后一道



(function () {

   console.log(a);

   var a=1;

   function a() {

       console.log("biu~");

   }

})()



二 - 究竟什么是声明提升?

引擎在解释JS代码之前,首先要对JS代码进行编译,其中编译的一部分工作就是找到所有的声明,包括变量和函数的所有声明都会在任何代码被执行前首先被处理。

var a = 1这句话会被浏览器读成 var a和a = 1两句话执行,其中var a会在编译阶段就先执行了,而a = 1这段赋值代码会在原地等待执行阶段。

console.log(a); 

var a = 2;



上边这段代码,如果代码按照顺序由上自下执行,那么执行到console.log(a);时,a还没有声明,所以会包一个找不到变量a的错,但是事实上,这句话打印了一个undefined,说明a被声明了,但是没有被赋值,那么结合上一段的文字,我们可以得出代码实际运行的是这样的:



var a;

console.log(a);

a = 2;



三 - 函数的提升

大家可能在书写代码的时候发现,无论函数封装写在前或者后,我们的函数调用都可以顺利执行。



fn1();//可以执行

function fn1() {

    console.log("hello");

}



为什么呢?其实函数声明,包括函数的代码块都i会被提升,所以调用函数的时候,函数声明已经被执行过了。



但是有个案例大家了解一下:



fn2();//报错,fn2不是一个函数

var fn2 = function () {

   console.log("world");

}



我们可以看到 以给匿名函数赋值的形式定义函数,只会提升函数声明,但是函数表达式却不会被提升。因为变量fn2被提升,但是并没有赋值,我们书写的fn2()无法运行,而抛出了异常。

以下就是实际执行的顺序:



var fn2;

fn2();

fn2 = function () {

   console.log("world")

}



函数优先提升

我们都知道了,函数声明和变量声明都会被提升,那么遇到这样的情况会怎么办?



fn3();

var fn3=function () {

    console.log("fn3-1");

}

fn3();

function fn3() {

    console.log("fn3-2");

}



哎呦,嘛情况,突然迷了!!!

☛ 这个时候你就要考虑,同样的一个变量名称,到底是把var fn3给先提声上去,再提升 fn3函数体?还是先提升 fn3函数体,再提升var fn3???其实都不对!!!



☛ 答案是:函数会被优先提升,但后才是变量提升,但是当函数提升后,然后发现还有一个变量声明和函数声明一样的名称,这个就是重复声明,那么这个var fn3 是不生效直接忽略的。



所以实际代码运行顺序是:



function fn3() {

   console.log("fn3-2");

}

fn3();//fn3-2

fn3=function () {//var fn3因为重复声明被忽略

   console.log("fn3-1");

}

fn3();//fn3-1



当然,我们还是建议再同一个作用域重复声明是很烂的选择



说在最后

再代码作用域中的声明,都会在代码执行前被首先处理,所有的声明都会被移动到各自作用域的最顶端,这个过程就叫做声明提升。



四 - 答案:

问题1:



var a="Hello";  

function test(){  

  alert(a); 

  var a="World";

  alert(a);

}

test();



实际执行:

var a="Hello";

function test(){

   //作用域有声明a,声明提升到这里

   var a;

   alert(a);//本作用域声明a,所以不去使用父作用域的a,但是本作用域的a没有赋值,所以弹出undefined

   a="World";

   alert(a);//赋值后 ,弹出world

}

test();



问题2:



var a = 1;

function outer(){ 

  a = 2; 

  function inner(){       

      alert(a); 

      a = 4; 

  } 

  inner();



outer(); 

alert(a);



执行结果:



var a = 1;

function outer(){

   a = 2;

   function inner(){

       //本作用域没有声明a,所以没有任何提升,直接执行

       alert(a); // 所以弹出 a为 2

       a = 4;

   }

   inner();

}

outer();

alert(a);//只有全局声明了a,所以所有作用域使用的都是全局的a,所以a最后被赋值为4 弹出4



问题3



(function(){

  f1(); 

  f2();

  var f1 = function(){};

  function f2(){

      alert(1);

  }

})();

实际执行结果:



(function(){

   function f2(){

       alert(1);

   }

   var fn1;

   f1();//提升后先执行fn1(),但是fn1被提升的是变量不是函数,所以这里报错,不是一个函数

   f2();//上一句话报错,这句话不再运行

   f1 = function(){};

})();



问题4:



(function () {

   console.log(a);

   var a=1;

   function a() {

       console.log("biu~");

   }

})()

实际执行结果:



(function () {

   function a() {

       console.log("biu~");

   }

   console.log(a);//打印了a这个函数的函数体

   a=1;//因为函数有限声明提升,所以这里的var a被提升时,发现重复声明,故被忽略了var a;    

})()


日历

链接

blogger

蓝蓝 http://www.lanlanwork.com

存档