Xcode-select 安装

打开 Terminal,直接输入
xcode-select —install

按照步骤直接同意

验证安装成功没有:  再输入

xcode-select --install
如果出现如下,说明安装成功了
xcode-select: error: command line tools are already installed, use "Software Update" to install updates

vue-cli3.0的配置与优化

Vue 作为前端目前三大框架之一,相信大家都不陌生。在国内,由于 Vue 使用简便、学习成本低以及中文资料丰富,深受大量中小型公司的青睐。
Vue 创建项目是使用 vue-cli,目前 vue-cli 已经出到了 3.0 版本,这版本项目结构相当清晰,而且把大量的配置都封装成 @vue/cli-service 包里面,几乎成为开箱即用的脚手架。
然而,需求千变万化,不可能每一个项目都能够在 vue-cli 创建项目之后,就马上运用到业务场景,需要对它进行合适的优化以及修改。
Vue Cli 3.0 新建项目
用 vue-cli 创建项目,看起来十分简单。安装依赖,运行命令就可以了:
$ npm install -g @vue/cli

OR

$ yarn global add @vue/cli
$ vue create hello-world

然而对 vue-cli 配置的优化,就是从这里开始的。首先,我们需要选择自己手动选择配置:

Vue CLI v3.11.0
? Please pick a preset: Manually select features
? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Babel
( ) TypeScript
( ) Progressive Web App (PWA) Support
( ) Router
( ) Vuex
( ) CSS Pre-processors
(*) Linter / Formatter
( ) Unit Testing
( ) E2E Testing

这里需要根据自己的业务需求来选择,我在做项目的时候,基本上必须选择的都是:Babel、Router、Vuex、Linter。其余配置,可以根据自己的需求选择。
选择完之后,会问你是否使用 History Mode 的路由,其实就是路径上面是否出现 #
我个人建议,不要选择 History Mode,因为 # 能够帮你避免很多错误的出现。特别是当项目没有前后端分离地十分彻底的情况下,直接跟路由,可能导致跳转到其他页面。
? Use history mode for router? (Requires proper server setup for index fallback in production) No

然后会选择 Linter 并且选择代码风格,我选择的是 ESLint + Standard,然后选择 Lint on save。

? Pick a linter / formatter config: Standard
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Lint on save
( ) Lint and fix on commit
最后,会问你需要把配置写到单独的文件里面还是写到 package.json 里面,这里选择写到单独文件里面。
原因是我们需要去调整这些配置,如果写到 package 中,不方便调整。
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.?
> In dedicated config files
  In package.json
回车后,会生成下面的目录结构
+--- .browserslistrc
+--- .editorconfig
+--- .eslintrc.js
+--- .gitignore
+--- babel.config.js
+--- package.json
+--- postcss.config.js
+--- public
|   +--- favicon.ico
|   +--- index.html
+--- README.md
+--- src
|   +--- App.vue
|   +--- assets
|   |   +--- logo.png
|   +--- components
|   |   +--- HelloWorld.vue
|   +--- main.js
|   +--- router.js
|   +--- store.js
|   +--- views
|   |   +--- About.vue
|   |   +--- Home.vue
+--- yarn.lock

Vue Cli 3.0 配置 vue.config.js

我们观察一下这里面的目录,发现没有 webpack 的配置,并不是 3.0 版本没有使用 webpack,而是它把 webpack 封装起来了。那么我们怎么用去调整 webpack 配置呢?3.0 版本提供了一个 vue.config.js 的途径。

publicPath

PublicPath 是 webpack 中十分重要的一个配置,这个配置决定了生成资源的路径。我会把 publicPath 在 .env 中配置,development 的时候,配置成 ./;production 模式下,配置成生产环境的路径。

module.exports = {
  publicPath: process.env.PUBLIC_PATH
}

chainWebpack 与 configureWebpack

这两个都可以用来调整 webpack 配置,区别在于 configureWebpack 是简单通过 webpack-merge 对 webpack 进行扩展,而 chainWebpack 则是通过 webpack-chain 插件进行扩展。
具体用哪一个,其实我觉得都可以,看哪一个方便以及熟悉程度。
configureWebpack
configureWebpack 的配置使用正常赋值的形式,往 config 对象中添加或者修改数值即可:

  configureWebpack: config => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
      config.mode = 'production'
    } else {
      // 为开发环境修改配置...
      config.mode = 'development'
    }
    Object.assign(config, {
      externals,
      // 开发生产共同配置
      resolve: {
        extensions: ['.js', '.vue', '.json'],
        alias: {
          '@': path.resolve(__dirname, './src')
        }
      }
    })
  },

chainWebpack
chainWebpack 的配置则是使用链式操作,通过调用方法来进行扩展:

  chainWebpack: config => {
    config.resolve.symlinks(true)
    config.module
      .rule('vue')
      .use('vue-loader')
      .loader('vue-loader')
      .tap(options => {
        options.transformAssetUrls = {
          audio: 'src'
        }
        return options
      })
  },

alias

使用别名是 Vue 开发中常用的技巧,如果大家也讨厌每次都要写无数个 ../ 的话,alias 是必备的配置。
alias: {
  '@': path.resolve(__dirname, './src')
}
配置了之后,在 Vue 的模板中,可以使用 @ 进行路径的引用:
<audio preload="preload" ref="audio" src="@/assets/music.mp3" loop="true" class="hidden"></audio>
import loading from '@/components/loading'
注意 scss 中的图片路径,需要使用 ~@
background: url(~@/assets/index-bg.jpg) no-repeat 0 0/100% 100%;

CSS

CSS 配置的是 Sass 或者 Scss 的属性,其中重要的是 loaderOptions,一般用来定义全局引入的 Scss:
  css: {
    // 是否使用css分离插件 ExtractTextPlugin
    extract: true,
    // 开启 CSS source maps?
    sourceMap: false,
    // css预设器配置项
    loaderOptions: {
      sass: {
        data: `@import "~@/scss/resources.scss";`
      }
    },
    // 启用 CSS modules for all css / pre-processor files.
    modules: true
  },

devServer

devServe 用来配置 webpack-dev-serve 的属性,可以把 host 配置成 0.0.0.0,这样能够以 localhost 以及电脑 IP 访问项目。

devServer: {
    host: '0.0.0.0',
    port: 3000,
    https: false,
    disableHostCheck: true
}

external

配置完这些基本东西之后,需要配置 external。这个属性在 webpack 中十分的重要而且常用,是用来定义外部引入的对象,定义了之后 webpack 就不会把这个对象对应的包打包进去项目文件中。
例如,我们在几个项目中都用到了 Vue,如果不配置 external,每个项目里面都会有 webpack 打包进来的 Vue 包,这样是非浪费服务器资源,而且加载文件大小也相对较大。
而如果配置了 external,我们就可以每次都加载同一个资源路径的 Vue,webpack 不会把 Vue 打包进去。
那怎么样去设置 external 呢?

以加载 Vue 为例,首先我们要在项目中引入 vue.min.js:

<script type="text/javascript" src=".../vue.min.js"></script>
然后,我们需要打开这个 vue.min.js,看一下里面暴露的对象是什么:
/*!
* Vue.js v2.6.10
* (c) 2014-2019 Evan You
* Released under the MIT License.
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).Vue=t()}(this,function(){"use strict";var e=Object.freeze({});function t(e){return null==e}function n(e){return...
一般我们打开之后,就看前两行或者最后两行,看到有 e.Vue 或者 module.Vue 之类的,这个 Vue 就是我们要的对象名字了。
拿到这个对象名称之后,建议在 vue.config.js 的顶部,定义一个 external 对象,来专门负责这些 externals:
const externals = {
  Swal: 'Swal',
  vue: 'Vue',
  vuex: 'Vuex',
  'vue-router': 'VueRouter',
  axios: 'axios',
  qs: 'Qs',
  Mock: 'Mock',
  TweenMax: 'TweenMax',
  TimelineMax: 'TimelineMax',
  AlloyTouch: 'AlloyTouch',
  Transform: 'Transform',
  html2canvas: 'html2canvas'
}
然后在 configureWebpack 中把 external 配置到 webpack 中:
  configureWebpack: config => {
    Object.assign(config, {
      externals,
    })
  },

Vue Cli 3.0 配置 .env

在开始配置的时候,一般会先在根目录新建两个文件:.env.development 以及 .env.production。这两个文件的作用是,当我们使用不同的 mode( development 和 production ) 去构建项目的时候,能够用 process.env 来获取对应文件中定义的配置。
.env.development
VUE_APP_SERVE=true
PUBLIC_PATH=./
VUE_APP_STATIC_PATH=https://www.bootcdn.cn/
注意一点,如果需要把 .env 里面的变量用到项目中,例如 public 中的 index.html 需要在前面加上 VUE_APP。具体的 .env 配置,可以在官网中的 API 查看。
使用这个配置文件有几个好处:
  1. 不需要查看具体代码就能方便修改里面的信息

  2. 方便同事或者其他开发人员查看配置详情

  3. 能够很好地区分开发环境与生成环境

  4. 定了文件之后,能够在项目任何地方使用里面定义的变量

Vue Cli 3.0 配置页面模板

说完上面的配置之后,其实之前所做的很多工作,都是为了配置页面模板所打下的基础。
页面模板是指 public 文件夹中的 index.html 文件,这个 index.html 比普通的 HTML 文件功能强大很多。它是一个会被 html-webpack-plugin 处理的模板,能够使用很多模板插值,条件渲染的语法。

插值

前面说到我们在 .env 中定义了一些静态资源的路径,这里就能够用上了:
<script type="text/javascript" src="<%= VUE_APP_STATIC_PATH %>/vue.min.js"></script>
<script type="text/javascript" src="<%= VUE_APP_STATIC_PATH %>/axios.min.js"></script>
<script type="text/javascript" src="<%= VUE_APP_STATIC_PATH %>/qs.min.js"></script>
使用 VUE_APP_ + 所以定义的变量名,就可以拿到对应的 .env 中的值,这样我们就不需要在 index.html 中写上详细的资源地址,只需要写上后缀就行。

表达式

除了能够插值之外,另一个常用的就是表达式,可以在页面上面使用 if else。我们可以在 .env 中配置一个属性,用来区分当前的状态是开发中,还是线上。然后对应不同的状态,加载不同的资源:

<% if (VUE_APP_SERVE === 'false') { %>
...
<% } else { %>
...
<% } %>

模拟数据

除了使用简单的插值跟表达式以外,前端开发经常需要处理的是模拟数据的情况。在后端没有给我们足够的数据支持的时候,我们需要自己去模拟数据以便测试我们的功能页面。
这里我们可以利用 API 工具加上页面模板,来实现模拟数据。
首先,我们需要找到一款合适的 API 工具,现在有很多开源的文档工具例如:apiDoc、Swagger 和 ShowDoc 等。不过这些都需要团队去学习如何使用,并且需要搭建环境。
我最终选择了 Postman,Postman 中有一个 Mock 功能,这个功能允许我们做数据模拟。

由于后端开发人员几乎都会使用 Postman 来测试自己的接口,所以我们只需要让后端同事导出一份 Postman 的文件,我们导入就有了对应项目的所有接口。
接下来我们要做的是,新建各种例子,然后在 Mock 的地址中,测试一下是否配置成功:

配置好 Postman 之后,我们就可以在页面模板中,把这些接口加入到 Vue 对象里面:
Vue.prototype.$projectOptions = {
  addUserInfo: '<%= VUE_APP_POSTMAN %>/addUserInfo',
}
然后就可以在项目中,用 this.$projectOptions.addUserInfo 来请求 Postman 中我们定义的接口了。
页面模板中还有很多可以优化的配置,像 Preload 和 Prefetch 等等,这些大家可以根据情况来使用,这里就不一样展开了。

结尾

最后给大家一些配置优化的小 Tips:
  • vue-cli 的配置大部分跟 webpack 有关,用好 webpack 就能对 vue-cli 的配置得心应手

  • vue-cli 已经是一个成熟的脚手架了,能够用官网提供的方法解决的情况下,就不用自己去找额外的 Loader 跟插件,避免不必要的麻烦

  • vue-cli 有模板功能,可以把自己配置好的文件弄成模板,下次新建项目的时候,直接用自己的模板 

JavaScript 基础强化:函数的应用(高阶函数)

高阶函数

所谓的高阶函数从通俗的意义上说就是以下两点满足任何一个都是高阶函数:

  • 一个函数的参数是函数 

(){}
(()=>{})
  • 一个函数返回一个函数

(){
    (){}
}

从我们的经验上可以得知,第一种参数是函数的,我们称之为回调方法。第二种返回一个函数的我们可以叫他拆分方法(把一个功能复杂的函数拆分出去) 结合上面两种定义,我们写一个封装功能时常用的例子

before方法:我们希望在调用一个方法之前先调用before函数,然后在调用核心功能函数(一步一个注释,像我这么细心的老大哥可不多咯)

= ()=>{
    console.() }
newCore = .(()=>{
    console.()
})
newCore1 = .(()=>{
    console.()
})

要实现上面的功能的代码其实很简单

Function..= (beforeFn){ ()=>{ beforeFn()
        () }
}

接下来就可以看看效果了,全部是这样的如下:

Function..= (beforeFn) { () => {    beforeFn()()}}= () => {
    console.()}newCore = .(() => {
    console.()})newCore1 = .(() => {
    console.()})newCore()newCore1()

什么?你还想传递参数啊?哎呀 你可真是个小机灵鬼 下面是传递参数的版本

Function..= (beforeFn) {
    (...arg) => { beforeFn()(...arg)}}= (...arg) => { console.(arg)}newCore = .(() => {
    console.()})newCore1 = .(() => {
    console.()})newCore()newCore1()

发布订阅

趁热打铁,我们再来看一个示例,react的事务队列的原理。

可以在某件事的前面和后面同事增加方法,同时也是发布订阅的一种应用。既然说到发布订阅,那就简单说两句(就两句)

  • 特点一 预先定义好一个东西,等某个东西发生的时候执行(这大白话可以吧)

  • 特点二 发布 和 订阅 之间是没有关系的 好了,两句写完了(我也就能总结成这样了,再通俗的我也不知道咋写了)还可以用现实中的一些例子来理解一下, 如:我要在9点钟吃一个苹果

预先定义好一个东西: 吃一个苹果 (也就是订阅)

等某个东西发生再执行:9点钟 (也就是发布)

9点钟和吃一个苹果没有关系 (满足特点二)

遮掩是不是好理解一点???(大概吧 😯)

来说回代码,下面这个例子就是的发布订阅的简单应用了

= (anymethodwrappers) => { wrappers.(wrap => {
        wrap.()})anymethod()wrappers.(wrap => {
        wrap.()})}(() => {
    console.()}[
    {
        () { console.()}() {
            console.()}
    }{
        () { console.()}() {
            console.()}
    }
])

那我们再来看一下另一个例子,用发布订阅处理并发问题,但是在此之前先来看看计数器方式处理并发问题的例子了解一下这个故事的前因后果(想跟我发生故事吗?)

再看看优雅的实现方式,应用了高阶函数,可见高阶函数在实际应用中还是非常广泛的

// 先写一个after函数
const after = (times,fn) => () => --times === 0 && fn() // 返回一个方法 当参数times减少为0的时候执行回调方法
let info = {}
const out = after(2, () => console.log("优雅的", info));

fs.readFile("name.txt", "utf8", (err, data) => {
  info["name"] = data;
  out();
});
fs.readFile("age.txt", "utf8", (err, data) => {
  info["age"] = data;
  out();
});

现在故事情节了解的差不多了吧,我们来看看发布订阅的实现方式吧

// 用发布订阅的方式实现// 用on订阅,emit来发布实现
let e = {
  arr: [],  on(fn) {    this.arr.push(fn);
  },
  emit() {    this.arr.forEach(fn => fn());
  }
};
let info = {};
e.on(() => {  console.log("ok");
});// 想写多少个就写多少个
e.on(() => { // 订阅  if (Object.keys(info).length === 1) {    console.log("这个订阅会在length为1的时候发布");
  }
});
e.on(() => { // 订阅  if (Object.keys(info).length === 2) {    console.log("发布订阅实现", infoOnEmit);
  }
});
fs.readFile("name.txt", "utf8", (err, data) => {
  info["name"] = data;
  e.emit(); //  发布
});
fs.readFile("age.txt", "utf8", (err, data) => {
  info["age"] = data;
  e.emit();  //  发布
});

以上就是发布订阅的标准写法了,应付面试题应该足够了 on-订阅 emit-发布,台下的同学跳起来说了,“这个这个怎么跟Vue里的那个事件啥啥啥的那么像呢”,这位同学请坐下,你说的没错哦,vue里面也有很多发布订阅应用,但是不要急哦,我还没写到呢,后面会在本博客的源码篇里面陆续分析哦。(标签就叫源码)

函数柯里化

函数柯里化属于高阶函数,但什么时候函数柯里化呢,通俗点说就是把一个大函数拆分成多个函数(大概就是不停的返回函数)

真理还是要得实践嘛,所以咱们主要还是看例子,那我们就继续来了解一下故事情节好了

下面我们准备写一个类型判断的方法,一般的类型判断怎么实现呢?

Object.prototype.toString.call() 
// 随便试两个 就两个console.log(Object.prototype.toString.call("123")); // [object String]console.log(Object.prototype.toString.call([123])); // [object Array]

然后我们再看看一般的封装是怎么实现的

const checkType = (content, type) => {  return Object.prototype.toString.call(content) === `[object ${type}]`;
};const b = checkType(123, "Number");console.log(b); // true

功能实现了没有问题,好了故事结束了。 哎!!导演导演,剧本不是这样的!!

好吧 我还以为可以回家吃火锅了呢!

上面的一般封装实现了判断类型的功能是没错的,所有的类型都每次判断的时候手动写入如果写错了就会导致错误,像我这种手残的就很容易敲错啊,老人家太难了,我太难了(尺神经损伤已经好几个月不能打球了,还要奋(划)斗(水)在一线战场搬砖)。

咳咳!说回猪蹄!呸!是主题。恩 主题!

所以我们要尽量不要每次判断都自己写类型,所以我们应用 函数柯里化 的时候到了,先来个基础版的尝尝鲜

// 柯里化实现(简单基础版)const checkType = type => {    return content => {        return Object.prototype.toString.call(content) === `[object ${type}]`
    }
}const isString = checkType('String') // 返回内层函数console.log(isString("123")) // true

到这里我成功应用了函数柯里化把一个方法拆分成了多个方法(这篇文章已经够长了,我就写一个String的就好了)且每个类型就写了一遍,减少了犯错几率

“这也太麻烦了吧,那么多个类型我要写那么多啊,好烦的啊,我很懒的啊”,好这位同学你没有错,错的是这个世界,懒才是我们的第一动力。

所以上面是基础版嘛,简单补充一下就是下面这个样子了

const checkType = type => {    return content => {        return Object.prototype.toString.call(content) === `[object ${type}]`
    }
}const utils = {} // 声明一个工具方法对象const TYPES = ["Number","String","Object","Array","Boolean"] // 行了行了 手疼TYPES.forEach( type => {
    utils[`is${type}`] = checkType(type)
})

也很简单是吧。哎呀!代码可真是太好玩了,我的天啊。

观察者模式

观察者模式的特点有三个

  • 观察者和被观察者是有联系的

  • 被观察者里面存了观察者

  • 观察者模式包含发布订阅

继续看码了,我敲代码千百遍,代码对我如初见~,当然这种事不会的,正所谓码敲百遍,其意自现。没事多敲敲,肯定好处多多啊

// 被观察者class Subject {  constructor() {    this.arr = [];    this.state = "我不饿";
  }  //  通过这个方法将观察者存入arr
  attach(o) { 
    this.arr.push(o);
  }
  setState(newState) { // 通过这个方法来设置状态并通知观察者
    this.state = newState;    this.arr.forEach(o => o.update(newState));
  }
}// 观察者class Observer {  constructor(name) {    this.name = name;
  }
  update(newState) { // 通过这个方法来更新到被观察者的状态
    console.log(`${this.name}  知道了 九儿  ${newState}`);
  }
}let o1 = new Observer("Mopecat"); // 创建一个观察者 Mopecat(我)let o2 = new Observer("Sean");  // 创建一个观察者 Sean(我媳妇)let s = new Subject("九儿"); // 九儿是我家的猫s.attach(o1); // 将o1存入被观察者 也就是Mopecats.attach(o2); // 将o2存入被观察者 也就是Seans.setState("又饿了"); // 更新状态 // 会输出Mopecat  知道了 九儿  又饿了// Sean  知道了 九儿  又饿了

上面就是也一个简单的观察者模式的例子

其中向被观察者中存入观察者的直到状态更新的时候再通知观察者的过程就是发布订阅的应用

而被观察者和观察者是有联系的:被观察者中存了观察者。好像上面的三个特点改成两个就可以了。算了就这吧

解决更新Xcode以后使用Git报错的问题

解决办法:
第一步: 输入下面的命令
guofeng@guofengiMacBook-Air SecondApp$ sudo xcodebuild -license
Password:
第二步: 同意Xcode条款
输入密码后要求你必须同意下面两个Xcode条款.
You have not agreed to the Xcode license agreements. You must agree to both license agreements below in order to use Xcode.
Hit the Enter key to view the license agreements at '/Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf'
按照提示点击Enter键来查看条款.
pple Inc.
Xcode and Apple SDKs Agreement
PLEASE SCROLL DOWN AND READ ALL OF THE FOLLOWING TERMS AND CONDITIONS CAREFULLY BEFORE USING THE APPLE SOFTWARE OR APPLE SERVICES.  THIS IS A LEGAL AGREEMENT BETWEEN YOU AND APPLE.  IF YOU AGREE TO BE BOUND BY ALL OF THE TERMS AND CONDITIONS, CLICK THE “AGREE” BUTTON.  BY CLICKING “AGREE” OR BY DOWNLOADING, USING OR COPYING ANY PART OF THIS APPLE SOFTWARE OR USING ANY PART OF THE APPLE SERVICES, YOU ARE AGREEING ON YOUR OW
By typing 'agree' you are agreeing to the terms of the software license agreements. Type 'print' to print them or anything else to cancel, [agree, print, cancel]
点击空格看到最后,输入agree来同意条款.
agree
You can view the license agreements in Xcode's About Box, or at /Applications/Xcode.app/Contents/Resources/English.lproj/License.rtf
然后就成功了 

Ubuntu 12.04 中安装和配置 Java JDK

先去 Oracle下载Linux下的JDK压缩包,我下载的是jdk-7u4-linux-i586.tar.gz文件,下好后直接解压

Step1:
# 将解压好的jdk1.7.0_21文件夹用最高权限复制到/usr/lib/jvm目录里
sudo cp -r ~/jdk1.7.0_21/ /usr/lib/jvm/

Step2:
# 配置环境变量
sudo gedit ~/.profile
在末尾加上:
export JAVA_HOME=/usr/lib/jvm/jdk1.7.0_21

然后保存关闭,使用source更新下
$ source ~/.profile

使用env命令察看JAVA_HOME的值
$ env
如果JAVA_HOME=/usr/lib/jvm/jdk1.7.0_21,说明配置成功。

Step3:
# 将系统默认的jdk修改过来
$ sudo update-alternatives –install /usr/bin/java java /usr/lib/jvm/jdk1.7.0_21/bin/java 300

输入sun jdk前的数字就好了
$ sudo update-alternatives –install /usr/bin/javac javac /usr/lib/jvm/jdk1.7.0_21/bin/javac 300

$ sudo update-alternatives –config java
$ sudo update-alternatives –config javac

Step4:
然后再输入java -version,看到如下信息,就说明改成sun的jdk了:
java version “1.7.0_04”
Java(TM) SE Runtime Environment (build 1.7.0_04-b20)
Java HotSpot(TM) Server VM (build 23.0-b21, mixed mode)

 

可能会存在的问题:
1.提示缺失libjli.so无法启动……,碰到这个问题是你下载的JavaJDK压缩包不完整,或者你的解压方式不对导致,直接解压到当前路径,然后拷贝到你需要的目录,JDK的安装目录可以随便选择,比如你可以放在HOME目录下,
libjli.so文件在:~/jdk1.7.0_07/jre/lib/i386/jli/libjli.so

2.可能无法配置成功,需要卸载以前安装的OpenJDK,具体可以命令行移除

3.不同版本的JDK,版本号如上修改即可

U盘安装64位CentOS 常见问题与方法

1.抄来抄去,转来转去,人云亦云,避重就轻。

2.U盘在Windows下被UltraISO等软件制作成Linux启动盘后会自动被格式化成FAT格式,导致无法再放得了一个大于4GB的CentOS 64位ISO。当机器顺利引导进安装界面后,由于找不到ISO文件而无法安装。

本人Linux菜鸟,这两天用u盘安装CentOS,在网上查的教程全是原来版本的,都是先单独做启动,再把iso复制进去。这样太麻烦了。最后查了维基发现了个简单方法。

U盘安装64位CentOS 6.5方法

从CentOS 6.5开始直接把iso文件写入U盘就行了。

Windows平台:

1.用UltraISO打开iso(如:CentOS-6.5-x86_64-bin-DVD1.iso)

2.然后点“启动”->”写入硬盘映像”,硬盘驱动器是你的u盘,映像文件安装光盘iso,写入方式是USB-HDD+,点击“写入”按钮。完成后安装u盘就做好了。

Linux平台:

用 dd命令将iso文件写入u盘即可。dd if=iso文件 of=u盘。(如:dd if=/centos-6.5-x86_64-bin-DVD1.iso of=/dev/sdb1)

注:dd命令运行后不显示复制状态,要查看复制状态可以再打开一个终端,输入“while killall -USR1 dd; do sleep 5; done”查看复制状态。

这种方法64位,32位通吃。我安装的就是64位。

注意:只有从CentOS6.5开始才能用这种方法,6.4及以下版本还得用老方法。

可能有许多人已经知道这个方法了,但是网上很多教程还都是老方法。我写出来就是想传播一下,让新手少走弯路。不喜勿喷

=================================

以前的解决方法:在Linux下对U盘进行分区,

—————————–以下摘抄自网络———————————–

1.成为 root 用户。在 U 盘上创建一个小的 VFAT 分区(100M)和一个大的 Linux 分区。标记VFAT 分区为启动分区。
fdisk /dev/sdg
在程序 fdisk 中用“m”命令查看菜单选项。命令的顺序就像下面的这样
(没有“#”后面的注解):
d # 删除已有的分区,必要的话,重复多次以删除多个分区
n # 创建新分区
p # 分区类型为主分区
1 # 分区号为 1
<enter> # 确定分区起始处,采用默认值
+100M # 分区大小为 100M
t # 改变分区类型
1 # 选择分区号为 1 的分区
b # 类型为 VFAT
n # 创建新分区
p # 分区类型为主分区
2 # 分区号为 2
<enter> # 确定分区起始处,采用默认值
<enter> # 确定分区结束处,采用默认值
a # 切换启动标志
1 # 选择分区号为 1 的分区
w # 将所有改变写入磁盘
完成后使用命令 fidsk -l 查看,应该像下面的样子:
Disk /dev/sdg: 7948 MB, 7948206080 bytes
** heads, ** sectors/track, ***** cylinders
Units = cylinders of *** * 512 = ****** bytes
Disk identifier: **********
Device Boot Start End Blocks Id System
/dev/sdg1 * 1 ** ** b W95 FAT32
/dev/sdg2 ** ***** ******** 83 Linux
2.创建文件系统:
mkfs.vfat -n BOOT /dev/sdg1
mkfs.ext2 -m 0 -b 4096 -L DATA /dev/sdg2
完成后安全删除 U 盘,拔下后再插上 U 盘,分区应该被分别挂载
在/media/BOOT和/media/DATA。
3.把 CentOS 的镜像文件以及镜像中的 images 文件夹复制到 ext2 分区:
cd /dir/of/iso/images # 镜像文件的路径
mkdir /media/DATA/centos
mkdir /tmp/cdimage
mount -ro loop CentOS-6.0-i386-bin-DVD.iso /tmp/cdimage
cp -v CentOS-6.0-i386-bin-DVD.iso /media/DATA/centos/; sync
此时最好检查一下复制后的文件的校验和,通常不会有错。
cp -rv /tmp/cdimage/images/ /media/DATA/centos/
4.在 VFAT 分区和 MBR 上安装和配置 syslinux:
syslinux –stupid /dev/sdg1 # 或syslinux -s /dev/sdg1,以系统支
持的为准
dd if=/usr/share/syslinux/mbr.bin of=/dev/sdg # 在 Linuxdeepin
中 mbr.bin 位于/usr/lib/syslinux/mbr.bin,此处以实际为准,mbr.bin
还可能在其他位置
cd /media/BOOT
cp -rv /tmp/cdimage/isolinux syslinux
mv syslinux/isolinux.cfg syslinux/syslinux.cfg
rm -f syslinux/isolinux.bin
rm -f syslinux/vesamenu.c32
cp -v /usr/share/syslinux/vesamenu.c32 syslinux/
umount /tmp/cdimage
<your-favorite-editor> syslinux/syslinux.cfg # 用你最习惯的文档
编辑器在文件的每个区域的“append”后添加语句:
method=hd:sda2:/centos #
5.安全删除 U 盘,关机,再开机,调整为从 U 盘启动。 

—————————–以上摘抄自网络———————————–

以上方法未验证。

自从CentOS 6.5发布以来,有了非常简单的方法,看这里 http://wiki.centos.org/HowTos/InstallFromUSBkey

受此启示,我在Windows下使用UltraISO直接把CentOS 6.5 64位ISO的Disk1(大小超过4GB)烧录到U盘,而不再拷贝ISO到U盘根目录。然后拿到机器插入后USB插槽,开机选择从USB启动,一步一步安装成功。

注:安装过程中到选择存储设备界面时,一定要选择Custom Layout一项,手工创建分区及挂载点,完成后,再选择把MBR信息写到机器的硬盘上(而不是USB盘上,默认是把MBR写到USB盘,导致装完系统,拔掉U盘,无法进入系统启动界面)。

var args=[].slice.call(arguments,1)是什么意思?

  • arguments是什么
我们逐一来看:

[]是什么?

[]是js语法中创建一个新数组的意思,看如下代码:
var a = [];
var b = new Array();
这两种写法并无二致。

[].slice.call是什么?

首先你知道[]是一个数组,那么[].slice是它的一个方法,是一个函数。
它的作用是返回数组中的某一段,看如下代码:
var a = [1, 2, 3, 4, 5];
var b = a.slice(2);
// b是a从2号位开始的片段
// 也就是[3, 4, 5]
在js中,函数本身也是一种对象,也是具有属性和方法的,call就是其中之一。
它的第一个参数,是指定函数执行时的this指针,后面的参数,就是函数执行的参数。
具体的不展开讲,你可以查阅MDN: Function.prototype.call()
看如下代码:
var a = function (n) {
    console.log(this, n);
}
var b = {};
a(1); // log出Window对象, 1
a.call(b, 2); // log出b对象, 2
所以说[].slice.call(arguments, 1)实际上相当于(并不一定等同于):
arguments.slice(1);

arguments是什么

arguments可以看做一个数组。每一个js函数内部都有arguments,它代表传入的参数数组。
看如下代码:
function a() {
    console.log(arguments);
}
a(1, 2, 3); // log出[1, 2, 3]
现在你应该明白了,[].slice.call(arguments, 1)返回的是arguments数组从1号位开始的片段。
看如下代码:
function a() {
    var args = [].slice.call(arguments, 1);
    console.log(args);
}
a('haha', 1, 2, 3, 4, 5); // log出[1, 2, 3, 4, 5]
a('run', '-g', '-b'); // log出['-g', '-b']