GithubHelp home page GithubHelp logo

blog's People

Contributors

aototo avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

blog's Issues

React and Redux 性能,框架优化总结

React and Redux 性能,框架优化总结


React

  1. 利用React Server Render 提高首屏的渲染速度

    • 利于SEO
    • 加速首屏的渲染时间
    • 前后端共享数据源

    使用Reacr.renderToString, React.renderToStaticMarkup

  2. 请将方法的bind一律置于constructor,避免多次bind。

  3. 请只传递component需要的props ,切勿一股脑的<Component {...props} />

  4. 不需要传入状态的component写成const element的形式,这样能加快这个element的初始渲染速度。

  5. dom上设置可被react识别的同级唯一key,否则情况可能不会重新渲染。

  6. 使用`Stateless Functional Component 无状态组件

    • Class并无必要
    • 没有this关键字
    • 无状态组件写起来代码量更少,
    • 便于测试

React 的无状态组件优雅的实现可复用组件的方式。
栗子如下:

const Pane = (props) => <div>{props.children}</div>;

Pane.propTypes = {
  label: React.PropTypes.string.isRequired,
  children: React.PropTypes.element.isRequired
};
  1. 使用pureRender,避免组件没有意义的渲染,配合immutable,减少渲染。

  2. 使用react-css-modules,解决了命名混乱,全局污染以及依赖管理的问题,多人协同开发有时候难免会发生样式上的冲突。
    有个需要注意的地方,下面的2个顺序如果颠倒,就会出错。

@connect(mapStateToProps, mapDispatchToProps)
@CSSModules(styles)

React-router && Webpack

按需加载模块

把这个按需写着这里,本身需要react-router支持,索性就放在这边了。
加载函数:

require.ensure(dependencies, callback, chunkName)

//这里react-router 使用require.ensure,当然了webpack需要配置一下。
<Route path="home" getComponent={(location, callback) => {
  require.ensure([], require => {
    callback(null, require('modules/home'))
  }, 'home')  
}}></Route>

具体看webpack官方
看不懂看这篇webpack 按需打包


Redux

Data

项目数据扁平化,不扁平化带来的问题:

  1. 数据拷贝比较更耗时
  2. 获取数据的时候比较麻烦

通过redux 的combineReducers 可以很好的扁平化数据。如果使用immutable的话整个侵入性非常的强,不仅要修改combineReducers(因为combineReducers实现就是可变的数据),还需要注意获取数据的时候是否是不可变,以免是null。如果使用immutable可以推荐使用redux-immutable。

return {
	...state,
	newData
}

上面这种写法本身也算是一种immutable,但是要求数据层级不能太深。如果数据相对复杂建议使用immutable。

推荐pure-render-decorator方便的来控制组件渲染。

	import pureRender from 'pure-render-decorator';
	@pureRender
	class ...

使用immutable的时候数据转换如下:

  • 可变转不变可以在redux的reducer执行
  • 不变转可变在mapStateToProps and getState()执行

immutableJs
Immutable 详解及 React 中实践
redux-immutable
seamless-immutable体积更小,兼容相对好。只支持Arrays and Objects。


数据筛选reselect

connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])

每当store发生改变的时候,connect就会触发重新计算,为了减少重复的不必要计算,减少大型项目的性能开支,需要对selector函数做缓存。推荐使用reactjs/reselect, 缓存的部分实现代码如下。

export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
  let lastArgs = null
  let lastResult = null
  const isEqualToLastArg = (value, index) => equalityCheck(value, lastArgs[index])
  return (...args) => {
    if (
      lastArgs === null ||
      lastArgs.length !== args.length ||
      !args.every(isEqualToLastArg)
    ) {
      lastResult = func(...args)
    }
    lastArgs = args
    return lastResult
  }
}

If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.

假如state.todos 中todos 提供的数据没有发生改变,就会return之前计算好的结果,这样就可以少去非常多的计算成本。
具体的实现可以去看https://github.com/reactjs/reselect#creating-a-memoized-selector。

具体用法:以下修改reudx官方的的demo

import { createSelector } from 'reselect'

const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos

export const getVisibleTodos = createSelector(
  [ getVisibilityFilter, getTodos ],
  (visibilityFilter, todos) => {
    switch (visibilityFilter) {
      case 'SHOW_ALL':
        return todos
      case 'SHOW_COMPLETED':
        return todos.filter(t => t.completed)
      case 'SHOW_ACTIVE':
        return todos.filter(t => !t.completed)
    }
  }
)

Batched actions

如果我们需要同时发送很多action,比如:

dispatch(action1)
dispatch(action2)
dispatch(action3)

可以减少不必要的计算,推荐用到redux-batched-actions

dispatch(batchActions[action1, action2, action3])

源码很简单
https://github.com/tshelburne/redux-batched-actions/blob/master/src/index.js#L7


Redux DevTools

开发中使用DevTools,建议使用谷歌的插件,不建议在页面结构中插入DevTools。
redux-devtools-extension

在开发环境以及产品环境中移除devTools,避免不必要性能开销和文件大小。
栗子如下:

if (process.env.NODE_ENV === 'production') {
  module.exports = require('./configureStore.prod');
} else {
  module.exports = require('./configureStore.dev');
}

注意: 需要在webpack中使用DefinePlugin 插件。

new webpack.DefinePlugin({
  'process.env': {
    NODE_ENV: JSON.stringify('production')
  }
}),

相关

  • 移动端开发的时候请禁止redux-devtools,会造成卡顿

以往收集的文章,博客

阮一峰的redux 入门
ReactJS组件间沟通的一些方法
聊一聊基于Flux的前端系统
React 性能工程
聊一聊基于Flux的前端系统
React性能工程-- 深入研究React性能调试
A Better File Structure For React/Redux Applications
React服务器端渲染实践小结
dva 项目解决方案
Getting Started with Redux
React 实践心得:react-redux 之 connect 方法详解
REACT&REDUX中SCROLL LIST封装实践
redux-axios-middleware axios兼容ie9,提供promise ,很方便。
深入理解 react-router 路由系统
Immutable 详解及 React 中实践
webpack+ react-router 按需加载

大概的整个项目具体的优化就这些,细节的插件和实施大家自己去看文档。后续继续更新,喜欢的朋友star支持一下。

wechaty centos 系统的使用

在使用wechaty 的时候,由于headless chrome 在linux 环境难安装,所以改用了 docker run

先安装docker
http://www.runoob.com/docker/centos-docker-install.html

拉取镜像的命令:
$ docker pull registry.docker-cn.com/zixia/wechaty

将Wechaty版本号指定到最新的版本
$ docker tag zixia/wechaty:latest

接下来跑就可也了
$ docker run -ti --rm --volume=$(pwd):/bot zixia/wechaty index.js

docker run options

-d, --detach=false :指定容器运行于前台还是后台,默认为false
--volumes-from=[] : 给容器挂载其他容器上的卷,挂载到容器的某个目录
--rm=false : 指定容器停止后自动删除容器(不支持以docker run -d启动的容器)

一般执行后台(ps: -d -m 不能一起使用)
$ docker run -ti -d --volume=$(pwd):/bot zixia/wechaty index.js

查看后台进程
$ docker ps 找到 CONTAINER ID
然后
$ docker logs -f --tail=all CONTAINER ID
就可以查看log 信息了

记住docker 需要绑定端口映射

-p 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。支持的格式有 ip:hostPort:containerPort | ip::containerPort | hostPort:containerPort。

比如
$ docker run -d -p 5000:5000 training/webapp app.js

react router v5 使用history 模块,控制路由

react router 核心 就是使用 history 模块。

so..

可以在 其他需要访问控制路由的地方

var history = require('history');
// 如果你的路由是: example/some/path 这样真实的 URL

import { createBrowserHistory } from 'history'
const history = createBrowserHistory()

// 如果你的路由是 :example/#/some/path

import { createHashHistory } from 'history'
const history = createHashHistory()


history.push(example/some/path)

使用storybook维护,测试react, vue组件

维护,测试组件是一件比较麻烦的事情,必须有使用接口文档,还有开发组件过程中不断测试的问题。storybook是一个能解决这一切问题的好工具。

github storybook地址

  1. 下载
cd my-react-app
npx -p @storybook/cli sb init

会在项目根目录出现几个文件夹

.storybook
stories

需要在.storybook 文件夹下 创建webpack.config.js 去新建loader 插件加载less 资源文件等

const path = require("path");

module.exports = (storybookBaseConfig, configType, defaultConfig) => {
  storybookBaseConfig.module.rules.push({
      test: /\.less$/,
      loaders: ["style-loader", "css-loader", "less-loader"],
      include: path.resolve(__dirname, "../")
  });

  storybookBaseConfig.module.rules.push({
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    include: path.resolve(__dirname, "../")
  });

  storybookBaseConfig.module.rules.push({
    test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/,
    loader: 'url-loader',
    include: path.resolve(__dirname, "../")
  });

  return storybookBaseConfig;
};

./stories/index.stories.js 文件添加组件

具体内容如下
https://storybook.js.org/basics/writing-stories/

插件添加
storybook 有许多可以用的插件比如notes ,还可以支持markdown 文件导入

image

notes 文档写的很清楚了
需要在.storybook 文件夹下 创建插件模块,导入使用


全局的style css 需要自己引入,这点比较麻烦。需要添加配置的在
./.storybook/webpack.config.js
修改添加就可以了


推荐插件 markdown

Vue 初体验

1、过滤器
配合moment.js 日期插件过滤时间, 非常方便

filters: {
    moment: function (data) {
    if (!data) return ''
    return moment(parseInt(data)).format('LL')
    }
}
<span>{{ date | moment }}<span/>

2、 v-if v-show

v-if 是“真正”的条件渲染,v-show 就简单得多基于 CSS 进行切换
如果频繁的切换元素,请使用v-show

3、避免 v-if 和 v-for 用在一起

v-for 的优先级大于 v-if

前端考题:二期

1.Js如何实现继承?

js通过构造函数来类,因为js没有类, 通过原型链实现继承,或者通过复制属性

//创建一个Dog的构造函数, 构造函数大写开头。
function Dog() {
}
// 通过注入prototype属性,来实现对象需要共享的属性和方法
Dog.prototype.call = function() {
    alert("汪")
}
//创建哈士奇,继承狗
function Husky(name) {
   this.name = name;
}

Husky.prototype = new Dog(); //这里是原型链矫正

Husky.prototype.variety = "哈士奇";

var variety1 = new Husky("小哈")

2.浏览器缓存

具体的内容太多了,推荐一篇文章讲的很棒
浅谈浏览器http的缓存机制


3.margin重叠的现象,如何解决?

上下相邻的普通元素,上下margin边距取其中较大的边距值。
比如:

div.top {
   margin-bottom: 30px;
} 
div.bottom {
   margin-top: 30px;
} 
// 此时它们之间还是只有30px。

第一种: 触发BFC就可以解决margin重叠的现象,可以通过以下触发BFC:

  • 浮动元素,float 除 none 以外的值
  • 绝对定位元素,position(absolute,fixed)
  • display 为以下其中之一的值 inline-blocks,table-cells,table-captions
  • overflow 除了 visible 以外的值(hidden,auto,scroll)

关于BFC可以看这篇文章,BFC详说

第二种: 解决margin重叠的可以用padding代替margin


4.解释下浮动和它的工作原理?清除浮动的技巧

在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。浮动元素脱离文档流,不占据空间。

清除浮动可以让元素实现BFC来解决,overflow: hidden 或 overflow: auto 触发浮动元素父元素的 BFC 特性,从而可以包含浮动元素,闭合浮动。

清除浮动的技巧:

1.使用空标签清除浮动,定义css clear:both. 问题增加了无意义标签。

2.浮动元素的父标签添加css属性overflow:auto; zoom:1; zoom:1用于兼容IE6。

3.使用after伪对象清除浮动。代码如下

.clearfix {
    zoom: 1;
}

.clearfix:after {
     visibility: hidden;
     display: block;
     font-size: 0;
     content: " ";
     clear: both;
     height: 0;
 }

5.利用函数编程**写一个add(1)(1,2,3)()

利用函数编程的惰性求值, 下面是我写的

function add() {
  //把arguments转成array对象
  var _args = Array.prototype.slice.apply(arguments);

  return function() {
    if ( arguments.length > 0 ) {
      var newArgs = Array.prototype.slice.apply(arguments);
      _args = _args.concat(newArgs);
      return add.apply(null, _args)
    }

    return _args.reduce(function(a, b) {
      return a + b;
    })
  }
}

var a = add(1,2,3)(2)

Js 性能优化

Js性能优化小结

谨慎使用闭包

由于闭包[[Scope]] 属性包含与执行环境作用域链相同的对象引用,函数活动对象本来会随着执行环境完毕后一同销毁,但引入闭包,对象无法被销毁。

闭包会造成更多的内存开销,同时IE下还会造成内存泄露。

缓存对象成员

在同一个函数中,如果存在多次读取同一个对象成员,可以在局部函数中保存对象,减少查找。

function getWindowWH() {
	var elBody = document.getElementsByTagName('body')[0];
	return {
		width: elBody.offsetWidth,
		height: elBody.offsetHeight
	}
}

同时也解决了属性越深,访问速度越慢的问题。

DOM 操作

访问DOM的次数越多,代码运行的速度越慢,统一的保存结果最后在一并输出。 例子:

 function innerHTMLLoop() {
	 var content = '';
	 
	 for (var count = 0; count < 10000; count++){
		 content += 'a';
	 }
	 
	 document.getElementById("idName").innerHTML += content;	 
}

重绘(repaints)与重排(reflows)

当页面布局和几何属性改变时就需要"重排"

避免在修改样式的过程中使用 offsetTop, scrollTop, clientTop, getComputedStyle() 这些属性, 它们都会刷新渲染队列

  • 最小化重绘和重排, 尽量一次处理

    1. 使元素脱离文档流(隐藏元素
    2. 使用 documentFragment
    3. 将原始元素拷贝到一个脱离文档的节点中, 修改副本, 完成后再替换原始元素)

事件委托

当有很多元素需要绑定事件的时候,我们一个一个的去绑定事件是有代价的的,元素越多应用程序越慢。事件绑定不但占用了处理时间,并且追踪事件需要更多的内存,有时候很多元素是不需要,或者是用户不会点击的,所以我们需要使用事件委托来解决没有必要的资源消耗。

例子: 我们需监听li的click事件,通过冒泡事件来获取点击的对象。

<ul>
	<li index='1'>1</li>
	<li index='2'>2</li>
	<li index='3'>3</li>
</ul>
var ul = document.getElementById('ul');

ul.addEventListener('click', function(e) {
  var now_index = e.target.getAttribute('index');
  ...
})

循环性能

一般的for语句可能很多人都这么写

for(var i = 0; i < array.length; i++){
	....
}

每次循环的时候需要查找array.length,这样不但很耗时,也造成性能损失。只要查找一次属性,存储在局部变量,就可以提高性能。

for(var i = 0, len = array.length; i < len; i++){
	....
}

重写后的循环根据数组的长度能优化25%的运行时间,IE更多。所以平时书写的时候还是要多加注意。同时还是要避免使用for-in循环。

条件语句

if-else 对比 switch, 当条件语句较多的时候switch 更易读,运行的要更快。所以但条件少的情况下使用if-else,当条件增加时,更倾向于switch,会更佳合理。

避免使用构造器

通过避免使用eval()和Function()构造器来避免双重求值带来的性能消耗。比如:

eval('2 + 2');  

使用 Object/Array 直接量

直接量的速度回更快。

//bad
var myObject = new Object();
myObject.name = "xxxx";

//good
var myObject = {
	name: "xxxx"
}

npm-audit

https://docs.npmjs.com/cli/audit.html

npm audit 是 npm 6 新增的一个命令,可以允许开发人员分析复杂的代码并查明特定的漏洞。在刚刚发布的 npm 6.1.0 版本中,开发团队对该命令进行了完善。现在可使用 npm audit fix 子命令自动修复检测到的漏洞,而不必再自己进行跟踪和修复。

当你npm audit的时候 会提示:
found 15 vulnerabilities (6 low, 8 moderate, 1 high) in 2810 scanned packages runnpm audit fixto fix 7 of them.

会提示 6 low, 8 moderate, 1 high

出现 high 就要注意了

$ npm audit fix --force

执行下命令,如果还有存在 high , 需要更替包的方案


yarn 也可以使用

更新yarn到 1.16.x 版本

执行
yarn audit 检查包 yarn audit fix -- force 修复 (删除已经存在的yarn.lock 和 node_module 包)

微信小程序 Component 组件内 无法覆盖第三方组件样式

这个一开始没注意,踩了坑!
反正没办法通过Component 定义的组件去修改引入第三方组件的样式,除非用标签选择器!不过这种做法也不好。

这是微信的相关的文档描述:https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/wxml-wxss.html

可以在外层的app.wxss 修改。也不好管理

或者设置下面值

-isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值)
apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用。)

或者使用 外部样式类
externalClasses

杂文系列-webpack引入静态资源

杂文系列-webpack静态资源-2017-8-28

基于webpack && html引入静态资源的几种方法

GitHub博客 https://github.com/asd0102433/blog 喜欢的start,长期更新


我们需要在页面插入图片:

index.html

<img src = 'assets/images/xxx.jpg' />

因为这个图片webpack并没有被加载进来,会得到404的结果。

通常的做法是在对应的js中require该资源

require('./assets/images/xxx.jpg');

这样就在内存中可以访问到内存中图片。(但是要注意文件加载的路径问题,最简单的就是按照构建的生产环境的资源路径)还要注意图片是否有hash值。

以下是js输出的图片资源路径

./images/acb790246029d8f127588eacd3005fbei1.jpg

比如最后生成的资源路径。页面也需要按照这样引入,显然是不可能的。

<img src = './images/acb790246029d8f127588eacd3005fbei1.jpg' />

当一个项目静态图片多的时候如何处理?比如一个不需要后端图片数据的前端活动页面?接下来有三种方法。

使用CopyWebpackPlugin

copy-webpack-plugin
把静态资源都拷贝到构建目录。使用方法也非常简单。

const CopyWebpackPlugin = require('copy-webpack-plugin');
Usage
new CopyWebpackPlugin([
	{ from: path , to: bundle_path }
])

这样就可以在页面中愉快的使用目录地址了(注意的是资源路径按照最终构建完成的目录)
如下是构建完毕后的目录

| dist
| ---- | images
| ---------- | xxx.jpg
| ---- | index.html

<img src='./images/xxxx.jpg' alt="">

CopyWebpackPlugin 能把全部静态资源全部拷贝过去,从而优化webpack在构建上面的速度,减少时间,是一个不错的优化方案,可以建议使用。

在 html文件中使用require

<img src='<%= require("./assets/images/xxx.jpg") %>'>

这种方法跟import是一样的,我们可以直接使用它,还可以配置alias,来简化这个path的名字

resolve: {
    alias: {
      imageBase: '../app/assets/images'
    },
 },

设置后页面中可以使用alias来代替路径问题

<img src='<%= require("imageBase/xxx.jpg") %>' >

同事css也可以使用,配合~

background: url('~imageBase/xxx.jpg')

此时~告诉webpack这是一个module,而不是相对路径。
webpack-contrib/css-loader#49
alias的使用同样也可以让构建的速度提升,直接锁定资源的地址,从而减少搜索的耗时。

使用html-loader

目前比较省力的方案

{
    test: /\.html$/,
    loader: 'html?attrs=img:src img:data-src'
}

它默认处理html中的<img src="image.png">为require("./image.png"),
同时还处理了hash文件名的问题。但是html-loader不支持下划线模板。会导致HtmlWebpackPlugin的变量模板失效。
具体问题:
jantimon/html-webpack-plugin#174
jantimon/html-webpack-plugin#223


以上的方法可以结合使用,比如2,3中使用的话,不但简化了图片的路径问题,还优化了构建速度,同时引入静态资源也非常的简单。

例子:

<img src='~imageBase/xxx.jpg' alt="">

基于socket.io的实时在线HTML5游戏思路

有2个月没怎么写文章了,这次项目做了一个HTML5的在线实时游戏,游戏是基于
Socket.IO架构写的,网上的资料也很多,比较零散,啰嗦。在这里总结下整个流程,开拓思路。(PS: 主要是整个流程的思路,不讲框架的基础用法)

  1. 创建node服务端

    var app = require('http').createServer(handler)
    var io = require('socket.io')(app);
    var fs = require('fs');
    
    app.listen(8080, function() {
      console.log('Listening at localhost:8080')
    });
    
    var room = {};
    // 客户端连接后处理事件
    io.on('connection', function(client) {
        ....  
    });    
  2. 创建游戏房间

    // 客户端:随机生成一个房间的keyId,然后发送到后端
    var socket = io.connect();
    socket.emit('create', roomId);
    
    // 服务端:
    io.sockets.on('connection', function(client) {
        //接受create事件 ,并且加入roomId
      client.on('create', function(roomId) {
        // 可以在这里记录roomId, 并且保存到rooms数组里
        // rooms.push(roomId)
        client.join(roomId);
      });
    });
  3. 生成房间链接,或者二维码

    可以使用qrcodejs来生成二维码。具体的步骤就是生成一个带有code的Url。玩家根据Code来判断是否有房间。有则加入,没有则创建。

    生成Url

    new QRCode(document.getElementById("qrcode"), location.href + 'play.html?id=' + ID);
  4. 玩家加入房间

    通过扫描二维码,得到location.search里roomId,然后发送到后端,加入房间

     var roomId = location.search.replace('?id=', '');
    
     // 客户端: 得到room id
     socket.emit('join', {
         roomId: roomId,
         ...
     });
    
     // 服务端
     io.sockets.on('connection', function(client) {
         ...
         client.on('join', function(data) {
             client.join(data.roomId);
             // 通知room房间里面的其他玩家
             io.in(data.roomId).emit('new_player', data);
         });
         ...
     }
    

    服务端接收join事件,客户端加入房间后,同时通知房间里面的其他玩家。

  5. 通过获取客户端request ,获取玩家请求的room id

     //node.js
     var url = client.request.headers.referer
    

    每次玩家发送一次请求的时候,无需每次都带上房间的id。

  6. 创建玩家数据

    每个玩家都会生成一个固定的user Id, 保存在server 和 客户端的localStorage 里面

     user = {
         id: null,
         rooms: [
             { roomId: null, data: null}
         ]
     }
    

    每一个玩家在连接后端的时候都可以创建一份数据,用来恢复掉线后的数据。


具体大概的流程都在上面了,socket的具体使用可以参考官网的demo, 这边只是一个大概的流程思路。具体的逻辑代码也没什么好讲的,比如玩家做了动作
emit (客户端) -> on (服务端) - emit -> on(客户端),很简单的。

chrome 版本61之后 $('body').scrollTop() 会获取到0

如果使用$('body').scrollTop() 获取的值是0,谷歌Translate翻译插件就是这样失效的。
使用documentElement || body 来兼容。

let scrollTop = document.documentElement.scrollTop || document.body.scrollTop

或者使用

$(window).scrollTop()

之前使用$('body').scrollTop() 的插件,需要修改了

compose and middleware 源码分析

Redux compose and middleware 源码分析

花了一天时间看了redux 几个function的源码感触颇深,接下来总结下源码的作用。

compose.js

https://github.com/reactjs/redux/blob/master/src/compose.js#L21

return funcs.reduce((a, b) => (...args) => a(b(...args)))

一头雾水啊,函数编程功力不够,第一眼懵逼,细细琢磨才领悟其中的奥妙。
先不谈奥妙之处我们先写段代码,慢慢解析。

下面代码我们需要组合2个函数,构建成一个新的函数

var f1 = function(a) {
	return a * 10;
}

var f2 = function(a) {
	return a + 1;
}

function compose(f1, f2) {
	return function(x) {
		return f1(f2(x))
	}
}

var number = compose(f1, f2)(4) 
number == 50 // true

让代码从右向左运行变成f1(f2(x)),4 -> f2 -> f1 -> 50,当然了你也可以在内部reverse一下让函数从第一个开始执行。
接下来我们看下实际运用的compose

let compose = (...funs) => (result) => {
	for (var i = funs.length - 1; i > -1; i--) {
      result = funs[i].call(this, result);
    }
    
	return result;
}

var number = compose(Math.round, parseFloat)('5.8');
// number => 6

parseFloat函数return的结果作为Math.round函数的参数
Math.round(parseFloat('5.8'))`

我们在回到redux compose.js

funcs.reduce((a, b) => (...args) => a(b(...args)))

跟上面的compose 的原理其实是一样一样的,就是写法很精妙。
先分析reduce 这个method

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

reduce()把返回的结果继续和序列的下一个元素做累积计算,其效果就是上面这样。

拆分上面的源码步骤如下:
第一次 返回 (...args) => a(b(...args) 且与下一个c函数做计算
第二次 a 等于 (...args) => a(b(...args) ,b 等于 c 这个function , 然后再一次做 (...args) => a(b(...args)) 计算,就形成了

	 (c(...args)) => a(b(...args))
	 //返回 a(b(c(...args)))

第三次也是如此

	(d(...args)) => a(b(c(...args)))
	//返回 a(b(c(d(...args))))

结果就如注释的一样

	// from right to left. For example, compose(f, g, h) is identical to doing
	 // (...args) => f(g(h(...args))).

到这里我们这点了compose 的实现原理,接下来我们看下applyMiddleware.js
中如何实现中间件的。
源码

	let dispatch = store.dispatch
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

然后我们看下middleware函数的签名
({ getState, dispatch }) => next => action => {...}

  1. 第一步把middlewares数组里的函数带着middlewareAPI这个参数都挨个执行个遍且,且保存在chain数组中。也就是middleware中的第一个参数,返回 next => action => {...}

  2. 第二步 就是上面composeJs 中组合chain中的函数。变成f1(f2(f3(store.dispatch))),并且最终保存在dispatch 变量中。里面的函数最终会返回action => {...} 这个函数 作为上一个函数的next参数保存在上个函数的scope中,所以每个middleware 中必须执行next(action)才能进入下个middleware。而最后一个middleware传入的next正是原始的store.dispatch。

     //演示代码
     const f1 = ({ getState, dispatch }) => next => action => {
     	...
     }
     
     compose(f1)(store.dispatch)  
     dispatch = (action) => {  /* next = store.dispatch */ }
     
     compose(f1, f2)(store.dispatch) 
     // f1 = next => action => { ... }
     // (action) => {  /* next = store.dispatch */ }  作为f2的返回值赋值给next 参数
     //其中的next就是f2的函数体
    

基本的源码分析到此就差不多了,要注意的是为什么异步middleware中可以使用dispatch让action在重新执行一遍。因为其中的dispatch就是源码中的

dispatch = compose(...chain)(store.dispatch)

这样异步middleware就非常容易理解,也很好巧妙的实现异步流。而next则是进入下一个middleware。如果在middleware里面滥用store.dispatch,就会造成无限的循环。

	const f2 = store => next => action => {
		next(action) //进入下一个middleware
		store.dispatch(action) //从左边的第一个middleware开始
	}

redux-thunk的实现就是判断action是否是function,如果是就执行action(),action就可以是一个异步请求的函数,具体可以看https://github.com/gaearon/redux-thunk/blob/master/src/index.js#L3的源码!

就写到这里,函数编程的巧妙还需多多学习呀,不足之处还请指正。

参考
Middleware

git 详细的操作指南笔记(从零开始)

设置

安装git后我们需要配置一下,告诉git我们的基本信息等等..一般在用户范围内去配置 git ,也就是在 global 范围。

  • global 全局设置

      $ git config --global user.name 'xxxx'
      $ git config --global user.email 'xxxx'
    

    同时我们可以用 $ git config --list来查看我们的设置,
    如果需要修改重新设置使用

      $ git config --unset --global user.name
    

    全局范围的配置会保存在当前用户的主目录下面 叫.gitconfig 的文件里面。我们可以使用cat ~/.gitconfig来查看

      $ cat ~/.gitconfig
    
    设置别名-alias

    通过别名可以简化经常输入的内容,别名的配置也可以在gitconfig里面查看

      git config --global alias.cm commit
    

    这样当你在commit 的时候 就可以 使用 git cm -m 'xx'来代替了。

  • 全局忽略文件

    有时候我们需要去忽略系统生成的文件比如mac 下的.DS_Store,我们可以在全局设置gitignore

      git config --global core.excludesfile ~/.gitignore_global
    

    然后在gitignore文件里面写入需要忽略的文件

      .DS_Store
    

    你可以参考下面的链接来看更多要忽略的文件
    https://gist.github.com/octocat/9257657

    如果在项目中可以创建名为.gitignore,为每个项目配置。具体忽略的文件可以查看上面的链接

    如果你想忽略掉已经跟踪的文件,可以使用 git rm cached选项,再指定一下文件名称,这样可以取消跟踪指定的文件。


Git 基础命令

  • 初始化Git

    控制和管理项目需要初始化git

      $ git init
    
  • 查看当前修改 -git status

      $ git status
    
  • 查看提交的信息 -git log

      $ git log
      $ git log --oneline //显示在一行
      $ git log --oneline --before = '2017-01-01' //显示2017-01-01的提交
    

你可以使用git help log 查看更多信息

  • 提交 -git commit

    添加新的文件,或者修改已有的文件,之后使用commit告诉 git 你做了哪些事情。可以使用git log 查看以往的提交。

      $ git commit -m '这里来描述事情'
    
  • 对比差异 -git diff

    如果你修改了文件,你想查看自己目前修改的了哪些,可以使用

      $ git diff
    

    如果想跟暂存区里面的文件进行对比(暂存区就是git add 文件),可以用

      $ git diff --staged
    
  • 重命名,移动 -git mv

    git mv可以重命名或者移动文件和目录

      $ git mv xx1.js xx2.js //重命名
      $ git mv xx1.js js/ //移动文件
      $ git mv js asset/ //移动目录
    
  • 删除文件 -git rm

      $ git rm fileName
    

    如果你想删除暂存区的可以使用

    $ git rm --cached fileName

  • 撤销操作 -git amend

    如果提交commit之后发现有遗漏的文件可以使用该命令,具体流程

      $ git conmmit -m "xxx.js"
      $ git add "xxx2.js"
      $ git commit --amend --no-edit
    

上面的三条命令最终只是产生一个提交,第二个提交命令修正了第一个的提交内容。提交之后你就可以使用git log --name-status提交了哪些文件

  • 修改撤销文件 -git checkout

    比如你删除了index.html,使用以下命令恢复文件,也可以恢复之前修改过的

      $ git checkout  -- index.html 
      $ git checkout .  //会取消所有本地的
    
  • 撤销已经add的文件 -git reset

有时我们会不小心git add,取消某些add的文件。(还原暂存区)

    $ git reset HEAD fileName
  • 撤销已经commit的文件 -git reset

    假如你的项目已经commit了,可以用到该命令恢复到指定的commit。
    第一步 git log --oneline

      5c422a3 add html
      6804500 Delete a.css
    

    第二步

      $ git reset id  //id 是指上面commit 的id
    

    第二种方法,更快捷的

      $ git reset HEAD^ // 回退到上一个commit, 默认--mixed
    

    git reset 有3个选项,
    --soft 不会影响到工作目录还有暂存区里的东西
    --hard 工作目录,暂存区直接重置到指定的提交状态
    --mixed 默认选项,会把暂存区里的东西重置到指定提交状态,并且指针指向这个提交。

    一般情况, 如果你发现commit文件是存在bug情况,你只需要修改文件代码,那就用默认的mixed,hard会重置文件的内容到指定的commit,也就是说你的之前写的代码会被重置删除掉,切记。

      git reset [--soft | --mixed | --hard] [-q] [<commit>]
    
  • 保存修改恢复进度文件 -git stash

    stath 可以让工作进度先保存起来,需要用到的时候在恢复。
    场景: 你修改文件app.js ,然后你git add file后你暂时不想跟后面的文件一起commit,那么就可以先储存起来

      $ git stash save "这里可以是说明"
    

    查看保存的进度,或者显示进度的目录

      $ git stash list
      $ git stash show -p stash@{..}
    

    恢复进度(取出之前保存的进度)

      $ git stash apply stash@{..}
    

    删除不需要的进度

      $ git stash drop 或者 后面跟上stash@{..}代号
    

分支branch

Git 分支 - 何谓分支

  • 查看,创建项目分支

      $ git branch
      $ git checkout -b [name_new_branch] 
    
  • 删除分支

      $ git branch -d [name_branch] 
    
  • 切换分支

      $ git checkout [branch-name]
    
  • 对比分区的区别

      $ git checkout branch
    
  • 分区合并

      $ git merge [your_branch]
    

    注意:如果你合并master ,首先需要切换到master 分支下进行合并。

  • 分区对比

      $ git diff [branch]..[branch]
    
  • 重命名branch

      $ git branch -m [branch] [new_name_branch]
    

远程 remote

  • 添加远程地址

      $ git remote add origin [git_address]
    
  • 分支推送到远程的版本

      $ git push origin master
    

具体很多细节去多看看深入的实战


git log 命令支持选项参考这里

选项 说明
-p 按补丁格式显示每个更新之间的差异
--word-diff 按 word diff 格式显示差异。
--stat 显示每次更新的文件修改统计信息。
--shortstat 只显示 --stat 中最后的行数修改添加移除统计。
--name-only 仅在提交信息后显示已修改的文件清单。
--name-status 显示新增、修改、删除的文件清单。
--abbrev-commit 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符。
--graph 显示 ASCII 图形表示的分支合并历史。
--relative-date 使用较短的相对时间显示(比如,“2 weeks ago”)。
--pretty 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式)。
--oneline --pretty=oneline --abbrev-commit 的简化用法。

更多的深入了解可以去git api查看
参考
git 官网
5.2 代码回滚:Reset、Checkout、Revert的选择
git 中文
Create a new branch with git and manage branches

ant-mobile & create-react-app 自定主题 高清方案

官方文档:
https://mobile.ant.design/docs/react/customize-theme-cn

问题:ant-mobile 使用 px 作为样式基本单位,在750 vw 方案下,内容会被缩小,需要把基础变量提升2倍,以便支持高清模式。

制定方案:使用 modifyVars 的方式来覆盖变量。

适用:webpack 3+ 以上

代码
第一步:配置 babel-plugin-import 确保加载 antd-mobile less 文件, package.json 如下

style 为true时候,引入 less 文件,等于 'css' 时候 加载编译好的 css 文件,这里要设置less,才可以修改变量

{
    ...
    "plugins": [
        ["import", {"libraryName": "antd-mobile", "style": true}],
    ]
}

二步:修改les-loader , 不同的webpack 会不一样的配置,如果是create-react-app 生成的项目,需要修改webpack.config.js 中 getStyleLoaders函数

{
  loader: 'less-loader', 
  options: {
    modifyVars: {
      "hd": "2px"
    },
   javascriptEnabled: true // 不开启会报错
 }
},

// 如果是create-react-app, 进入webpack.config.js, 找到 getStyleLoaders函数

if (preProcessor) {
      let options = {
        sourceMap: isEnvProduction && shouldUseSourceMap
      }
      if (preProcessor === 'less-loader') {
        /* 导入 antd mobile Theme 主题 */
        options = {
          ...options,
          modifyVars: antdMobileTheme,
          javascriptEnabled: true
        }
      }
      loaders.push(
        ...
        {
          loader: require.resolve(preProcessor),
          options: options
        }
       ...
      );
    }

使用 Optional Chaining

它现在处于 stage-1 阶段。你可以在.babelrc文件中引入 @babel/plugin-proposal-optional-chaining插件来使用它。

可以 这样获取数据

const data = myObj?.value?.xxxxx

MobX.js 使用笔记

mobx 笔记

API

observable 和 autorun

observable 用来观察对象,数组,类等数据结构

使用方式:

例子:

import {observable} from 'mobx';

var name = observable('aotu');

//ES7 装饰器的使用
class Aotu {
    @observable name = 'aotu'
}

使用autorun去观察依赖的相关数据的变化(下面demo中只有name的值发生改变才会触发该函数

var disposer = autorun(() => console.log(name.get()));

更多匹配类型应用转换规则
https://cn.mobx.js.org/refguide/observable.html

Computed values

创建计算值, 并返回,纯函数形式,内部做了优化,当参数相同时候不从新计算

// ES7 装饰器的使用
import {observable, computed} from "mobx";

class Sum {
    @observable price = 1;

    @computed get total() {
        return this.price * 10;
    }
}

// 不使用 decorate
import {decorate, observable, computed} from "mobx";

class Sum {
    price = 1;
    get total() {
        return this.price * 10;
    }
}

decorate(Sum, {
    price: observable,
    total: computed
})

action

把一些修改状态的fn放在action里面,以便更好的管理代码,(严格模式开启,限制其他地方随意改变需要的值,降低不确定性)。

例子

import {observable, action} from 'mobx';
useStrict(true);
class Store {
  @observable number = 0;
  @action add = () => {
    this.number++;
  }
}

const newStore = new Store();
newStore.add();

runInAction

runInAction 其实就是action的语法糖action(fn))()
主要用在异步的回调时候立即执行,action只会影响当前执行的动作。

例子:

useStrict(true);

class Store {
  @observable userName = '';
  @action load = async () => {
    const data = await getUserData();
    runInAction(() => {
      this.userName = data.userName;
    });
  }
}

Autorun

所提供的函数总是立即被触发一次, 而当观测到的数据发生变化的时候,如果变化的值处在autorun中,那么autorun就会自动执行。

class User {
  @observable name;

  @action
  setName(name) {
    this.name = name
  }
}

let user = new User()
user.setName('aotu')

//每次修改打印name ,值相同不打印
autorun(() => console.log(user.name))

Reaction

Reaction是autorun 的变种,对于如何追踪 observable 赋予了更细粒度的控制。接收两个函数参数,第一个(数据 函数)是用来追踪并返回数据作为第二个函数(效果 函数)的输入。 不同于 autorun 的是当创建时效果 函数不会直接运行,只有在数据表达式首次返回一个新值后才会运行。 在执行 效果 函数时访问的任何 observable 都不会被追踪。

class User {
  @observable user = {
      name: '',
      age: 0
  };

  @action
  setName(name) {
    this.user.name = name
  }
  
  @action
  setAge(value) {
    this.user.age = value
  }
}

//只有name发生变化的时候,才会执行该函数,age发生改变则不会运行
let userReaction = reaction(
  () => user.name,
  (value) => console.log(value)
);

reaction 返回一个清理函数,可以在不需要的时候,运行返回函数,节省内存开销

//直接执行
userReaction()

后续更新...
参考:https://cn.mobx.js.org/

使用rem 和 vw布局的不同

Note: If you do not specify a font size, the default size for normal text, like paragraphs, is 16px (16px=1em).

so :1rem = 16px
设置 html { font-size: 20px } so 1rem = 20px

rem 布局

假如设计稿750,设置1rem 为 100px

// 换算rem
let baseFontSize = 100
px2rem (num) {
 return num / 100
}

// 动态修改根类html 的 fontsize
const baseDesign = 750
changeView () {
  fontSize = window.innerWidth / 750 * baseFontSize
}

vw布局

设计稿 750 px, 1w 等于 7.5 px

const baseDesign = 750
px2vw (num) {
   return = (num / baseDesign * 100) +'vw'
}

aotm 不同代码风格的缩进问题...

使用 Editorconfig 来解决不同人的缩进风格

atom 编辑器
https://github.com/sindresorhus/atom-editorconfig

需要在项目根目录创建一个.editorconfig文件

下面是一个简单的demo.(ps: 这玩意要重启一下,很玄乎)

root = true

[*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8

[*/*]
indent_style = tab
indent_size = 4
end_of_line = lf
charset = utf-8

[*.{json,yml}]
indent_size = 4

[*.md]
trim_trailing_whitespace = false

修改 indent_size 数值可以修改缩进的大小。

ps: atom的缩进设置在 * setting -> setting -> Editor Settings * 里面, atom-editorconfig 插件里也需要修改Tab Length

支付宝小程序底部安全边距iPX方案

手机型号 支付宝的版本标识
iPhone X iPhone10,3 / iPhone10,6
iPhone XR iPhone11,8
iPhone XS iPhone11,2
iPhone 11 iPhone12,1
iPhone 11 Pro iPhone12,3
iPhone XS Max iPhone11,6 / iPhone11,4
iPhone 11 Pro Max iPhone12,5
iPhone 12 iPhone13,2
iPhone 12 Pro iPhone 13,3

解决方案
通过 my.getSystemInfo 获取设备信息,可以获取最新的一个 isIphoneXSeries 来确定是否是X系列

const sysInfo = getSystemInfoSync()
if (sysInfo.isIphoneXSeries === true) {
	isIpx = true
}

方案二
目前更新的IPhone 12,在sysInfo.model: iPhone13,2, iPhone13,3(真是奇怪,居然这样的命名)

const sysInfo = getSystemInfoSync()

if ([
    'iPhone10,3',
    'iPhone10,6',
    'iPhone11,8',
    'iPhone11,2',
    'iPhone12,1',
    'iPhone12,3',
    'iPhone11,6',
    'iPhone11,4',
    'iPhone12,5',
    'iPhone13,2',
    'iPhone13,3',
  ].includes(sysInfo.model)) {
    isIpx = true
  }
}

推荐使用 方案一,但二的方案也要在具体的代码里面做兼容操作。

ES6 promise & async

Promise

Promise对象有以下两个特点。

  1. 对象的状态不受外界影响, Promise对象代表一个异步操作,有三种状态:Pending(进行中)、Fulfilled(已成功)和Rejected(已失败)
  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果。

Promise也有一些缺点。首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。

resolve(value) VS resolve(promise)

then(onFulfiled, onRejected)

var d = new Date()
const promiseA = new Promise((resolve, reject) => {
    setTimeout( () => {
      resolve("ok")
    },2000)
})

const promiseB = new Promise((resolve, reject) => {
    resolve(promiseA)
})

promiseB.then( (resolve)=> {
  console.log(resolve, (new Date()) - d)
})

promise2中调用了resolve(promise1),此时promise1的状态会传递给promise2,或者说promise1的状态决定了promise2的状态。所以当promise1进入fulfilled状态,promise2的状态也变为fulfilled,同时将promise1自己的不可变值作为promise2的不可变值.

Promise新建后就会立即执行。


promise 捕获错误

回调函数有同步和异步之分,区别在于对方执行回调函数的时机,异常一般出现在请求、数据库连接等操作中,这些操作大多是异步的。

异步回调中,回调函数的执行栈与原函数分离开,导致外部无法抓住异常。

function fetch(callback) {
    setTimeout(() => {
        throw Error('请求失败')
    })
}

try {
    fetch(() => {
        console.log('请求处理') // 永远不会执行
    })
} catch (error) {
    console.log('触发异常', error) // 永远不会执行
}
//
// Uncaught Error: 请求失败

但是,永远不要在 macrotask 队列中抛出异常,因为 macrotask 队列脱离了运行上下文环境,异常无法被当前作用域捕获 如下。

function fetch(callback) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
             throw Error('用户不存在')
        })
    })
}

如果第三方函数在 macrotask 回调中以 throw Error 的方式抛出异常怎么办?

值得欣慰的是,由于不在同一个调用栈,虽然这个异常无法被捕获,但也不会影响当前调用栈的执行。

macrotask 抛出异常的话,请改为 reject 的方式。

function thirdFunction() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject('收敛一些')
        })
    })
}

Promise.resolve

现有对象转为Promise对象

var p = Promise.resolve('foo');
p.then( (resolve) => {
  console.log(resolve);
})

需要注意的是,立即resolve的Promise对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
// one
// two
// three

下面函数f是同步的,但是用 Promise 包装了以后,就变成异步执行了。

const f = () => console.log('now');
Promise.resolve().then(f);
console.log('next');

async

async函数返回一个 Promise 对象,可以使用then方法添加回调函数。

async function f() {
  return await 123;
}

f().then(v => console.log(v))

具体: http://es6.ruanyifeng.com/#docs/async
参考:
http://imweb.io/topic/57a0760393d9938132cc8da9
http://www.jianshu.com/p/78dfb38ac3d7

简单的总结Js的单例模式

简单的总结Js的单例模式

单例模式

单例模式的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为

但是Js里面不存在类,所以实现单例模式跟传统语言并非要一样(需要创建一个类)。

  1. 可以使用对象字面量的方法, (ps: 这本质上并非单例模式, 但能提供所要的需求)

     var Singleton = {
       method: function () {
     	  console.log('hello');
       }
     };
    
  2. 惰性单例
    页面需要一个唯一的弹窗的时候,并且使用的时候才初始化,减少没必要的性能开销。如下例子:

    var createSingleDiv = (function() {
    		var div;
    		createSingleDiv = function() {
    		    if (!div) {
    			    div = document.createElement('div');
    			    div.innerHTML = "弹窗";
    				document.body.appendChild(div);
    				
    				return div;
    		    }
    		 }
    		 
    		return createSingleDiv
    })();
    
    button.onclick = function() {
      createSingleDiv();
    }

    当点击button的时候我们去初始化创建div,这样就可以减少一开始就创建node节点造成的性能开销,因为有时候用户并非要点击。

  3. 内部new实例
    下面的例子用在系统间各种模式的通信协调上。

    var Singleton = (function () {
        function Singleton(args) {
            var args = args || {};
            this.args = args;
        }
    
        //实例容器
        var instance;
    
        var _static = {
            //返回Singleton的实例
            getInstance: function (args) {
                if (instance === undefined) {
                    instance = new Singleton(args);
                }
                return instance;
            }
        };
    
        return _static;
    })();
    
    var singleton = Singleton.getInstance({name: "app"});

Vscode IDE下React JSX无法自动补全的设置

前往vsCode用户设置的Json文件
第一步:"emmet.triggerExpansionOnTab": true
第二步:
"emmet.includeLanguages": { "javascript": "javascriptreact", "vue-html": "html", "plaintext": "jade" }
第三步:
"emmet.syntaxProfiles": { "javascript": "jsx" },

前端考题:第一期

  1. CSS优先级算法如何计算?

  2. CSS盒子模型

  3. new操作符具体干了什么呢?

  4. DOM操作——怎样添加、移除、移动、复制、创建和查找节点?

  5. js如何判断一个数组


答1题:

    
    * 优先级就近原则,同权重情况下样式定义最近者为准。
    * 已最后载入的样式为准。
    优先级为:
    同权重: 内联样式表(标签内部)> 嵌入样式表(当前文件中)> 外部样式表(外部文件中)。
    !important > id > class > tag
    important  内联优先级高

答2题:

在HTML中有句话:every element in web design is a rectangular box!
盒子包括: content -> padding -> border -> margin

css3  box-sizing: border-box 时,width: content + padding + border

答3题:

var obj = {};
obj.__proto__ = fun.prototype;
fun.call(obj);

答4题:

创建: 
createDocumentFragment (通常会起到优化性能的作用)
createELement (创建一个具体的元素)
createTextNode (创建一个文本节点)

添加,移除,替换,插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子节点前插入一个新的子节点

查找
getElementsByTagName()    //标签名称
getElementsByName()    //通过元素的Name属性的值
getElementById()    //通过元素Id,唯一性

答5题:

1. 使用Object.prototype.toString 去判断!最好兼容性

if( Object.prototype.toString.call( someVar ) === '[object Array]' ) {
    alert( 'Array!' );
}

Array.isArray IE9以下不行

eslint 配合 atom

下载aotm插件 linter-eslint
https://github.com/AtomLinter/linter-eslint

需要设置如下:

  • Install locally to your project eslint and the plugin
    • $ npm i --save-dev eslint [eslint-plugins]
  • Install globally eslint and plugins
    • $ npm i -g eslint [eslint-plugins]
    • Activate Use Global Eslint package option
    • (Optional) Set Global Node Path with $ npm config get prefix

提供了一些插件,可自行下载(ps: 版本差异会导致部分插件报错)

  • eslint-config-airbnb
  • eslint-plugin-import
  • eslint-plugin-jsx-a11y
  • eslint-plugin-react
  • eslint-plugin-html (可解析html中的脚本, 最新的版本v4跟早期eslint有冲突)

然后在项目下
$ eslint --init

http://eslint.cn/docs/user-guide/configuring 中文文档


使用以下注释,关闭提示。

/* eslint-disable */

使用eslintignore 忽略特定的文件和目录

创建一个 .eslintignore 文件,添加需要过滤的文件夹,或者文件

 build/*
 app/lib/*

命令行使用 --ignore-path

$ eslint --ignore-path .eslintignore --fix app/*

路径是相对于 .eslintignore 的位置或当前工作目录

更多 http://eslint.cn/docs/user-guide/configuring

基础配置:

module.exports = {
    parser: 'babel-eslint',

    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true
    },

    // 以当前目录为根目录,不再向上查找 .eslintrc.js
    root: true,

    // 禁止使用 空格 和 tab 混合缩进
    "extends": "eslint:recommended",

    globals: {
        // 这里填入你的项目需要的全局变量
        $: true,
    },
    
    // eslint-plugin-html 开启
    "plugins": [
        "html"
    ],

    "parserOptions": {
        "ecmaFeatures": {
            "jsx": false
        },
        "sourceType": "module"
    },

    "rules": {
        "indent": ["error", 'tab'],

        "linebreak-style": ["error","unix"],

        "quotes": ["error","single"],

        "semi": ["error","always"],

        "semi": ["error","always"],

        "arrow-spacing": ["error", { "before": true, "after": true }],

        "no-unused-vars": "off", //禁止提示没有使用的变量,或者函数

        "block-spacing": "error",

        "no-console": "off", //可以使用console

        "keyword-spacing": ["error", { "before": true }] //强制关键字周围空格的一致性

    }
};

js构造函数中的疑点

构造函数已经是老生常谈的事情了。这里讲一些比较基础的东西。

先看下一个例子

function Book(name) { 
    if (!(this instanceof Book)) { 
        // the constructor was called without "new".
        return new Book(name);
    } 
}

var myBook = Book(name);
var myBook1 = Book(name);
myBook.constructor === myBook1.constructor // true

首先判断this是否为Book的实例,不是就返回新的实例。经常用于解决在构造函数前面忘记使用new的情况,如果没有使用在function前面使用new,那就按正常的函数执行。那为什么这里可以这么使用?

我们先看下new的原理

(1) 创建一个新的对象: var myBook = New Object()
(2) 设置对象的__proto__ 指向构造函数的prototype
    myBook.__proto__ = Book.prototype

到了第二步骤我们就可以看到myBook可以访问构造函数的prototype的constructor。

var myBook = New Object();
myBook.__proto__ = Book.prototype;
myBook instanceof Book // true

当执行第二步骤以后例子中的 if (!(this instanceof Book)) 就不会被执行。所以this instanceof Book可以判断当前函数是否使用new。

(3)第三步就是执行Book函数,并且让this指向myBook对象

第四步就是判断Book返回值的类型:

判断条件
(1)如果是值类型就丢弃,返回instance。
(2)如果是引用类型,就返回这个引用类型的对象,替换掉instance。

例子:

function Book() {
    return 2;
}
var myBook = new Book();
myBook instanceof Book // true

return 2属于值类型,包括String、布尔值、null、undefined等..如果是值类型,就丢弃返回instance。

function Book() {
    var newObj = {}
    return newObj;
}
var myBook = new Book();
myBook instanceof Book // false

如果是引用类型,就返回这个引用类型的对象

function Book() {
    return new Number();
}
...

如果return的值是一个Number 对象,那么实例对象的值就是Number 对象。

Note: 使用Object.create创建的对象的__proto__并没有指向任何的构造函数

原型链继承需要注意的一点

例子:

function Car() {}
function Bmw() {}

Bmw.prototype = new Car();
Bmw.prototype.constructor = Bmw; 

var bmw1 = new Bmw();

比较奇怪的是 Bmw.prototype.constructor = Bmw; 解释下为什么要这么处理。
假设如果没有这行

bmw1.constructor === Car //true

Bmw.prototype 实际上是 new Car() 的实例,结果导致Bmw prototype中的 constructor从丢失(ps: function创建后prototype已经有constructor值),
bmw1对象在原型链中查询constructor的时候指向了构造函数Car,这明显是错误的。因此这里修正了Bmw.prototype.constructor = Bmw。同时还可以通过proto获取Car的构造函数。

bmw1.__proto__.__proto__.constructor === Car

react-native run android v0.50版本 环境配置坑

React-native

android

第一次部署 react-native run-android
https://services.gradle.org/distributions/gradle-2.14.1-all.zip 下载很慢的问题

手动下载之后,把文件放在
~/.gradle\wrapper\dists\gradle-2.14.1-all\8bnwg5hd3w55iofp58khbp6yv

Android开发环境需求
java JDK 必须是1.8以上

下载地址

React Native的开发环境 - 简书

jdk版本问题导致:

Unsupported major.minor version 52.0

解决方案更新jdk,修改文件内容具体内容 点这里!

设置skd dir path

报错内容:

SDK location not found. Define location with sdk.dir in the local.properties file or with an ANDROID_HOME environment variable.

解决方案:在android 下面创建 local.properties 文件,绑定android sdk 路径

sdk.dir = /Users/*username*/Library/Android/sdk

或者设置变量ANDROID_HOME
需要.bash_profile文件 定义ANDROID_HOME 变量,修改之后
然后在 .bashrc 或者 zsh 文件修改

. ~/.bash_profile

保证重启后生效

需要下载安装Android studio

https://developer.android.com/studio/install.html

具体可以看http://sstlant.com/2017/11/05/React%20Native%20%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.