JavsScript 設計模式(一)

JavsScript 設計模式(一)

讀完本文可以學到

  1. this花鹅、call、apply交掏、bind
  2. 閉包
  3. 什么是高階函數(shù)
  4. 高階函數(shù)的應用妆偏,包括AOP、currying盅弛、debounce等

[TOC]

之所以在學習設計模式之前钱骂,先理解這些內容,是因為設計模式里面很多函數(shù)作為參數(shù)挪鹏,或者作為返回的值见秽,還有很多call和apply的使用。

1. this讨盒、call解取、apply和bind

1.1 this

我們知道,this指向一個對象返顺,具體的指向由運行時基于函數(shù)的執(zhí)行環(huán)境動態(tài)來綁定的禀苦,需要注意的地方時蔓肯,this不一定指向函數(shù)被聲明時的環(huán)境≌穹Γ總結來說就是this指向最后調用它的那個對象蔗包。

看一個例子:

var outername = 'window';
var obj = {
    fn: function(){
        console.log(this.name);
    }
}
console.log(obj.fn())

輸出的結果是undefined,因為最后調用fn的對象是obj慧邮,而對象obj中沒有name的定義调限,所有就是undefined。這說明this永遠指向最后調用它對象赋咽,也不會繼續(xù)向上一個對象尋找this.name。

改變this的指向吨娜,除了不常用的with和eval之外脓匿,通常有5種方式

  • 作為對象的方法調用
    當作為函數(shù)的方法調用時,this指向該對象
var outername = 'window';
var obj = {
    fn: function(){
        console.log(this.name);
        console.log(this === obj);
    }
}

obj.fn()
  • 作為普通函數(shù)調用
    此時this指向window對象
var outername = 'window';
var obj = {
    fn: function(){
        console.log(this.name);
        console.log(this === obj);
    }
}

var objFn = obj.fn宦赠;
objFn();
  • 作為構造函數(shù)調用
    通常情況下陪毡,構造器里面的this就是指向返回的這個對象
var Myconstructor = function (){
    this.name ='inner'
};

var myInstance = new Myconstructor();
myInstance.name;

這里需要注意的是,如果構造函數(shù)中沒有顯示的返回一對象勾扭,那么this指向的就是構造函數(shù)毡琉,否則指向返回的那個對象。

var Myconstructor = function (){
    this.name ='inner';
    return {
        name: 'inreturn',
    };
};

var myInstance = new Myconstructor();
myInstance.name;
  • ES6 的箭頭函數(shù)
    箭頭函數(shù)的this始終指向函數(shù)定義時的this妙色,而非執(zhí)行時桅滋。

  • 通過Function.prototype.call或者Function.prototype.apply來調用
    call和apply可以動態(tài)的傳入函數(shù)的this

var obj = {
 name: 'obj';
 getName: function(){
   return this.name;
 }
}

var obj1 = {
  name: 'obj1'
}

obj.getName()
obj.getName.call(obj1);

1.2 call

語法:

fun.call(thisArg[, arg1[, arg2[, ...]]])

thisArg代表fun運行時指定的this的值

call() 方法調用一個函數(shù), 其具有一個指定的this值和分別地提供的參數(shù)(參數(shù)的列表)

我們先看個例子:

var foo = {
    value: 1
};

function bar() {
    console.log(this.value);
}

bar.call(foo); // 1

如何來簡單的實現(xiàn)這個call方法呢?
我們把上面的代碼修改成:

var foo = {
    value: 1,
    bar: function() {
        console.log(this.value)
    }
};

foo.bar(); // 1

可以看到,this指向了foo身辨,但是缺點是在foo上增加了一個方法丐谋,不過沒關系,我們用完刪了不就可以了煌珊,所以我們來看看步驟:

  • 把函數(shù)設置為對象的屬性
  • 執(zhí)行該函數(shù)
  • 刪除該函數(shù)
Function.prototype.call2 = function(context) {
    // 首先要獲取調用call的函數(shù)号俐,用this可以獲取
    context.fn = this;
    context.fn();
    delete context.fn;
}

看一個如何模擬call方法

Function.prototype.call = function(context) {
  var context = context || window;
  context.fn = this;
  var args = Array.prototype.slice.call(arguments,1);
  var result = context.fn(...args);
  delete context.fn
  return result;
} 

如何去模擬實現(xiàn)call可以參考
https://github.com/mqyqingfeng/Blog/issues/11

1.3 apply

語法:

fun.apply(thisArg, [argsArray])

apply() 方法調用一個函數(shù), 其具有一個指定的this值,以及作為一個數(shù)組(或類似數(shù)組的對象)提供的參數(shù)

apply和call的區(qū)別在于傳入?yún)?shù)不一樣定庵,但是還有一個比較大的區(qū)別吏饿,call的運行效率要比apply的高。
前段時間看了underscore的源碼蔬浙,其中有這么一部分

var optimizeCb = function(func, context, argCount) {
    if (context === void 0) return func;
    switch (argCount == null ? 3 : argCount) {
      case 1: return function(value) {
        return func.call(context, value);
      };
      case 2: return function(value, other) {
        return func.call(context, value, other);
      };
      case 3: return function(value, index, collection) {
        return func.call(context, value, index, collection);
      };
      case 4: return function(accumulator, value, index, collection) {
        return func.call(context, accumulator, value, index, collection);
      };
    }
    return function() {
      return func.apply(context, arguments);
    };
  };

其他中間那些func.call是可以不寫的猪落,直接最后return func.apply不就可以了么。

apply的模擬方法和call類似就不說啦

1.4 bind

語法:

fun.bind(thisArg[, arg1[, arg2[, ...]]])

bind()方法創(chuàng)建一個新的函數(shù), 當被調用時畴博,將其this關鍵字設置為提供的值许布,在調用新函數(shù)時,在任何提供之前提供一個給定的參數(shù)序列绎晃。也就是說bind方法是創(chuàng)建一個方法蜜唾,我們必須手動的調用

作用:

  • 創(chuàng)建綁定函數(shù)杂曲,最簡單的用法是創(chuàng)建一個函數(shù),使這個函數(shù)不論怎么調用都有同樣的 this 值
this.x = 9; 
var module = {
  x: 81,
  getX: function() { return this.x; }
};

module.getX(); // 返回 81

var retrieveX = module.getX;
retrieveX(); // 返回 9, 在這種情況下袁余,"this"指向全局作用域

// 創(chuàng)建一個新函數(shù)擎勘,將"this"綁定到module對象
// 新手可能會被全局的x變量和module里的屬性x所迷惑
var boundGetX = retrieveX.bind(module);
boundGetX(); // 返回 81
  • 偏函數(shù), 另一個最簡單的用法是使一個函數(shù)擁有預設的初始參數(shù)
function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// Create a function with a preset leading argument
var leadingThirtysevenList = list.bind(undefined, 37);

var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
  • 配合setTimeout
function LateBloomer() {
  this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// Declare bloom after a delay of 1 second
LateBloomer.prototype.bloom = function() {
  window.setTimeout(this.declare.bind(this), 1000);
};

LateBloomer.prototype.declare = function() {
  console.log('I am a beautiful flower with ' +
    this.petalCount + ' petals!');
};

var flower = new LateBloomer();
flower.bloom();  // 一秒鐘后, 調用'declare'方法

我們都知道bind方法是有兼容性問題的颖榜,那么我們怎么實現(xiàn)一個bind方法呢棚饵?
我們看看最簡單的版本

Function.prototype.bind = function(context) {
    var self = this;
    return function() {
        self.apply(context);
    };
};

進階版本:

Function.prototype.bind = function(context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments, 1);
    return function() {
        var bindArgs = Array.prototype.slice.call(arguments);
        self.apply(context, arg.contact(bindArgs));
    };
}

可以傳參數(shù),可以返回函數(shù)了掩完,但是還有一個問題沒解決噪漾,因為bind方法還有一個特點:
一個綁定函數(shù)也能使用new操作符創(chuàng)建對象:這種行為就像把原函數(shù)當成構造器。提供的 this 值被忽略且蓬,同時調用時的參數(shù)被提供給模擬函數(shù)欣硼。

MDN上的版本

if (!Function.prototype.bind) {
  Function.prototype.bind = function(oThis) {
    if (typeof this !== 'function') {
      // closest thing possible to the ECMAScript 5
      // internal IsCallable function
      throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
    }

    var aArgs   = Array.prototype.slice.call(arguments, 1),
        fToBind = this,
        fNOP    = function() {},
        fBound  = function() {
          return fToBind.apply(this instanceof fNOP
                 ? this
                 : oThis,
                 // 獲取調用時(fBound)的傳參.bind 返回的函數(shù)入?yún)⑼沁@么傳遞的
                 aArgs.concat(Array.prototype.slice.call(arguments)));
        };

    // 維護原型關系
    if (this.prototype) {
      // Function.prototype doesn't have a prototype property
      fNOP.prototype = this.prototype; 
    }
    fBound.prototype = new fNOP();

    return fBound;
  };
}

2. 閉包

2.1 概念

MDN 對閉包的定義為:

閉包是指那些能夠訪問自由變量的函數(shù)

那么這里我們需要理解什么是自由變量

自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也不是函數(shù)的局部變量的變量

舉個例子:

var a = 1;
function foo() {
    console.log(a);
}

foo();

foo 函數(shù)可以訪問a恶阴,并且a不是函數(shù)參數(shù)也不是函數(shù)局部變量诈胜,所有foo函數(shù)和a就形成了閉包。

理論上來說所有的函數(shù)都是閉包冯事,但是在實踐角度來說閉包的定義是:

  • 首先是一個函數(shù)
  • 函數(shù)的上下文即使已經(jīng)銷毀焦匈,它依然存在
  • 函數(shù)的代碼中應用了自由變量

我們先看一個簡單的例子:

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

var f = func();

f();
f();
f();

我們可以看到,當退出函數(shù)之后昵仅,局部變量a并沒有消失缓熟。只是因為在執(zhí)行var f = func()時,f返回了一個匿名函數(shù)的引用摔笤,這個函數(shù)可以訪問到a變量荚虚,所以a沒有被銷毀

2.2 應用

  • 封裝變量
    閉包可以把一些不需要暴露在全局變量中的變量封裝為私有變量
var mult = function() {
    var a = 1;
    for(var i = 0; i < arguments.length; i++) {
        a = a * arguments[i];
    }
    return a;
}

這個函數(shù)本身沒啥問題,那么如果我們需要把算出來的結果緩存一波籍茧,怎么辦呢版述?

var cache = {};
var mult = function() {
    var args = Array.prototype.join.call(arguments, ',');
    if (cache[args]) {
        return cache[args];
    }
    var a = 1;
    for (var i = 0, l = arguments.length; i < l; i++) {
        a = a * arguments[i];
    }
    return cache[args] = a;
}

這樣似乎可以解決問題,但是caches暴露在了外部寞冯,我們可能改變它的值渴析。


var mult = (function() {
    var cache = {};
    return function(){
        var args = Array.prototype.join.call(arguments, ',');
        if (cache[args]) {
            return cache[args];
        }
        var a = 1;
        for (var i = 0, l = arguments.length; i < l; i++) {
            a = a * arguments[i];
        }
        return cache[args] = a;
    }
})()

我們看到這個函數(shù)和上面沒啥大的區(qū)別,就是用一個立即執(zhí)行函數(shù)把之前的mult函數(shù)包裹了起來吮龄,然后返回俭茧。

  • 延續(xù)局部變量的壽命

我們看一個例子:

var report = function(src) {
    var img = new Image();
    img.src = src;
}

report('http://xxxx.img.jpg')

這個代碼看起來好像沒啥問題,但是在IE7之類的低版本瀏覽器會有問題漓帚,report函數(shù)并不是每次都可以發(fā)起http請求母债,原因就是img是report的局部變量,當report函數(shù)調用結束之后,img局部變量就銷毀了毡们,這個時候有可能還么發(fā)起http請求迅皇,所有請求就丟失掉啦。

var report = (function() {
    var imgs = [];
    return function(src) {
        var img = new Image();
        imgs.push(img);
        img.src = src;
    }
})()

2.3 閉包與設計模式

在設計模式中衙熔,有很多的地方用到了閉包登颓,例如命令模式等等。后續(xù)再詳細的介紹

3. 高階函數(shù)概念

高階函數(shù)是指至少滿足下列兩個條件之一的函數(shù)

  • 函數(shù)可以作為參數(shù)被傳遞
  • 函數(shù)可以作為返回值輸出

3.1 函數(shù)作為參數(shù)傳遞

  • 作為回調函數(shù)
    如要我們需要對業(yè)務做一個流程的控制红氯,可以利用回調函數(shù)來實現(xiàn)框咙,例如做完A,然后才去做B
var doA = function (callback) {
    console.log('do a')
    callback();
}

var doB = function(){
    console.log('do b');
}

doA(doB);
  • Array.prototype.sort
    接受一個函數(shù)作為參數(shù)

3.2 函數(shù)作為返回值

其實簽名的例子就有函數(shù)作為返回值的例子痢甘,我們接下來看兩個例子

  • 判斷數(shù)據(jù)類型
    我們之前其實知道了如何去判斷一個數(shù)據(jù)是否為數(shù)組或者字符串
var isArray = function(obj) {
    return Object.prototype.toString.call(obj) == '[object Array]'
};
var isString = function(obj) {
    return Object.prototype.toString.call(obj) == '[object String]'
};

其實這些代碼都是重復的喇嘱,我們可以返回一個函數(shù)來減少代碼

var isType = function(type) {
    return function(obj) {
        return Object.prototype.toString.call(obj) == '[object ' + type + ' ]';
    };
}

var isString = isType('String');
var isArray = isType('Array');
  • getSingle
    我們再來看一個單例模式的例子:
var getSingle = function ( fn ) {
     var ret; 
     return function () { 
        return ret || ( ret = fn.apply( this, arguments ) ); 
     }; 
};

我們可以看到這里既把函數(shù)作為了輸出,又把函數(shù)作為了返回值塞栅,我們看單例模式的應用:

var getNode = getSingle(function(){
    return document.createElement('script');
});

var node1 = getNode();
var node2 = getNode();

node1 === node2

4. 高階函數(shù)的應用

4.1 高階函數(shù)與AOP

AOP 也叫做面向切面編程者铜,作用就是把一些和核心業(yè)務邏輯無關的代碼抽離出來,比如說:日志處理构蹬、安全控制王暗、異常處理等等悔据。在Java中可以利用反射和動態(tài)代理來實現(xiàn)AOP庄敛,而對于JavaScript這種動態(tài)語言來說,它天生就有這種能力科汗,利用Function.prototype就可以很容易做到AOP編程

Function.prototype.before = function(beforefn) {
    var _self = this;
    // 這里保持了原函數(shù)的引用
    return function(){
        // 返回包含了原函數(shù)和新函數(shù)的代理函數(shù)
        beforefn.apply(this, arguments);
        // 執(zhí)行函數(shù)藻烤,并且保證this不被劫持,新函數(shù)接受的參數(shù)也會被傳入原來的函數(shù)头滔,新函數(shù)在原函數(shù)之前執(zhí)行
        return _self.apply(this, arguments);
        // 執(zhí)行原函數(shù)并返回原函數(shù)的執(zhí)行結果
        // 并且保證this不被劫持
    }
}

Function.prototype.after = function(afterfn) {
    var _self = this;
    return function() {
        var ret = _self.apply(this, arguments);
        afterfn.apply(this, arguments);
        return ret;
    };
}

var func = function(){
    console.log('2');
}

func = func.before(function(){
    console.log('1');
}).after(function(){
    console.log('3');
});

func();

這其實就是裝飾者模式

4.2 高階函數(shù)與柯里化

柯里化定義

In mathematics and computer science, currying is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument.

柯里化作用

  • 延遲計算
  • 參數(shù)復用
  • 動態(tài)生產函數(shù)的作用

看個例子吧

function add(a, b) {
    return a + b;
}
add(1, 2) // 3

// 假設有一個 curry 函數(shù)可以做到柯里化
var addCurry = curry(add);
addCurry(1)(2) // 3

用閉包把參數(shù)保存起來怖亭,當參數(shù)的數(shù)量足夠執(zhí)行函數(shù)了,就開始執(zhí)行函數(shù)坤检,有沒有毛病

我們看一個版本的實現(xiàn)

function curry(fn, args) {
    var length = fn.length;

    args = args || [];

    return function() {

        var _args = args.slice(0),

            arg, i;

        for (i = 0; i < arguments.length; i++) {

            arg = arguments[i];

            _args.push(arg);

        }
        if (_args.length < length) {
            return curry.call(this, fn, _args);
        }
        else {
            return fn.apply(this, _args);
        }
    }
}


var fn = curry(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", "b", "c") // ["a", "b", "c"]
fn("a", "b")("c") // ["a", "b", "c"]
fn("a")("b")("c") // ["a", "b", "c"]
fn("a")("b", "c") // ["a", "b", "c"]

再看一個高顏值的寫法

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, args

4.3 高階函數(shù)與函數(shù)防抖

其實函數(shù)防抖以前分享過一次兴猩,但是只是分享了場景和underscore的api,這里我們仔細看一下如何去實現(xiàn)一個函數(shù)防抖

防抖的原理就是早歇,隨便怎么觸發(fā)事件倾芝,但是事件只會在n秒之后才執(zhí)行,但是如果在n秒內你又觸發(fā)了箭跳,那就重新計時晨另,總之就是我一定要等你觸發(fā)完事件了,并且n秒內不再觸發(fā)谱姓,我才執(zhí)行

先看第一版

function debounce(func, wait) {
    var timeout;
    return function() {
        clearTimeout(timeout);
        timeout = setTimeout(func, wait);
    }
}

container.onmousemove = debounce(doSomething, 1000);

如果不使用debounce函數(shù)借尿, doSomething中的this指向的是container函數(shù),使用了之后this指向了window對象,所以上面的版本是有問題的

function debounce(func, wait) {
    var timeout;
    return function(){
        clearTimeout(timeout);
        var context = this;
        timeout = setTimeout(function(){
        func.apply(context);
        }, wait);  
    };
}

但是這個函數(shù)還是有問題路翻,因為dosomething(e)中的e在經(jīng)過debounce后打印出來的是undefined狈癞。其實只需要把參數(shù)綁定到新的函數(shù)就可以啦

function debounce(func, wait) {
    var timeout;
    return function(){
        clearTimeout(timeout);
        var context = this;
        var args = arguments;
        timeout = setTimeout(function(){
        func.apply(context, args);
        }, wait);  
    };
}

我們做了兩件事

  • 改變了this的指向
  • 綁定了參數(shù)event

我們可以考慮一個新的需求,我們希望事件立即被觸發(fā)帚桩,然后等停止觸發(fā)n秒后亿驾,才重新觸發(fā)函數(shù)

function debounce(func, wait, immediate) {

    var timeout, result;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            // 如果已經(jīng)執(zhí)行過,不再執(zhí)行
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

接下來我們看看underscore的實現(xiàn)

  _.debounce = function(func, wait, immediate) {
    var timeout, args, context, timestamp, result;

    var later = function() {
      var last = _.now() - timestamp;

      if (last < wait && last >= 0) {
        timeout = setTimeout(later, wait - last);
      } else {
        timeout = null;
        if (!immediate) {
          result = func.apply(context, args);
          if (!timeout) context = args = null;
        }
      }
    };

    return function() {
      context = this;
      args = arguments;
      timestamp = _.now();
      var callNow = immediate && !timeout;
      if (!timeout) timeout = setTimeout(later, wait);
      if (callNow) {
        result = func.apply(context, args);
        context = args = null;
      }

      return result;
    };
  };

參考資料:

書籍:《JavaScript設計模式與實踐》
博客鏈接:https://github.com/mqyqingfeng/Blog/issues/22

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末账嚎,一起剝皮案震驚了整個濱河市莫瞬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌郭蕉,老刑警劉巖疼邀,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異召锈,居然都是意外死亡旁振,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門涨岁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拐袜,“玉大人,你說我怎么就攤上這事梢薪〉牌蹋” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵秉撇,是天一觀的道長甜攀。 經(jīng)常有香客問我,道長琐馆,這世上最難降的妖魔是什么规阀? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮瘦麸,結果婚禮上谁撼,老公的妹妹穿的比我還像新娘。我一直安慰自己滋饲,他們只是感情好厉碟,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著了赌,像睡著了一般墨榄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上勿她,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天袄秩,我揣著相機與錄音,去河邊找鬼。 笑死之剧,一個胖子當著我的面吹牛郭卫,可吹牛的內容都是我干的。 我是一名探鬼主播背稼,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼贰军,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蟹肘?” 一聲冷哼從身側響起词疼,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎帘腹,沒想到半個月后贰盗,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡阳欲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年舵盈,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片球化。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡秽晚,死狀恐怖,靈堂內的尸體忽然破棺而出筒愚,到底是詐尸還是另有隱情赴蝇,我是刑警寧澤,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布锨能,位于F島的核電站扯再,受9級特大地震影響芍耘,放射性物質發(fā)生泄漏址遇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一斋竞、第九天 我趴在偏房一處隱蔽的房頂上張望倔约。 院中可真熱鬧,春花似錦坝初、人聲如沸浸剩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绢要。三九已至,卻和暖如春拗小,著一層夾襖步出監(jiān)牢的瞬間重罪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工装哆, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留阵难,地道東北人摘盆。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓精盅,卻偏偏與公主長得像藕施,于是被迫代替她去往敵國和親蔗彤。 傳聞我的和親對象是個殘疾皇子孝扛,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內容

  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,798評論 0 38
  • 函數(shù)和對象 1舀锨、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念蝇更。通過函數(shù)可以封裝任意多條語句沪编,而且...
    道無虛閱讀 4,564評論 0 5
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,149評論 0 13
  • 《JavaScript設計模式與開發(fā)實踐》作者:曾探 系統(tǒng)的介紹了各種模式年扩,以及js中的實現(xiàn)漾抬、應用,以及超大量高質...
    undefinedR閱讀 812評論 0 10
  • 感悟:人生會經(jīng)歷不同的階段常遂,會有不同的變化纳令,公司也是會從小到大人也越來越多所以管理模式也會在不斷的變化,同樣管理模...
    臨淄茂業(yè)DDM黃紅閱讀 173評論 0 0