Hank's Blog

耕种思考的自留地

0%

1
2
3
4
5
6
7
8
9
10
var name = "window";
var test = function() {
console.log(this.name);
};
test(); // window
var obj = {
name: "obj",
test: test
};
obj.test(); // obj

设计一个customBind函数,使其满足如下效果:

1
2
3
4
5
var obj = {
name: "obj",
test: test.customBind(window)
};
obj.test(); // window

很明显customBind函数需要改变 this 的指向,所以需要用到callapply方法

1
2
3
4
5
6
7
8
Function.prototype.customBind = function(that) {
var _this = this, // _this 指向当前被调用的函数
slice = Array.prototype.slice,
args = slice.call(arguments, 1); // 将customBind函数的参数转化为数组
return function() {
return _this.apply(that, args);
};
};

以上代码可以实现作用域绑定,但是无法支持调用函数的参数传递,也就是说obj.test('obj2')里传递的参数不会被处理,因此我们需要改进一下customBind函数:

1
2
3
4
5
6
7
8
9
Function.prototype.customBind = function(that) {
var _this = this, // _this 指向当前被调用的函数
slice = Array.prototype.slice,
args = slice.call(arguments, 1); // args 是 customBind 函数的参数
return function() {
// slice.call(arguments, 0) 是被调用函数的参数
return _this.apply(that, args.concat(slice.call(arguments, 0)));
};
};

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var name = "window";
var test = function(a, b) {
console.log("作用域绑定:" + this.name);
console.log("customBind传递的参数:" + a);
console.log("调用函数传递的参数:" + b);
};
var obj = {
name: "obj",
test: test.customBind(window, "obj")
};
obj.test("obj2");
// 作用域绑定: window
// customBind传递的参数:obj
// 调用函数传递的参数:obj2

测试通过,所以 js 中的 bind 函数可以这样实现:

1
2
3
4
5
6
7
8
Function.prototype.bind = function(that) {
var _this = this,
slice = Array.prototype.slice,
args = slice.call(arguments, 1);
return function() {
return _this.apply(that, args.concat(slice.call(arguments, 0)));
};
};

如果使用ES6的写法会更加简单:

1
2
3
4
5
6
Function.prototype.bind = function (that, ...arg) {
var _this = this
return function name(...inArg) {
return _this.apply(that, arg.concat(inArg))
}
}

在css中常用的单位就几个(px%remsdeg),其实css/css3中还有很多单位可用。

长度

单位 解释
px 相对于屏幕分辨率而不是视窗大小:通常为1个点或1/72英寸
em 相对于父元素的字体大小
rem 相对于根元素字体大小
vw 相对于视窗的宽度:视窗宽度是100vw
vh 相对于视窗的高度:视窗高度是100vh
vm 相对于视窗的宽度或高度,取决于哪个更小
Read more »

HTTP/1.1协议中和网页缓存相关的字段:

header 解释 例子
Expires 响应过期的日期和时间 Expires: Thu, 01 Dec 2010 16:00:00 GMT
Cache-Control 告诉所有的缓存机制是否可以缓存及哪种类型 Cache-Control: no-cache
Last-Modified 请求资源的最后修改时间 Last-Modified: Tue, 15 Nov 2010 12:45:26 GMT
ETag 请求变量的实体标签的当前值 ETag: “737060cd8c284d8af7ad3082f209582d”

HTTP/1.0协议中有一个功能比较弱的缓存控制机制:Pragma,使用HTTP/1.0的缓存将忽略ExpiresCache-Control

Read more »

Last-Modified 是http响应头的一部分,与之相对的是请求头中的 If-Modified-Since ,都表示请求资源的最后修改时间。

工作原理

  1. 当客户端访问页面时,服务器会将页面最后修改时间通过 Last-Modified 标识由服务器发往客户端
  2. 客户端记录修改时间,再次请求本地存在的cache页面时,客户端会通过 If-Modified-Since 头将先前服务器端发过来的最后修改时间戳发送回去
  3. 服务器端通过这个时间戳判断客户端的页面是否是最新的,如果不是最新的,则返回新的内容,如果是最新的,则返回 304 告诉客户端其本地 cache 的页面是最新的

由此客户端可以直接从本地加载页面,减少在网络上传输的数据,同时也减轻了服务器的负担。

从输入URL到DOM

  1. 用户输入URL,webkit调用其资源加载器加载对应的网页
  2. 网页被交给HTML解释器,经历以下解析变成DOM结构:Bytes → Characters → Tokens → Nodes → Object Model。如果节点需要依赖其他资源:图片、css、视频等,调用资源加载器异步加载他们,期间不阻碍DOM树的构建
  3. 如果遇到js标签,调用js引擎解释并执行,js可能会修改DOM树结构,所以会阻碍DOM树的构建。网页中依赖的js资源加载完成后,触发DOMContentLoad事件
Read more »

提取库文件

CommonsChunkPlugin

React、jQuery等库文件很少变化,并且到处被复用,应该被提取出来,并且得到长时间的缓存。
使用插件:webpack.optimize.CommonsChunkPlugin(webpack内建插件)

1
2
3
4
5
6
7
8
9
10
entry: {
react: ['react'],
jquery: ['jquery']
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: ['jquery', 'react'],
minChunks: Infinity
})
]
Read more »

冲突发生的情况

假设A、B两个用户,他们分别从SVN服务器中检出了test.js文件,此时A、B、服务器三个地方的test.js的版本都是13。现在,B用户修改文件内容并提交,此时B用户和服务器的test.js的版本都变为14,只有A用户的test.js的版本还是13。接下来,A用户修改不同的内容然后提交。
由于A用户是在13版本上做的修改,而服务器已经是14版本了,所以会提交失败。
提交失败之后有两个选择:第一,选择revert,省去了解决冲突的麻烦;第二,选择更新文件,这时会有冲突问题。

Read more »

Vue 中要遍历 n 项可以这么写

1
2
<div v-for="i in n">{{i}}</div>
<div v-for="i in new Array(n)">{{i}}</div>

遍历数组

1
2
3
<div v-for="(item, index)in array">
{{ item }} - {{ index }}
</div>

遍历对象,遍历顺序就是对象书写顺序

1
2
3
<div v-for="(value, key, index) in object">
{{ index }}. {{ key }}: {{ value }}
</div>
Read more »

收集了一些日常项目中经常会用到的 webpack 配置,加深对webpack配置的理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
module.exports = {
// entry: 打包的入口文件,一个字符串或者一个对象
entry: {
bundle: './index.js',
},
// output:配置打包的结果,一个对象
output: {
// fileName:定义输出文件名,一个字符串
// path:定义输出文件路径,一个字符串
path: __dirname,
filename: '[name].js' // 这里的name就是指 entry 对象的键名,即 bundle
},
// module: 定义对模块的处理逻辑,一个对象
module: {
// rules: 定义文件加载规则,一个数组
rules: [{
test: /\.vue$/, // 正则表达式,用于匹配指定文件
loader: 'vue-loader', // 加载器名字
options: vueLoaderConfig, // 传入加载器的参数
// include: 字符串或者数组,规定需要解析的文件夹
include: [resolve('src')],
// exclude:字符串或者数组,规定不需要解析的文件夹
exclude: [resolve('node_modules')]
}],
// loaders: 定义一系列的加载器,一个数组
loaders: [{
test: /\.css$/,
loader: "style-loader!css-loader"
}],
},
// devtool: 规定一个开发工具来加快调试,字符串
devtool: 'cheap-module-eval-source-map',
// resolve: 模块解析的相关配置,一个对象
resolve: {
// extensions:自动补全没有后缀的文件,一个数组
extensions: ['.js', '.vue', '.json'],
// alias: 设置解析别名,一个对象
alias: {
'~': resolve('src/components'), // 配置后使 import('~') 等价于 import('src/components')
}
},
// externals: 规定某些依赖不会被webpack解析,一个对象
externals: {
// externals中的key是import中使用的
// externals中的value是window下调用的
echarts: 'echarts',
_: 'lodash'
},
// plugins: 定义一系列的插件,一个数组
plugins: [
new MyPlugin({name: 'hanger'})
]
};

更多更详细的介绍在官方文档

在实际的移动端项目中会遇到横幅展示的需求,用来展示最新上架的内容或者广告等。为此我制作了一个 Vue 组件(Demo&源码),让我们来一步步实现这个组件吧,有可以改进的地方欢迎指正。

制定一个小目标

首先我们搭建一个简单的例子,并希望引入Banner组件就可以实现 banner 效果。

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
<template>
<div>
<banner>
<div slot="item" class="item"><img src="http://olislpb6q.bkt.clouddn.com/bizhi1.jpg"></div>
<div slot="item" class="item"><img src="http://olislpb6q.bkt.clouddn.com/bizhi2.jpg"></div>
<div slot="item" class="item"><img src="http://olislpb6q.bkt.clouddn.com/bizhi4.jpg"></div>
</banner>
</div>
</template>

<script>
import { Banner } from '@/components';
export default {
name: 'el-banner',
components: { Banner }
};
</script>

<style lang="scss" scoped>
.item {
img {
height: 150px;
width: 100%;
}
}
</style>
Read more »