Kenyon Duan
2015-10-25T05:02:42+00:00
http://kenyonduan.github.io/
Kenyon Duan
Javascript 初探
2015-10-23T00:00:00+00:00
http://kenyonduan.github.io//posts/Javascript初探
<h1>Javascript中几个非常重要的语言特性——对象、原型继承、闭包</h1>
<p>来自 Google Docs <a href="https://docs.google.com/document/d/1S7pSryAT3v9jyhrH4040EEVq9hennaJIg1ArnWXwZtk/edit">Javascript 初探</a></p>
<h2>1. 对象(直接声明、直接赋值、直接使用)</h2>
<blockquote><h3>(1). 所有变量都是对象(除了null 和 undefined)</h3>
<pre><code class="javascript">var name = 'duan';
var duan = {name: 'duan', email: 'duan@easya.cc'};
//读取
duan.name //成员(点操作符)
duan['name'] //Hash(中括号操作符)
duan.name = 'balabala' //重新赋值
duan = {} //使用对象的字面语法 - {} - 可以创建一个简单对象。这个新创建的对象从Object.prototype 继承下面,没有任何自定义属性
</code></pre>
<h3>(2). function 也是对象</h3>
<pre><code class="javascript">function sayHi() {
// 注意这里的 this, 没有它的话就是局部变量或者局部函数了
alert("My name is" + this.name + ", my email is" + this.email);
}
sayHi instanceof Object // => true
duan.satHi = sayHi //添加成员函数
duan.sayHi() // => "My name is duan, my email is duan@easya.cc"
</code></pre>
<h3>(3). 删除属性</h3>
<pre><code class="javascript">delete duan['name'] //删除对象的属性
duan.hasOwnProperty('name') // => false 注: 删除属性的唯一方法是使用 delete 操作符;设置属性为 undefined 或者null 并不能真正的删除属性, 而仅仅是移除了属性和值的关联。
</code></pre>
<h3>(4). <a href="https://gist.github.com/kenyonduan/4667de99d945764dfc1d">属性的配置</a></h3>
<h3>(5). this</h3>
<blockquote><ol type="a">
<li><p><a href="https://gist.github.com/kenyonduan/87d785da835bf5345465">Github Gist</a></p></li>
<li><p>setTimeout 函数:
setTimeout 会牵涉到 <a href="http://www.ruanyifeng.com/blog/2014/10/event-loop.html">Event Loop</a> 机制,简单来说就是将 js 代码分成了两种: 同步任务(synchronous)、异步任务(asynchronous)。同步任务会在在主线程上执行的任务,依次排队执行,而异步任务会进入执行队列,当任务队列通知主线程后才会进入主线程执行。异步任务中就有 Mouse click、Keypress、Network events、setTimeout 等,javascript 引擎会在 Golbal contxt 下执行这些异步任务。<a href="http://jsfiddle.net/dposin/okjr81ev/light/">代码示例</a></p></li>
</ol>
</blockquote>
<h3>(6). 没有 class(ES5)</h3></blockquote>
<h2>2. 继承</h2>
<p> JavaScript 不包含传统的类继承模型,而是使用 prototype 原型模型。</p>
<blockquote><h3>(1). __proto__</h3></blockquote>
<ol type="a">
<li> 示例</li>
</ol>
<pre><code class="``javascript"> var array1 = [1,2,3]
array1.push(4) //哪里来的这个方法?
[] instanceof Array // => true
array1.__proto__ == Array.prototype // => true
Object.getPrototypeOf(array1) === Array.prototype // => true
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_0.png" alt="image alt text" /></p>
<ol type="a">
<li><p> 当访问对象其中的一个成员或方法的时候,如果这个对象中没有这个方法或成员,那么Javascript引擎将会访问这个对象的<strong>proto</strong>成员所指向的另外的一个对象,并在那个对象中查找指定的方法或成员,如果不能找到,那就会继续通过那个对象的<strong>proto</strong>成员指向的对象进行递归查找,直到这个链表结束(PS: 有点像 Ruby 中的方法查找)</p></li>
<li><p> 所有的东西都由Object衍生而来, 即所有东西原型链的终点指向</p></li>
</ol>
<pre><code class="``javascript"> Object.prototype
function F() {}
F.prototype.foobar = function() {}
var i = new F();
F.prototype.__proto__ == Object.prototype
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_1.png" alt="image alt text" /></p>
<blockquote><h3>(2). Prototype</h3>
<p> prototype 成员</p></blockquote>
<pre><code class="``javascript"> Array 的 prototype:
Object.getOwnPropertyNames(Array.prototype)//=> ["length", "constructor", "toString", "toLocaleString", "join", "pop", "push", "concat", "reverse", "shift", "unshift", "slice", "splice", "sort", "filter", "forEach", "some", "every", "map", "indexOf", "lastIndexOf", "reduce", "reduceRight", "entries", "keys"]
function Base() {
this.id = ‘base’;
}
//输出的格式为: 构造函数名 原型
Base.prototype //=> Base {}
Base.prototype.foobar = function() {alert(1)}
Base.prototype //=> Base {foobar: function}
a = new Base()
a.prototype.foobar = function() {} //=> TypeError: Cannot set property 'foobar' of undefined
a.__proto__ == Base.prototype //=> true
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_2.png" alt="image alt text" />
(1)、当一个函数对象被创建时,这个函数对象就具有一个 prototype 成员,这个成员是一个对象,这个对象包含了一个constructor 构造子成员,这个构造子成员会指向这个函数本身
(2)、实例"只能"查看 <strong>proto</strong> 来得知自己是基于什么 prototype 被制造出来的,所以"不能"再重新定义实例的 prototype创造出实例的实例对象
* new 操作符(用来调用构造函数)</p>
<pre><code class="``javascript"> var obj = new Base() //new 操作符干了什么?
var obj = {}; //创建了一个空对象obj
obj.__proto__ = Base.prototype; //将这个空对象的__proto__成员指向了Base函数对象prototype成员对象
Base.call(obj); //改变 this
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_3.png" alt="image alt text" /></p>
<pre><code class="``javascript"> //这个时候如果我们修改 Base 的 prototype 对象,为它添加一些函数:
Base.prototype.print = function() {
return this.id;
}
obj.print() //=> 'foobar'
//根据上面提到的 __proto__ 的特性,print 这个方法也可以作为 obj 对象的方法被访问到。
</code></pre>
<ul>
<li>方法重写</li>
</ul>
<pre><code class="``javascript"> obj.print = function() {return 'balabala'}
obj.print() //=> 'balabala' WHY?
</code></pre>
<ul>
<li> 总结
<blockquote><ul>
<li>构造子中(一般为大写开头的函数),我们来设置对象的成员变量(例如:上面的 id)</li>
<li>构造子对象 prototype 中我们来设置‘类’的公共方法。通过函数对象和 <strong>proto</strong>与 prototype 成员以及 new 操作符,模拟出类和类实例化的效果。</li>
<li>简单描述:</li>
<li><strong>proto</strong> 是用来指向指向另外一个对象</li>
<li>prototype就是对一对象进行扩展,其特点在于通过委托的机制来调用原型对象的方法和访问原型对象的属性</li>
</ul>
</blockquote></li>
</ul>
<blockquote><h3>(3). Pseudo classical 继承</h3>
<pre><code class="``javascript"> function Derive(id) {
this.id = id;
}
function Base() {
this.id = ‘base’;
}
Base.prototype.toString = function() {
return this.id;
}
Derive.prototype = new Base();
Derive.prototype.constructor = Derive //修Derive.prototype.constructor为Derive本身
Derive.prototype.test = function(id){
return this.id === id;
}
var newObj = new Derive("derive");
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_4.png" alt="image alt text" /></p></blockquote>
<p> 问题
为什么是 Derive.prototype = new Base() 而不是 Derive.prototype = Base.prototype ?</p>
<pre><code class="``javascript"> function A(){}
function B(){}
A.prototype = B.prototype
A.prototype.test = function() { return 'A.test'; }
new A().test() //=> A.test
new B().test() //=> A.test
// 分割线 //
A.prototype = new B()
A.prototype.test = function() { return 'A.test'; }
new A().test() //=> A.test
new B().test() //=> TypeError: (intermediate value).test is not a function
//WHY? 要实现继承,就必须保证A继承B以后,A所做的修改不能影响到B以及继承自B的其它对象,A.prototype = new B();这个方法,是创建了一个新的对象{},并且继承了B的原型,这是一个新对象,不是和B同一引用,所以不会污染B。
</code></pre>
<ul>
<li> 为什么要 Derive.prototype.constructor = Derive?</li>
</ul>
<pre><code class="``javascript"> //正常情况下不错修正也不会有什么影响,但是当你需要显式的使用构造函数的时候就会出现问题。
function Person(){}
function Women() {}
Women.prototype = new Person()
Women.prototype.constructor //=> function Person(){} Why?
//由于 constructor 始终指向的是创建本身的构造函数,所以 Women.prototype.constructor 指向的是这个 Person 对象的构造函数,也就是 Person 函数,这样一来 Women 的 constructor 函数指向就不对了。
Women.prototype.constructor = Women
Women.prototype.constructor //=> function Women() {}
var women = new Women()
//如果在不清楚 women 对象是由哪个函数实例化出来的情况下,但是我想 clone 一个怎么办?当我们重置了 Women 函数的 constructor 后我们可以直接访问 women 对象的 constructor 来拿到构造函数。
women.constructor //=> function Women() {}
var women = new women.constructor
</code></pre>
<blockquote><h3>(4). Prototypal 继承</h3>
<pre><code class="``javascript"> function object(old) {
function F() {};
F.prototype = old;
return new F();
}
var base = {
id:"base",
toString:function(){
return this.id;
}
}
var derive = object(base);
</code></pre>
<p> <img src="http://kenyonduan.github.io/images/Javascript%E5%88%9D%E6%8E%A2/image_5.png" alt="image alt text" /></p>
<h3>(5). Object.create 方法(ES5)</h3>
<pre><code class="``javascript"> function A(){}
function B() {}
A.prototype.test = function() { return 'A.test'; }
A.prototype = Object.create(B.prototype) //Pseudo classical 继承
A.prototype.constructor = A //重置构造函数
var derive = Object.create(base); //Prototypal 继承
</code></pre>
<h3>(6). 区别</h3>
<ul>
<li>Pseudo classical 继承是使用了“构造函数” 和 new 操作符来创建对象,并且使用了构造函数给予的 prototype 属性来构造继承链。所有的实例对象都会继承该 prototype 属性。</li>
<li>Prototypal 继承是直接从现有对象来创建新的对象</li>
</ul>
</blockquote>
<h2>3. 闭包(Closure)</h2>
<blockquote><h3>1. 概念</h3>
<ul>
<li>闭包就是能够读取其他函数内部变量的函数。</li>
<li>当在一个函数内定义另外一个函数就会产生闭包。</li>
<li>闭包就是就是函数的“堆栈”在函数返回后并不释放,可以理解为这些函数堆栈并不在栈上分配而是在堆上分配</li>
</ul>
<h3>2. 变量的作用域</h3>
<pre><code class="javascript">//javascript 区分全局变量和局部变量,函数内部可以直接读取全局变量,而函数外部无法读取函数内部的局部变量
var n = 1;
function foobar(){
return n;
}
foobar() //=> 1
function foobar2(){
var n = 2; //注意这里的 var,如果不加var 实际声明的是一个全局变量(污染全局命名空间)
}
alert(n) //=>n is not defined
</code></pre>
<h3>3. 如何读取函数内部的局部变量</h3>
<pre><code class="javascript">//在函数内部再定义一个函数并返回它
function outer() {
var n = 999;
function inner() {
alert(n);
}
return inner; //WHY? 且为什么是 inner 而不是 inner()
}
var r = outer();
r();
//Javascript语言有一个"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量。所以,父对象的所有变量,对子对象都是可见的,反之则不成立。既然 inner 可以读取 outer 中的局部变量,那我们就将 inner 返回给 outer 的调用者,那我们就可以在 outer 的外部读取它的内部变量,而 inner 就是闭包。
//...但是看起来好像和这样写区别不大
function outer() {
var n = 999;
alert(n);
}
</code></pre>
<h3>4. 闭包的用处</h3>
<ul>
<li><h4>可以读取函数内部的变量</h4></li>
<li><h4>让这些变量的值始终保持在内存中</h4>
<pre><code class="javascript">//对上面的 outer 再改造一下看一下闭包的好处在哪里
function outer() {
var n = 999;
plus = function() { //注意这里没有加 var 所以 plus 是一个全局变量,而 plus 的值是一个匿名函数(也是一个闭包),该函数相当于一个 setter, 可以在函数外部操作函数内部的局部变量
n += 1;
}
function inner() {
alert(n);
}
return inner;
}
var r = outer();
r(); //=> 999
plus()
r(); //=> 1000
//可以看到函数 outer 中的 n 一直保持在内存中,并没有在 outer 调用完成后被清除。而如果不使用闭包:
function outer() {
var n = 999;
plus = function() { n += 1;}
return n;
}
var r = outer(); // => 999
plus();
outer(); //=> 999
//WHY?
//因为 outer 是 inner 的父函数,而 inner 被赋给了 r 这个局部变量(但是它的作用域在 global),在 r 没有被回收前 inner 会一直存在内存中,而 inner 的存在依赖于 outer,因此 outer 也会始终存在内存中,不会被垃圾回收机制回收。
</code></pre></li>
</ul>
<h3>5. 使用闭包要注意的地方</h3>
<ul>
<li>闭包会使得函数中的变量都被保持在内存中,加大内存消耗,滥用闭包会造成网页的性能问题。解决办法: 用完了及时清除,不管闭包赋予的是全局变量还是局部变量。</li>
<li>闭包可以在父函数外部,改变父函数内部变量的值(比如刚才的 plus 函数),所以需要注意内部私有变量被污染。
<code>javascript
//再次改造一下上面的 outer 函数
var outer = (function() { //立即执行函数
var n = 999;//私有变量
function setN(value) { //公共的 setter
n = value;
}
function printN() {
console.log(n)
}
return {
setN: setN,
printN: printN
};
})();
</code></li>
<li>几个容易让人混淆的使用方式</li>
</ul>
</blockquote>
<pre><code class="javascript">function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + list[i];
result.push( function() {
//console.log(item)
//console.log(i)
alert(item + ' ' + list[i])}
);
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
testList() //?会弹出什么?
//答案是弹出三次 item3 undefined, 原因是因为 result 里添加的是闭包,这个闭包在调用 buildList([1,2,3]) 的时候是 不会执行的,当 fnlist[j]() 这个时候才会执行,而这个时候 buildList 函数内部的局部变量已经发生了变化(见 console.log 的内容),可以看到 var item = item3, var i = 3,[1,2,3][3] 取出的就是 undefined。
结论:闭包中局部变量是引用而非拷贝。
// 我是分割线 //
var name = "Outer";
var object = {
name : "Inner",
getName: function() {
return function(){
return this.name;
}
}
}
object.getName()() //=> 返回的是什么?
返回的是 Outer:
var getNameFunc = object.getName() //=>function(){ return this.name }
this //=> Window {top: Window, window: Window, location: Location, external: Object, chrome: Object…}
this.name //=> “Outer”
// 我是分割线 //
var name = "Outer";
var object = {
name : "Inner",
getName: function() {
var that = this;
//console.log(this)
return function(){
return that.name;
}
}
}
object.getName()() //=> 返回的是什么?
返回的是 Inner:
var getNameFunc = object.getNameFunc() //=> function (){ return that.name; }
而这个时候 that 是调用者 object
</code></pre>
<blockquote><h3>6. 应用场景示例</h3>
<ul>
<li>立即调用函数表达式</li>
</ul>
</blockquote>
<pre><code class="javascript">(function(window){
var a = 'foo', b = 'bar';
function private(){
alert(a + b);
}
window.jQuery = {
public: private
};
})(this); //=> this-> window
jQuery.public() //=> foobar
//好处是可以避免污染全局命名空间
</code></pre>
<h2>4. 参考</h2>
<ol>
<li><a href="http://coolshell.cn/articles/6441.html">Javascript 面向对象编程</a></li>
<li><a href="http://coolshell.cn/articles/6668.html">再谈javascript面向对象编程</a></li>
<li><a href="http://www.douban.com/note/293217333/">学习 JavaScript 最难点之一 – 理解prototype(原型)</a></li>
<li><a href="http://bonsaiden.github.io/JavaScript-Garden/zh/">javascript 秘密花园</a></li>
<li><a href="http://coolshell.cn/articles/6731.html">理解Javascript的闭包</a></li>
<li><a href="http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html">学习Javascript闭包(Closure)</a></li>
<li><a href="http://yanhaijing.com/es5/">ECMAScript5.1</a></li>
<li><a href="http://es6.ruanyifeng.com/">ECMAScript 6</a></li>
</ol>
<h2>5. 版权申明</h2>
<p>如果你在哪里看到和本教程十分类似的文章,不要怀疑,就是我抄了他们的作业。</p>
<p>Kenyon</p>
Ruby 中的各种稀奇古怪的关键字
2015-05-17T00:00:00+00:00
http://kenyonduan.github.io//posts/Ruby中的各种稀奇古怪的关键字
<h1>写在前面</h1>
<p>Ruby 中有很多稀奇古怪的关键字,冷不丁的看到了一下还真不记得是个什么用法。这里就把我自己碰到的记录下来,方便下次查找 😜</p>
<h3>1. __END__(END 两边分别有两个下划线)</h3>
<p>如果一个文件包含这行代码,并且标记两边没有空白字符,Ruby 解释器会在此停止对该文件的处理。所以可以在该文件的余下部分可以包含任何内容(当然还是可以通过 IO 对象的 DATA 对其进行读取的)</p>
<pre><code class="ruby"># test.rb
def foo
puts 'bar'
end
foo()
__END__
puts 'balabala...'
# ruby test.rb => bar
</code></pre>
<h3>2. #coding: utf-8文件编码的指定</h3>
<p>告诉 Ruby 解释器该文件的编码(或者在执行 .rb 文件的时候手动指定 ruby -E utf-8)</p>
<h3>3. __ENCODING__</h3>
<p>这个是一个常量,存储了当前文件的字符编码。</p>
<pre><code class="ruby"># gbk.rb
# coding: GBK
puts __ENCODING__
# ruby gbk.rb => GBK
</code></pre>
<h3>4. 1_000_000_000 千分符</h3>
<pre><code class="ruby">1_000_000_000 # 千分符(等同于1000000000)
</code></pre>
<h3>5. <<HEAR 自定义字符串分界符(需要结束)</h3>
<p>自定义分界符内的全部作为字符串的内容</p>
<pre><code class="ruby"># test.rb
puts <<GROCERY_LIST
1. Salad mix.
2. Strawberries.*
def foo
puts '这里是里面'
end
foo()
GROCERY_LIST
def foo2
puts '这里是外面'
end
foo2()
# ruby test.rb =>
1. Salad mix.
2. Strawberries.*
def foo
puts '这里是里面'
end
foo()
这里是外面
# 备注
# GROCERY_LIST 开始标示
# GROCERY_LIST 结束标示
</code></pre>
<h3>6. `ls`</h3>
<p>由`` 包裹住的会被传递给 Kernel.` 方法,会将文本当做一个操作系统的 shell 命令来执行(所以你也可以这样去调用 Kernel.`(……),效果相同),或者使用 system(‘ls’) 也是可以的</p>
<pre><code class="ruby"># irb
`ls` # => "rubyconf.txt\ntest.rb\n"
Kernel.`'ls' # => "rubyconf.txt\ntest.rb\n"
system('ls') # => rubyconf.txt test.rb
=> true
</code></pre>
<p><em>这里捎带提一下 system、exec、`` 方法的区别,直接上代码 😊:</em></p>
<h4>1. system</h4>
<pre><code class="ruby"># test.rb
result = system("echo 'hello'")
puts 'foobar'
puts result
# ruby test.rb =>
hello
foobar
true
########## 这里是分割线 ############
# test2.rb
result = system("echo0 'hello'")
puts 'foobar'
puts result
# ruby test2.rb =>
sh: echo0: command not found
foobar
false
</code></pre>
<p><em>总结:
用system执行终端命令,命令会被执行,命令执行成功返回 true,命令执行失败返回 false,代码会继续往下执行。</em></p>
<h4>2. exec</h4>
<pre><code class="ruby"># test.rb
exec("echo 'hello'")
puts 'foobar'
# ruby test.rb => hello
</code></pre>
<p><em>总结:
后面的 puts ‘foobar’ 并没有被执行,以exec方法引导执行的程序启动的新进程会覆盖当前进程,而退出脚本。所以用exec可以执行终端命令,命令会被执行,命令执行成功后面的代码就不再继续执行了,命令执行失败,程序会报错。</em></p>
<h4>3. ``</h4>
<pre><code class="ruby"># test.rb
result = `echo 'hello'`
puts 'foobar'
puts result
# ruby test.rb => hello
foobar
hello
</code></pre>
<p><em>总结:
通过将系统 shell 包含在符号``之间, 命令执行成功返回执行结果( string 对象),命令执行失败程序会报错。</em></p>
<h3>7. === 条件相等性操作符</h3>
<p>条件相等性操作符,一般用在 case 语句的目标值是否和某个 when 从句相匹配</p>
<pre><code class="ruby">case some_object
when /a regex/
# do something
when String
# do something
when 2..4
# do something
end
# 等同
if /a regex/ === some_object
# do something
elsif String === some_object
# do something
elsif (2..4) === some_object
# do something
end
# 所以
# irb
Integer === 1 # => true
(1..5) === 5 # => true
</code></pre>
<p><em>所以可以重写该方法用来在 case 语句中决定两者是否匹配</em></p>
<h3>8. =~ 正则匹配</h3>
<p>这个是用来匹配正则表达式的</p>
<pre><code class="ruby">"aaa0" =~ /\d/ => 3 # 返回起始位置,未匹配上返回 nil
</code></pre>
<h3>9. <=> 顺序比较</h3>
<pre><code class="ruby">1 <=> 2 # => -1
1 <=> 1 # => 0
2 <=> 1 # => 1
</code></pre>
<h3>10. __FILE__ (Ruby 解释器正在执行的文件名称)</h3>
<pre><code class="ruby"># test.rb
puts __FILE__
# ruby test.rb => test.rb
</code></pre>
<h3>11. <strong>LINE</strong> (当前代码的行数(整数) 该代码属于 <strong>FILE</strong> 所代表的文件)</h3>
<pre><code class="ruby"># test.rb
# 这里是一行注释
puts __LINE__
# ruby test.rb => 2
</code></pre>
<h3>12. ::ARGV (常量前面加上两个冒号)</h3>
<p>表示在全局域内寻找 ARGV 这个常量等同于 Object::ARGV (因为不存在针对常量的 ‘全局作用域’,所以常量会被定义在 Object 里)。</p>
<p><em>PS: 另外在提一下变量和常量的一个小区别:</em></p>
<pre><code class="ruby"># 1. 变量: 当 Ruby 解释器看到对变量的赋值时,变量已经存在了
a = 1 if false
puts a #=> nil
puts b #=> NameError!
# 2. 常量: 必须真正被赋值后常量才会存在
A = 1 if false
puts A #=> NameError!
</code></pre>
<p>未完待续…😄</p>
<p>Kenyon</p>
Macbook Air 尝鲜 Yosemite
2014-10-18T00:00:00+00:00
http://kenyonduan.github.io//posts/尝鲜Yosemite
<p>昨天 Apple 推出了 Yosemite 的正式版,一时心痒痒就想体验一下新系统。在下载了大概5个小时左右后终于开始安装了 (顺便提一下在重启安装的界面最后一个步骤会卡上大概10分钟的样子,请克制住千万不要以为死机了然后去重启!):</p>
<p><img src="http://upload-images.jianshu.io/upload_images/42374-0223271cc3e0086e.png" alt="桌面" /></p>
<p><img src="http://upload-images.jianshu.io/upload_images/42374-4682ea0f92c7c61f.png" alt="版本号" /></p>
<p>短暂体验了一下还是蛮喜欢新的系统的,和 10.9 相比漂亮的很多(好多的糖果色啊……)。不过不知道是不是我的 屌丝机配置比较低的缘故,升级后感觉比较烫手,温度比 10.9 的时候高上不少:</p>
<p><img src="http://upload-images.jianshu.io/upload_images/42374-20f9db5fecf48bd9.png" alt="温度情况" /></p>
<p>升级之前也一直担心内存不够用的情况,不过好像没有碰到(虚惊一场):</p>
<p><img src="http://upload-images.jianshu.io/upload_images/42374-06ae48c414d83d2f.png" alt="内存占用情况" /></p>
<p>可以看到在后台开着几个程(QQ 音乐、Chrome、iTerm 2)序的情况下大概用了 30% 左右的内存,和 10.9 差别不大。其他的像是程序的兼容性问题也暂时没遇到。</p>
<p>综合看起来,如果你不介意提升的那些温度的话,低配的 Macbook Air 也是可以很好的运行 Yosemite 的。(土豪请无视) 值得升级尝鲜一下, Enjoy it! : )</p>
<p>Kenyon at 18/10/2014.</p>
说说如何黑掉别人的无线路由器
2014-06-08T00:00:00+00:00
http://kenyonduan.github.io//posts/说说如何黑掉别人的无线路由器
<p>前段时间一时兴起想试试破解一下无线路由器的密码,也正好家里有一台闲置的无线路由器,于是就拿它玩了下破解。</p>
<p>现行的破解一般是这两种:一、抓取握手包然后使用外置字典暴力破解。二:穷举Ping来破解,这两种方式的各有千秋。</p>
<p>先说说第一种,这种方式理论上来说成功率是100%的,当然前提是强悍的字典+牛叉的机器+无敌的人品。这种方式的原理在于现在的无线路由器有这样一个机制,就是当我们的手机、电脑等客户端在和无线路由器通讯呢过程中如果发现断线了,它们之间就会互相向对方发送一个握手包,来达到重新连接,这个握手包内就包含了加密过后的密码信息。所以我们就可以使用Linux下的一个叫做水滴或者奶瓶的软件来发送大量垃圾数据攻击路由器的客户端导致断线并互传握手包,这个时候我们就可以捕捉到这个握手包信息。拿到这个握手吧之后就可以导出到windows下然后使用一款叫做EWSA的跑包工具使用准备好的字典来尝试匹配密码了。剩下的就看运气和字典了。(看到过有人在淘宝上购买代跑包的服务,尝试了几十个G的字典还没出密码的…囧)</p>
<p>第一种需要强大的运气不怎么靠谱,那就再来看看第二种方式吧~这个破解的原理基于现在的无线路由大部分都含有一个叫做WPS的功能(跟金山的那个WPS不是一回事….),这个功能是为了方便连入无线网而设计的,但是问题就出在这儿了!这个功能的原理是我们的路由器有一个初始的Ping值,只要客户端知道这个值就可以不用输入密码直接连接上无线网,这个值是一个八位十进制数,并且最后一位(第8位)为校验位(可根据前7位算出),验证时需要先检测前4位,如果一致则反馈一个信息,所以只需1万次就可完全扫描一遍前4位,前4位确定下来的话,只需再试1000次(接下来的3位),校验位可通过前7为算出,就可暴力验证出pin码。所以大概只需要最多尝试10000+1000+10次=11010次就可以获得PIN,从而获得wifi密码,是不是简单很多?先别激动,理想是丰满的,现实却是骨感的。现在市面上大部分的路由器一部分已经有了防止Ping的防御机制,一部分Ping一段时间就会导致路由器假死了,所以说这种破解方式也是非常要耐心和运气的。</p>
<p>好了,讲了这么多破解相关的方法。什么?你说你也想试试?放上具体的步骤和相关工具。</p>
<p>1.首先你需要准备一个无线网卡(如果你的笔记本内置网卡能够被识别也是可以的),需要8187或者3070芯片的。
2.下载好一个破解用的Linux系统,我用的是CDLinux
3.CDLinux在虚拟机内搭建起来。
4.插上无线网卡,打开CDLinux内的那个外形像奶瓶的软件,就可以抓包了或者点击Rever启动Ping破解,剩下的就是等待了。</p>
<p>最后,祝你成功。 : )</p>
<p>附:</p>
<p>我购买的无线上网卡: http://item.jd.com/282728.html</p>
<p>CDLinux下载地址: http://kuai.xunlei.com/d/IZBYNGEUBZMX</p>
<p>详细的教程: http://hi.baidu.com/sese_shenqiu/item/06667737932d6c4e033edc6a</p>
Hello Github~
2014-04-16T00:00:00+00:00
http://kenyonduan.github.io//posts/first-blog
<p>经过一个晚上的努力,总算将自己的 Blog 在 Github Pages 上搭建起来了 : ) 。话说Github 提供的这个 Github Pages 还是蛮好的,不用考虑流量、带宽、服务器这些东西,嘿嘿~ 之前也尝试着搭过一个,不过一直偷懒没有去写点什么东西。</p>
<p>第一次尝试着使用 Markdown 这种标记语言来写了这篇 Blog,语法看起来还挺简单的,基本上花个十来分钟就能简单上手。</p>
<p>顺便提一下,我使用的是在 Github 上找到的一个<a href="https://github.com/holman/left">Left</a>主题,如果你也有兴趣你可以去<a href="http://jekyllthemes.org/">这里</a>找找看有没有自己喜欢的。另外推荐一个不错的在线Markdown编辑器-<a href="http://jianshu.io/writer#/">简书</a>,它的预览功能很符合我的需求,这里有它的简单使用<a href="http://jianshu.io/p/q81RER">教程</a>。</p>
<p>Kenyon</p>