整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

JavaScript的值传递和引用传递

avaScript有5种基本的数据类型,分别是:布尔、null、undefined、String和Number。这些基本类型在赋值的时候是通过值传递的方式。值得注意的是还有另外三种类型: Array、Function和Object,它们通过引用来传递。从底层技术上看,它们三都是对象。

基本数据类型

如果一个基本的数据类型绑定到某个变量,我们可以认为该变量包含这个基本数据类型的值。

var x = 10;
var y = 'abc';
var z = null;

当我们使用 = 将这些变量赋值到另外的变量,实际上是将对应的值拷贝了一份,然后赋值给新的变量。我们把它称作值传递

var x = 10;
var y = 'abc';
var a = x;
var b = y;
console.log(x, y, a, b) // 10, 'abc', 10, 'abc'

a和x都包含10,b和y都包含'abc',并且它们是完全独立的拷贝,互不干涉。如果我们将a的值改变,x不会受到影响。

var x = 10;
var y = 'abc';
var a = x;
var b = y;
a = 5;
b = 'def';
console.log(x, y, a, b); // 10, 'abc', 5, 'def'

对象

如果一个变量绑定到一个非基本数据类型(Array, Function, Object),那么它只记录了一个内存地址,该地址存放了具体的数据。注意之前提到指向基本数据类型的变量相当于包含了数据,而现在指向非基本数据类型的变量本身是不包含数据的。

对象在内存中被创建,当我们声明arr = [],我们在内存中创建了一个数组。arr记录的是该内存的地址。

var arr = []; // (a)
arr.push(1); // (b)

当执行完(a)之后,内存中创建了一个空的数组对象,其内存地址为#001, arr 指向该地址。

当执行完(b)之后,数组对象中多了一个元素,但是数组的地址依然没有变,arr也没有变。

引用传递

对象是通过引用传递,而不是值传递。也就是说,变量赋值只会将地址传递过去。

var reference = [1];
var refCopy = reference;

reference和refCopy指向同一个数组。 如果我们更新reference,refCopy也会受到影响。

reference.push(2);
console.log(reference, refCopy); // [1, 2], [1, 2]

引用重新赋值

如果我们将一个已经赋值的变量重新赋值,那么它将包含新的数据或则引用地址。

var obj = { first: 'fundebug.com'};
obj = { second: 'fundebug.cn'};

obj 从指向第一个对象变为指向第二个对象。

如果一个对象没有被任何变量指向,就如第一个对象(地址为#001),JavaScript引擎的垃圾回收机制会将该对象销毁并释放内存。

== 和 ===

对于引用类型的变量,==和===只会判断引用的地址是否相同,而不会判断对象具体里属性以及值是否相同。因此,如果两个变量指向相同的对象,则返回true。

var arrRef = ['Hi!'];
var arrRef2 = arrRef;
console.log(arrRef === arrRef2); // true

如果是不同的对象,及时包含相同的属性和值,也会返回false。

var arr1 = ["Hi!"];
var arr2 = ["Hi!"];
console.log(arr1 === arr2); // false

如果想判断两个不同的对象是否真的相同,一个简单的方法就是将它们转换为字符串然后判断。

var arr1str = JSON.stringify(arr1);
var arr2str = JSON.stringify(arr2);
console.log(arr1str === arr2str); // true

另一个方法就是递归地判断每一个属性的值,直到基本类型位置,然后判断是否相同。

函数参数

当我们将基本类型数据传入函数,函数会将这些数据拷贝赋值给函数的参数变量。

var hundred = 100;
var two = 2;
function multiply(x, y) {
 return x * y;
}
var twoHundred = multiply(hundred, two);

hundred的值拷贝给变量x,two的值拷贝给变量y。

纯函数

对于一个函数,给定一个输入,返回一个唯一的输出。除此之外,不会对外部环境产生任何附带影响。我们机会称该函数为纯函数。所有函数内部定义的变量在函数返回之后都被垃圾回收掉。

但是,如果函数的输入是对象(Array, Function, Object),那么传入的是一个引用。对该变量的操作将会影响到原本的对象。这样的编程手法将产生附带影响,是的代码的逻辑复杂和可读性变低。

因此,很多数组函数,比如 Array.map 和 Array.filter 是以纯函数的形式实现。虽然它们的参数是一个数组变量,但是通过深度拷贝并赋值给一个新的变量,然后在新的数组上操作,来防止原始数组被更改。

我们来看一个例子:

function changeAgeImpure(person) {
 person.age = 25;
 return person;
}
var alex = {
 name: 'Alex',
 age: 30
};
var changedAlex = changeAgeImpure(alex);
console.log(alex); // { name: 'Alex', age: 25 }
console.log(changedAlex); // { name: 'Alex', age: 25 }

在非纯函数changeAgeImpure中,将对象person的age更新并返回。原始的alex对象也被影响,age更新为25。

让我们来看如何实现一个纯函数:

function changeAgePure(person) {
 var newPersonObj = JSON.parse(JSON.stringify(person));
 newPersonObj.age = 25;
 return newPersonObj;
}
var alex = {
 name: 'Alex',
 age: 30
};
var alexChanged = changeAgePure(alex);
console.log(alex); // { name: 'Alex', age: 30 }
console.log(alexChanged); // { name: 'Alex', age: 25 }

我们通过JSON.sringify将对象变为一个字符串,然后再通过JSON.parse将字符串变回对象。通过该操作会生成一个新的对象。

一道简单的面试题

值传递和引用传递经常在面试中被问到,来尝试回答一下如下代码如何输出:

TML DOM INPUT FILE 大文件上传解决方案,HTML5大文件上传解决方案,HTML5大文件上传源代码,HTML5大文件上传源码,HTML5大文件上传代码,HTML5大文件上传技术,HTML5大文件上传技巧,HTML5大文件上传配置,HTML5大文件上传方法,HTML5大文件上传原理,HTML5大文件上传教程,HTML5大文件上传视频,javascript大文件上传技术,vue大文件上传技术,dom大文件上传技术,input file大文件上传技术,

用户上传的文件比较大,有20G左右,直接用HTML传的话容易失败,服务器也容易出错,需要分片,分块,分割上传。也就是将一个大的文件分成若干个小文件块来上传,另外就是需要实现秒传功能和防重复功能,秒传就是用户如果上传过这个文件,那么直接在数据库中查找记录就行了,不用再上传一次,节省时间,实现的思路是对文件做MD5计算,将MD5值保存到数据库,算法可以用MD5,或者CRC,或者SHA1,这个随便哪个算法都行。

分片还需要支持断点续传,现在HTML5虽然提供了信息记录功能,但是只支持到了会话级,也就是用户不能关闭浏览器,也不能清空缓存。但是有的政府单位上传大文件,传了一半下班了,明天继续传,电脑一关结果进度信息就丢失了,这个是他们的一个痛点。

切片的话还有一点就是在服务器上合并,一个文件的所有分片数据上传完后需要在服务器端进行合并操作。

聊下HTML5吧,怎么说呢,HTML5也就是chrome提供的一个API来实现文件分片,反正基本的需求,小文件用是能用,但是用起来多多少少还是有点别扭,扩展性,安全性,稳定性用户那阵都不太满意,关键是什么,我们是没办法对HTML5进行扩展,个性化和定制化开发的,基本上被谷歌给限制死了,这也是现在国产化的意义,希望能够打破这个限制。不然公司的一些产品和业务不太好开展,总不能用户提个需求,我们就说谷歌Chrome没提供API,所我们就无法开发吧。这不是跟客户扯呢。

1.下载示例

https://gitee.com/xproer/up6-vue-cli



将up6组件复制到项目中

示例中已经包含此目录



1.引入up6组件



2.配置接口地址

接口地址分别对应:文件初始化,文件数据上传,文件进度,文件上传完毕,文件删除,文件夹初始化,文件夹删除,文件列表

参考:http://www.ncmem.com/doc/view.aspx?id=e1f49f3e1d4742e19135e00bd41fa3de



3.处理事件



启动测试



启动成功



效果



数据库



源码工程文档:https://drive.weixin.qq.com/s?k=ACoAYgezAAw1dWofra

源码报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwoiul8gl

OEM版报价单:https://drive.weixin.qq.com/s?k=ACoAYgezAAwuzp4W0a

控件源码下载:https://drive.weixin.qq.com/s?k=ACoAYgezAAwbdKCskc

外话:近来想把网站做下更新,从框架到内容的更新,但又不想放弃SEO的优势,日常工作用到vue.js在SEO方面劣势较多,果断选择了Nuxt.js,苦于国内文章抄袭的非常严重 如某n 某书,最终在稀土找到一篇像样的文章,以头条为平台记录网站改版全过程。

此文章建议在PC端查看,涉及到代码部分,移动端查看确实不方便

Nuxt.js 概要

简而言之,Nuxt.js是帮助Vue.js轻松完成服务端渲染工作的框架。Nuxt.js预设了服务端渲染所需要的各种配置,如异步数据,中间件,路由。它好比是 Angular Universal 之于 Angular, Next.js 之于 React。

如Nuxt.js文档所说,通过对客户端/服务端基础架构的抽象,Nuxt.js 让开发者专注于页面的UI渲染。

静态文件生成器

Nuxt.js的一个重要功能是,通过 generate 命令,生成静态站点。类似于流行的静态生成工具Jekyll。

Nuxt.js 内部依赖

除了Vue.js 2.0之外,Nuxt.js集成了如下模块: Vue-Router, Vue-Meta 和 Vuex (仅在使用 Vuex 状态树配置项 时引入)。 这样的好处在于,不需要手工配置依赖,不需要同时在客户端和服务端配置相同的库。 Nuxt.js在包含如上依赖的情况下,总大小仍然保持在 28kb min+gzip (如果使用了 Vuex 特性的话为 31kb)。

另外,Nuxt.js 使用 Webpack 和 vue-loader 、 babel-loader 来处理代码的自动化构建工作(如打包、代码分层、压缩等等)。

工作原理

当你访问一个基于Nuxt.js构建的页面时,发生了的事情如下:

  1. 当用户访问应用程序, 如果store中定义了 nuxtServerInit action,Nuxt.js将调用它更新store。
  2. 接下来,将加载即将访问页面所依赖的任何中间件。Nuxt首先从nuxt.config.js这个文件中,加载全局依赖的中间件,之后检测每个相应页面对应的布局文件 ,最后,检测布局文件下子组件依赖的中间件。以上是中间件的加载顺序。
  3. 如果要访问的路由是一个动态路由, 且有一个相应的 validate() 方法路由的validate 方法,将进行路由校验。
  4. 之后, Nuxt.js 调用 asyncData() 和 fetch() 方法,在渲染页面之前加载异步数据。asyncData() 方法用于异步获取数据,并将fetch回来的数据,在服务端渲染到页面。 用fetch() 方法取回的将数据在渲染页面之前填入store。
  5. 最后一步, 将所有数据渲染到页面。

下图阐述了 Nuxt.js 应用一个完整的服务器请求渲染的流程,摘自官网:

使用 Nuxt.js 创建一个静态网站

下面让我们动手创建一个基于Nuxt.js简单的静态博客。我们的发送的请求,返回 mock 的JSON数据。

完成下面的例子,你需要了解基础的 vue.js 知识。如果你是个新手,你可以通过Jack Franklin的getting started guide了解 Vue.js 2.0。同时,我将使用ES6语法,你可以参考www.sitepoint.com/tag/es6/ 重温ES6语法。

我们的 Demo 最终效果如下:

本文中代码可参照 GitHub, demo 地址如下:https://github.com/sitepoint-editors/nuxt-ssr-blog/

基础配置

开始使用 Nuxt.js 最简单的方式就是使用 Nuxt.js 团队自己开发的脚手架。我们可以使用 vue-cli 快速创建我们的项目 (ssr-blog):

`vue init nuxt/starter ssr-blog`
# 提示: 如果你没有安装过vue-cli,请先通过npm install -g vue-cli 命令安装vue-cli。

# 之后,我们将安装项目的依赖
cd ssr-blog
npm install

# 现在我们启动程序:
`npm run dev`

# 如果正确启动, 你能访问 http://localhost:3000 
# 展示的页面是 Nuxt.js 模板的初始页面
# 你也可以通过查看页面源代码,验证页面所展示的一切内容,都是服务端渲染好的。

下面,我们简单配置下 nuxt.config.js,包含以下选项:

// ./nuxt.config.js

module.exports = {
  /*
   * Headers of the page
   */
  head: {
    titleTemplate: '%s | Awesome JS SSR Blog',
    // ...
    link: [
      // ...
      { 
        rel: 'stylesheet', 
        href: 'https://cdnjs.cloudflare.com/ajax/libs/bulma/0.4.2/css/bulma.min.css' 
      }
    ]
  },
  // ...
}

在如上配置文件下,我们使用 titleTemplate 字段 title 变量指定文章题目,在渲染之前用title变量值替换掉%s这个占位,填充到titleTemplate

同时,我也使用了 CSS 框架, Bulma, 预设一些样式。通过 link 配置项。

提示: Nuxt.js使用 vue-meta 更新我们的 html headers 信息。所以,我们可以看看 meta 具体的配置项,优化页面 html 信息。

现在,我们可以通过几个步骤,完成博客的页面和功能。

使用 Layouts

首先,我们将为我们所有的页面定义一个通用的基本布局。我们通过修改 layouts/default.vue 文件,更新 main Nuxt.js layout:

<!-- ./layouts/default.vue -->

<template>
  <div>
    <!-- navigation -->
    <nav class="nav has-shadow">
      <div class="container">
        <div class="nav-left">
          <nuxt-link to="/" class="nav-item">
            Awesome JS SSR Blog!
          </nuxt-link>
          <nuxt-link active-class="is-active" to="/" class="nav-item is-tab" exact>Home</nuxt-link>
          <nuxt-link active-class="is-active" to="/about" class="nav-item is-tab" exact>About</nuxt-link>
        </div>
      </div>
    </nav>
    <!-- /navigation -->

    <!-- displays the page component -->
    <nuxt/>

  </div>
</template>

在我们通用的布局里,我们仅仅对页面添加导航栏,我们通过 component进一步完成具体页面模块的定制。你可以查看components-nuxt-link 进一步了解。

在创建布局时component非常重要,它决定具体页面展示的元素。

当然,component也可以做更多事情,比如定义通用组件和错误页面,但是我们的博客很简单,不需要这些功能。强烈建议阅读 Nuxt.js documentation on views ,你可以通过这篇文章了解更多 Nuxt.js 特性。

简单的页面和路由

Nuxt.js 页面是以 单文件组件 形式组织目录结构。 Nuxt.js 自动找到目录下每个 .vue 文件,并添加到页面中。

创建博客主页

我们可以通过修改 index.vue 文件修改主页, 通过 Nuxt.js 创建的文件如下:

<!-- ./pages/index.vue -->
<template>
  <div>
    <section class="hero is-medium is-primary is-bold">
      <div class="hero-body">
        <div class="container">
          <h1 class="title">
            Welcome to the JavaScript SSR Blog.
          </h1>
          <h2 class="subtitle">
            Hope you find something you like.
          </h2>
        </div>
      </div>
    </section>
  </div>
</template>

<script>
  export default {
    head: {
      title: 'Home'
    }
  }
</script>

如前所述,在渲染之前,题目将自动填充至文件。

我们现在可以刷新页面,看看主页的变化。

创建 About 页面

Nuxt.js 还有一个优秀的特性,监听文件夹下文件的更改,所以,在文件更改时,不需要重启应用更新。

来,我们添加一个简单的 about.vue 页面:

<!-- ./pages/about.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">About this website.</h2>
      <p>Curabitur accumsan turpis pharetra <strong>augue tincidunt</strong> blandit. Quisque condimentum maximus mi, sit amet commodo arcu rutrum id. Proin pretium urna vel cursus venenatis. Suspendisse potenti. Etiam mattis sem rhoncus lacus dapibus facilisis. Donec at dignissim dui. Ut et neque nisl.</p>
      <br>
      <h4 class="title is-4">What we hope to achieve:</h4>
      <ul>
        <li>In fermentum leo eu lectus mollis, quis dictum mi aliquet.</li>
        <li>Morbi eu nulla lobortis, lobortis est in, fringilla felis.</li>
        <li>Aliquam nec felis in sapien venenatis viverra fermentum nec lectus.</li>
        <li>Ut non enim metus.</li>
      </ul>
    </div>
  </div>
</template>

<script>
export default {
  head: {
    title: 'About'
  }
}
</script>

现在我们访问 http://localhost:3000/about 看看about页面,无需重启,非常方便。

在主页展示文章列表

我们的首页在没有内容的时候展示如上, 所以下一步,我们要在 index.vue 上添加博客列表这个组件。

首先,我们需要把 JSON 格式的文章保存在服务根目录下。文件可以从 这里下载,或者你可以复制下面的 JSON 到根目录文件夹 posts.json 下:

[
    {
        "id": 4,
        "title": "Building universal JS apps with Nuxt.js",
        "summary": "Get introduced to Nuxt.js, and build great SSR Apps with Vue.js.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "08:00 - 07/06/2017"
    },
    {
        "id": 3,
        "title": "Great SSR Use cases",
        "summary": "See simple and rich server rendered JavaScript apps.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "17:00 - 06/06/2017"
    },
    {
        "id": 2,
        "title": "SSR in Vue.js",
        "summary": "Learn about SSR in Vue.js, and where Nuxt.js can make it all faster.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "Jane Doe",
        "published": "13:00 - 06/06/2017"
    },
    {
        "id": 1,
        "title": "Introduction to SSR",
        "summary": "Learn about SSR in JavaScript and how it can be super cool.",
        "content": "<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
        "author": "John Doe",
        "published": "11:00 - 06/06/2017"
    }
]

提示: 理想情况下,我们应该从通过 API 获取文章数据。

components 存放在 components 文件夹下,我们可以创建如下组件:

<!-- ./components/Posts.vue -->
<template>
  <section class="main-content">
    <div class="container">
      <h1 class="title has-text-centered">
        Recent Posts.
      </h1>
      <div class="columns is-multiline">
        <div class="column is-half" v-for="post in posts">
          <div class="card">
           <header class="card-header">
            <p class="card-header-title">
              {{ post.title }}
            </p>
          </header>
          <div class="card-content">
            <div class="content">
              {{ post.summary }}
              <br>
              <small>
                by <strong>{{ post.author}}</strong> 
                \\ {{ post.published }}
              </small>
            </div>
          </div>
          <footer class="card-footer">
            <nuxt-link :to="`/post/${post.id}`" 
              class="card-footer-item">
              Read More
            </nuxt-link>
          </footer>
        </div>
      </div>
    </div>
  </div>
</section>
</template>

<script>
  import posts from '~/posts.json'

  export default {
    name: 'posts',
    data () {
      return { posts }
    }
  }
</script>

我们引入 JSON 文件充当异步数据,通过 v-for 指令循环列表,取出我们需要的属性填充进组件模板展示。

提示: ~ 符号是 / 的别名。你可以查看 这篇文档 了解更具体的用法。

下面,我们添加 component 到主页:

<!-- ./pages/index.vue -->
<template>
<div>
    <!-- ... -->
    <posts />
</div>
</template>

<script>
import Posts from '~components/Posts.vue'

export default {
  components: {
    Posts
  },
  // ...
}
</script>

添加动态路由

现在,我们为文章页配置动态路由,我们以 /post/1 为例:

为此,我们添加 post 文件夹到 pages 目录下,如下:

pages
└── post
    └── _id
        └── index.vue

我们的程序生成相应的动态路由:

router: {
  routes: [
    // ...
    {
      name: 'post-id',
      path: '/post/:id',
      component: 'pages/post/_id/index.vue'
    }
  ]
}

更新单一发布文件:

<!-- ./pages/post/_id/index.vue -->
<template>
  <div class="main-content">
    <div class="container">
      <h2 class="title is-2">{{ post.title }}</h2>
      <div v-html="post.content"></div>
      <br>
      <h4 class="title is-5 is-marginless">by <strong>{{ post.author }}</strong> at <strong>{{ post.published }}</strong></h4>
    </div>
  </div>
</template>

<script>
  // import posts saved JSON data
  import posts from '~/posts.json'

  export default {
    validate ({ params }) {
      return /^\d+$/.test(params.id)
    },
    asyncData ({ params }, callback) {
      let post = posts.find(post => post.id === parseInt(params.id))
      if (post) {
        callback(null, { post })
      } else {
        callback({ statusCode: 404, message: 'Post not found' })
      }
    },
    head () {
      return {
        title: this.post.title,
        meta: [
          {
            hid: 'description',
            name: 'description',
            content: this.post.summary
          }
        ]
      }
    }
  }
</script>

Nuxt.js通过添加通用方法,简化开发流程。看看我们应该如何在单文件应用中使用它。

  • 路由校验可以通过路由校验方法 validate 校验路由。如果我们的验证路由参数验证数字,如果验证失败,将自动跳转到404页面。如果它返回“false”,Nuxt。js将自动加载404错误页面。想看更多,请查看Nuxt官网。
  • asyncData 方法用于 fetch 数据,并在服务端渲染页面,返回给浏览器。它可以通过多种方式返回数据。我们可以通过多种方式返回数据。在本文中的例子里,我们使用回调函数返回页面。我们使用一个回调函数来返回相同的帖子“id”属性“id”参数的路线。
  • 正如我们之前看到的,我们使用head 的方法来设置页面 header 。这时,我们改变页面你的 title ,添加页面信息到具体页面。

现在我们可以再次访问我们的博客看到所有路线和页面正常工作,并查看页面源代码生成的HTML。我们有一个服务器端JavaScript应用程序呈现功能。

生成静态文件

接下来,我们要生成程序的 HTML 静态文件。

我们需要对 Nuxt.js 做一个小修改,Nuxt.js 默认忽略动态路由。为了生成动态路由文件,我们需要修改 ./nuxt.config.js

我们使用回调函数,返回以后包含动态路由的列表:

// ./nuxt.config.js

module.exports = {
  // ...
  generate: {
    routes(callback) {
      const posts = require('./posts.json')
      let routes = posts.map(post => `/post/${post.id}`)
      callback(null, routes)
    }
  }
}

如果你想查看全部关于 generate 的配置, 可以参照 这篇文档 。

运行如下命令,生成全部页面:

`npm run generate`

Nuxt 将所有生成的页面放到 dist 文件夹下。

使用 Nginx 部署

最后一步,可以使用 Nginx 进行部署,nginx的安装过程此文不再赘述。

结论

generate 命令来生成我们页面的静态文件,假如,我们需要回复。

下一期讲,改版中的踩坑问题。


上一篇:JSP 文件上传
下一篇:html5常用基本标签