Martin's Dean

Cast a cold eye, on Life on Death, Horseman, 123!


  • 首页

  • 分类2

  • 标签28

  • 时间轴

开发一个h5小游戏

发表于 2017-09-05 | 分类于 技术
| 9k | 0:09

这次,我们的目标是开发一个网页版猜拳小游戏。首先看看最终的效果图:

瞄一眼效果图,游戏玩法大致可以了解个七七八八了。很简单,用户从石头剪刀布中随便选一个并出拳后,电脑也会随机(实际上是根据服务端的返回值)做出选择,之后判断用户和点小融之间的胜负,弹出相应的动画即可。

游戏的玩法虽然简单,但实际的开发过程中,坑还是不少。下面我们从头梳理一下开发的过程。

阅读全文 »

浏览器兼容issues && solution

发表于 2017-08-01 | 分类于 技术
| 1k | 0:01

web开发中,对ie的兼容曾经是无数前端工程师的切肤之痛,如今,随着移动设备的崛起和ie浏览器的没落,我们越来越不需要考虑在ie上的兼容性问题。

然而,没有ie我们就可以高枕无忧了吗?在移动端,一个新的问题又摆在了我们的面前—对旧版移动端浏览器的兼容。

下面就总结一下这些年在移动端踩过的大大小小的兼容性的坑和解决办法。

首先是有关函数兼容性的问题(大部分转自我的同事乔乐的博客):

阅读全文 »

webpack HMR插件原理浅析

发表于 2017-07-27 | 分类于 技术
| 2k | 0:02

开发过程中,我们一般都会在webpack的配置文件中添加热更新的插件:

1
2
3
4
5
6
7
8
9
10

plugins: [

// ...

new webpack.HotModuleReplacementPlugin(),

// ...

]

有了这个插件,开发过程中,一旦我们对代码进行了改动,webpack会立即rebuild我们的代码,大大提高了开发效率。那么,它背后的原理是什么呢?

阅读全文 »

How to read ECMAScript Specification?

发表于 2017-07-13 | 分类于 技术
| 6k | 0:06

TC39 Overview

从零开始写个编译器

Javascript语法解析与抽象语法树

TC39 Process

TC39 Proposals

ECMAScript 2018规范

LL(K)算法

LL(1)文法分析器的简单实现

Keywords:

TC39, tokens, lexical grammer, terminal symbols, parse tree, nonterminal,

Production, terminal symbols, nonterminal symbols


最近抽空大致看了下ES2018的specification,内容深广,涉及的语言设计的底层细节非一日所能达。面对这样庞大的一份资料,如何看待它呢?我的态度是,不求通读标准,但求拥有阅读和理解标准的能力。即使你熟记标准中的所有细节,对应用开发者来说,也无助于解决实际生产中的绝大部分问题,但当我们遇到某些无法可解疑难杂症时,查阅标准,可能是我们攻克问题的最后一件武器。更重要的是,对于自己朝夕使用的工具,如果都只知皮毛,那也确实说不过去了。

阅读全文 »

使用React实现无限下拉加载列表

发表于 2017-04-24 | 分类于 技术
| 4k | 0:04

组件的实现参考了一个原生的js实现的下拉加载的例子。

有了前人踩过的坑,我们不再需要大费周张的使用原生js造一遍轮子。

此处就直奔主题,看看如何用React实现同样的功能。

阅读全文 »

深入NodeJS事件系统

发表于 2017-04-05 | 分类于 技术
| 3k | 0:03

对于前端开发,js的事件系统可以说是我们接触最多的特性之一,甚至很多人把他当作了js与生俱来的特性,把js看作一门基于事件驱动的语言。

但当我们追本朔源,我们会发现,这个看似高深的特性又是一个基于发布/订阅模式的经典实现。下面,我们就仿照nodejs中的这一模块,一步步实现一个基本的事件发布系统。

阅读全文 »

redux saga

发表于 2017-03-23 | 分类于 技术
| 4k | 0:04

最近项目中引入了redux-saga,在复杂的异步问题上为我们带来了很多便利。当然,对工程师来说,往往不满足于知其然,我们更希望知其所以然。本着这个原则,我研究了saga的源码,总结出了这篇文章。

在阅读本文前,如果你对redux还不了解,可以先看看阮一峰老师的这篇Redux入门。另外,在middleware的定义中大量使用了ES6的箭头函数,如果你对箭头函数还不熟悉,推荐去恶补一下箭头函数的知识。

阅读全文 »

如何理解TCP的三次握手协议?

发表于 2016-11-03 | 分类于 技术
| 1k | 0:01

TCP是一个面向链接的协议,任何一个面向连接的协议,我们都可以将其类比为我们最熟悉的打电话模型。

如何类比呢?我们可以从建立和销毁两个阶段分别来看这件事情。

阅读全文 »

前端面试题目总结

发表于 2016-10-28 | 分类于 技术
| 5k | 0:05

dom0事件

使用onclick添加的事件为dom0事件,同一个元素只能拥有一个dom0事件,后添加的事件会覆盖之前的事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14

<div id="test" onclick="alert('test')" /> //在元素上直接绑定dom0事件

<script>

//使用onclick方法添加dom0事件

document.getElementById('test').onclick=function() {

alert('test');

}

</script>

对dom0事件,IE的事件流是冒泡(首先出发叶子节点事件),而netscape采用的是事件捕获(相反的顺序)。

阅读全文 »

JS中的this

发表于 2016-10-16 | 分类于 技术
| 2k | 0:02

Javascript中的this一直是一个老大难的问题,在ES6中,箭头函数的

1
2
3

<!--more-->
### ES5中的```this

首先需要明确this绑定的基本原则:this绑定发生在函数的调用时(而非声明时),也就是所谓的运行时绑定。明确了这一点,我们可以看看实际使用中this常常遇到的几种情况:

1. 默认绑定全局变量

1
2
3
4
5
6
7
8
9

var a = 1;

function foo() {

console.log(this.a);
}

foo(); //ouput: 1

根据我们上面的原则,函数foo调用时未执行任何绑定操作,this默认指向全局对象,也就是a。需要注意的是,若我们采用

1
2

#### 2. 对象中的隐式绑定

function foo() {

console.log(this.a);

}

var b = {

a: 2,

foo: foo

}

b.foo(); //2

var c = {

a: 3,

b: b

}

c.b.foo(); //2

1
2
3
4

此时foo函数的调用者是对象b,因此根据原则,```this```指向对象b。另外,``this``的指向遵循就近原则,因此c.b.foo()的结果是2而不是3。

####3. 显式绑定

function foo() {

console.log(this.a);

}

var obj = {

a: 2

}

foo.call(obj); // 2

foo.apply(obj); // 2

1
2
3
4

javascript提供了内置函数apply和call,通过调用它们,我们可以强制将函数的``this``对象指定为obj。

在apply和call的基础上,js还实现了bind函数:

function foo() {

console.log(this.a);

}

var obj = {

a: 5

};

var obj2 = {

a: 10

};

var bar = foo.bind(obj);

bar(); // 5

bar.apply(obj2); // 5

1
2
3
4
5
6

对foo调用bind函数,我们得到一个bar函数。此时bar函数的``this``对象固定指向obj,即使我们对bar函数调用了apply方法,依然无法改变``this``的指向。我们称这种情况为``hard bind``。

####4. ``new``绑定

除了上面几种情况,js中,我们可以通过``new``创建对象,此时也会造成``this``绑定。

function foo(a) {

this.a = a;

}

var obj = {

a: 5

};

var baz = foo.bind(obj); // 绑定obj

var bar = new baz(2); // new覆盖了绑定

console.log(bar.a); // 2

1
2
3
4
5
6
7
8

``new``会创建对象,并让``this``指向当前对象。通过上面的例子,我们还可以发现,``new``绑定的优先级高于``hard bind``,即使baz已经是foo函数调用``bind``的结果,bar.a的输出依然是2。



### 绑定丢失的问题

下面是一个最常见的绑定丢失的场景:

function foo() {

console.log(this.a);

}

var obj = {

a: 5,

foo: foo

}

setTimeout(obj.foo, 10); // undefined

1
2

我们原本期待setTimeout函数在十秒后输出5,然而输出结果却是undefined。原因是什么呢?因为**作为参数传递到setTimeout函数中的obj.foo只是一个指向foo方法的引用**,它的效果其实等同于下面这段代码:

setTimeout(function() {

console.log(this.a);

}, 10);

1
2

此时,不存在任何this绑定,``this``指向调用它的匿名函数对应的this,在普通模式下是global变量,在strict模式下是undefined。这也就解释了为什么会出现this绑定丢失的情况。解决办法也简单:可以使用bind函数强制绑定this对象,也可以将this对象作为参数传递给对应的函数。这里推荐第一种方法:

setTimeout(obj.foo.bind(obj), 10); // 5

1
2

### ES6箭头函数(=>)中的```this

为了解决绑定丢失的问题,ES6中的箭头函数对this绑定做了一定的改进,具体来说,就是:箭头函数内的this始终指向调用它的闭包所绑定的this。说起来有点拗口,下面还是用setTimeout的例子来解释这句话:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

var obj = {

a: 5

}

function foo() {

setTimeout(() => {

console.log(this.a);

}, 10);

}

foo.call(obj); // 5

setTimeout对应的闭包是foo(注意js中,闭包只针对函数,Object不是闭包),而foo的this对应obj,因此setTimeout中,匿名箭头函数的this指向调用它的闭包(也就是foo函数)对应的this。可以看到,箭头函数完美解决了匿名函数this绑定丢失的问题。

参考:

You dont know js: this & object.prototypes

123
Martin Cai

Martin Cai

Coding, Travelling, Reading and Enjoying

24 日志
2 分类
28 标签
GitHub E-Mail
0%
© 2020 Martin Cai | 91k | 1:31
由 Hexo 强力驱动 v3.9.0
|
主题 — NexT.Gemini v6.1.0