函数本身就是一段JavaScript代码,定义一次但可能被调用任意次。如果函数挂载在一个对象上,作为对象的一个属性,通常这种函数被称作对象的方法。用于初始化一个新创建的对象的函数被称作构造函数。

相对于其他面向对象语言,在JavaScript中的函数是特殊的,函数即是对象。JavaScript可以把函数赋值给变量,或者作为参数传递给其他函数,甚至可以给它们设置属性等。

JavaScript的函数可以嵌套在其他函数中定义,这样定义的函数就可以访问它们外层函数中的任何变量。这也就是所谓的“闭包”,它可以给JavaScript带来强劲的编程能力。

1.函数定义

函数使用function关键字定义,有函数语句函数表达式两种定义方式。

//一.函数语句类:

//打印对象所有属性名称和值。
function printprops(obj) {
    for (var key in obj) {
        console.log(key + ":" + obj[key]);
    }
}
//计算阶乘的递归函数,函数名称将成为函数内部的一个局部变量。
function factorial(n) {
    if (n <= 1) return 1;
    return n * factorial(n);
}

//二.函数表达式类:

//计算n的平方的函数表达式。这里将一个函数赋给一个变量。
var square = function (x) { return x * x; }

//兔子数列。函数表达式也可以包含名称,方便递归。
var foo = function foo(n) {
    if (n <= 1) return 1;
    else foo(n - 1) + foo(n - 2);
}

//数组元素升序排列。函数表达式也能作为参数传递给其他函数。
var data = [5, 3, 7, 2, 1];
data.sort(function (a, b) { return a - b; });

//函数表达式有时定义后立即调用。
var tensquared = (function (x) { return x * x; }(10));

函数命名
函数名称要求简洁、描述性强,因为这样可以极大改善代码的可读性,方便别人维护代码;函数名称通常是动词或以动词开头的词组。通常来说,函数名编写有两种约定:

  1. 一种约定是函数名第一个单词首字母小写,后续单词首字母大写,就像likeThis()
  2. 当函数名包含多个单词时,另一种约定是用下划线来分割单词,就像like_this()

项目中编写方法名时尽量选择一种保持代码风格一致。还有,对于一些私有函数(不作为公用API的一部分),这种函数通常以一条下划线作为前辍。

2.函数调用

函数声明后需要通过调用才能被执行。JavaScript中通常有4种方式来调用函数:

  1. 作为普通函数;
  2. 作为对象方法;
  3. 作为构造函数;
  4. 通过它们的call()apply()方法间接调用。

下面就通过一些具体示例来演示上述4中函数的调用方式。

1.对于普通函数,通过调用表达式就可直接调用,这种方式很直接也很常见。

//定义一个普通函数。
var strict = function () { return !this; }; //检测当前运行环境是否为严格模式。
//通过函数名直接调用。
console.log(strict()); 

注:根据ES3和非严格的ES5对普通函数调用的规定,调用上下文(this)是全局对象;在严格模式下,调用上下文则是undefined。

2.通常,保存在对象属性里的JavaScript函数被称作“方法”。

//定义一个对象直接量。
var calc = {
    a: null,
    b: null,
    add: function () { //将函数保存在对象属性中。
        return this.a + this.b;
    }
};
//通过对象名调用方法。
calc.a = 1, calc.b = 2;
console.log(calc.add()); 

注:对象方法中的调用上下文(this)不同于普通函数中的上下文。这里this指代当前对象。

方法链:当方法返回值是一个对象,那么这个对象还可以再调用它的方法。每次调用的结果都是另外一个表达式的组成部分,这种方法调用方式最终会形成一个序列,也被称为“方法链”。所以,在自己设计API的时候,当方法并不需要返回值时,最好直接返回this。这样以后使用API就可以进行“链式调用”风格的编程。

需要注意的是,this是一个关键字,Javascript语法不允许给它赋值。再者,关键字this没有作用域的限制,嵌套的函数不会从外层调用它的函数中继承this。也就是说,如果嵌套函数作为方法调用,其this指向为调用它的对象。如果嵌套函数作为函数调用,其this值不是全局对象就是undefined。下面通过一段代码来具体说明。

var o = {
    m: function () { //对象中的方法
        var self = this; //将this的值保存在一个变量中
        console.log(this === o); //输出true,表明this就是这个引用对象o
        f(); //调用嵌套函数f()
        function f() { //定义一个嵌套函数(**普通函数,非对象方法)
            console.log(this === o); //输出false,this的值为全局对象或undefined
            console.log(self === o); //输出true,变量self指外部函数的this值
        }
    }
}

3.如果函数或者防方法调用之前带有关键字new,它就构成构造函数调用。构造函数调用会创建一个新的对象,构造函数通常不使用return,函数体执行完毕它会显示返回。还有,创建的对象继承自构造函数的prototype属性,构造函数中使用this关键字来引用这个新创建的对象。

//与普通函数一样的定义方式。
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.say = function () {
        console.log("My name is " + this.name + ", I am " + this.age + " years old.");
    }
}
//用关键字new调用构造函数,实例化对象。
var obj = new Person("Lamb", "21");
obj.say();//调用对象方法。

4.我们知道Javascript中的函数也是对象,所以函数对象也是可以包含方法的,其中call()apply()两个方法可以用来间接地调用函数,这两个方法都可以显式指定调用函数里面的调用上下文this

//定义一个打印函数。
function print() {
    if (this.text) {
        alert(this.text);
    } else {
        alert("undefined");
    }
}
//call方法间接调用方法,并指定其调用上下文。
print.call({ text: "hello" });

关于call()apply()两个方法的用法以及区别下面详细讨论。

3.函数的实参和形参

JavaScript中的函数定义不需要指定函数形参的类型,调用函数时也不检查传入形参的个数。这样,同时也会留下两个疑问给我们:

  1. 当调用函数时的实参个数和声明的形参个数不匹配的时候如何处理;
  2. 如何显式测试函数实参的类型,以避免非法的实参传入函数。

下面就简单介绍JavaScript是如何对上述两个问题做出处理的。

可选参数
当调用函数的时候传入的实参比函数定义时指定的形参个数要少,剩下的形参都将设置为undefined。一般来说,为了保持函数较好的适应性,都会给省略的参数设置一个合理的默认值。

function getPropertyNames(obj,/*optional*/arr) {
    arr=arr||[];
    for (var property in obj) { arr.push(property); }
    return arr;
}

需要注意的是,当使用这种可选实参来实现函数时,需要将可选实参放在实参列表的最后。一般来书,函数定义中使用注释/*optional*/来强调形参是可选的。

实参对象
当调用函数时传入的参数个数超过了原本函数定义的形参个数,那么方法中可以通过实参对象来获取,标识符arguments是指向实参对象的引用。实参对象是一个类数组对象,可以通过数字下标来访问传入函数的实参值。实参对象有一个重要的用处,就是让函数可以操作任意数量的实参,请看下面的例子:

//返回传入实参的最大值。
function max(/* ... */) {
    var max = Number.NEGATIVE_INFINITY; //该值代表负无穷大。
    for (var i = 0; i < arguments.length; i++) {
        if (arguments[i] > max) {
            max = arguments[i];
        }
    }
    return max;
}
//调用。
var largest = max(10, 45, 66, 35, 21); //=>66

还有重要的一点,如果函数中修改arguments[]元素,同样会影响对应的实参变量。

除以上之外,实参对象还包含了两个属性calleecaller

  • callee是ECMAScript标准规范的,它指代当前正在执行的函数。
  • caller是非标准属性但是大多数浏览器都支持,它指代当前正在执行函数的函数。
//callee可以用来递归匿名函数。
var sum = function (x) {
    if (x <= 1) return 1;
    return x + arguments.callee(x - 1);
}

//调用函数b,方法a中打印结果为函数b。
 var a = function () {
     alert(a.caller);
 }
 var b = function () {
     a();
 }

注意,在ECMAScript 5严格模式下,对这两个属性进行读写会产生一个类型错误。

实参类型
声明JavaScript函数时形参不需要指定类型,在形参传入函数体之前也不会做任何类型检查,但是JavaScript在必要的时候会进行类型转换,例如:

function mult(a, b) {
    return a * b;
}
function conn(x, y) {
    return x + y;
}
console.log(mult(3, "2")); //字符串类型自动转为数字类型,输出结果:6
console.log(conn(3, "2")); //数字类型自动转为字符串类型,输出结果:"32"

上述的两种类型存在隐式转换关系所以JS可以自动转换,但是还存在其他情况:比如,一个方法期望它第一个实参为数组,传入一个非数组的值就可能引发问题,这时就应当在函数体中添加实参类型检查逻辑。

4.作为值的函数

开篇提到过,在JavaScript中函数不仅是一种语法,函数即是对象,简单归纳函数具有的几种性质:

1.函数可以被赋值给一个变量;

function square(x) { return x * x; }
var s = square; //现在s和square指代同一个函数对象
square(5); //=>25
s(5); //=>25

2.函数可以保存在对象的属性或数组元素中;

var array = [function (x) { return x * x; }, 20];
array[0](array[1]); //=>400

3.函数可以作为参数传入另外一个函数;

//这里定义一些简单函数。
function add(x, y) { return x + y; }
function subtract(x, y) { return x - y; }
function multipty(x, y) { return x * y; }
function divide(x, y) { return x / y; }
//这里函数以上面某个函数做参数。
function operate(operator, num1, num2) {
    return operator(num1, num2);
}
//调用函数计算(4*5)-(2+3)的值。
var result = operate(subtract, operate(multipty, 4, 5), operate(add, 2, 3));
console.log(result); //=>15

4.函数可以设置属性。

//初始化函数对象的计数器属性。
uniqueInteger.counter = 0;
//先返回计数器的值,然后计数器自增1。
function uniqueInteger() {
    return uniqueInteger.counter+=1;
}

当函数需要一个“静态”变量来在调用时保持某个值不变,最方便的方式就是给函数定义属性,而不是定义全局变量,因为定义全局变量会让命名空间变的杂乱无章。

5.作为命名空间的函数

函数中声明的变量只在函数内部是有定义,不在任何函数内声明的变量是全局变量,它在JavaScript代码中的任何地方都是有定义的。JavaScript中没有办法声明只在一个代码块内可见的变量的。基于这个原因,常常需要定义一个函数用作临时的命名空间,在这个命名空间内定义的变量都不会污染到全局变量。

//该函数就可看作一个命名空间。
function mymodule() {
    //该函数下的变量都变成了“mymodule”空间下的局部变量,不会污染全局变量。
}
//最后需要调用命名空间函数。
mymodule();

上段代码还是会暴露出一个全局变量:mymodule函数。更为常见的写法是,直接定义一个匿名函数,并在单个表达式中调用它:

//将上面mymodule()函数重写成匿名函数,结束定义并立即调用它。
(function () {
    //模块代码。
}());

6.闭包

闭包是JavaScript中的一个难点。在理解闭包之前先要明白变量作用域函数作用域链两个概念。

  • 变量作用域:无非就是两种,全局变量和局部变量。全局变量拥有全局作用域,在任何地方都是有定义的。局部变量一般是指在函数内部定义的变量,它们只在函数内部有定义。

  • 函数作用域链:我们知道JavaScript函数是可以嵌套的,子函数对象会一级一级地向上寻找所有父函数对象的变量。所以,父函数对象的所有变量,对子函数对象都是可见的,反之则不成立。需要知道的一点是,函数作用域链是在定义函数的时候创建的。

关于“闭包”的概念书本上定义很具体,但是也很抽象,很难理解。简单的理解,“闭包”就是定义在一个函数内部的函数(这么说并不准确,应该说闭包是函数的作用域)。

var scope = "global scope"; //全局变量
function checkscope() {
    var scope = "local scope"; //局部变量
    function f() { return scope; } //在作用域中返回这个值
    return f();
}
checkscope(); //=>"local scope"

上面一段代码就就实现了一个简单的闭包,函数f()就是闭包。根据输出结果,可以看出闭包可以保存外层函数局部变量,通过闭包可以把函数内的变量暴露在全局作用域下。

闭包有什么作用呢?下面一段代码是上文利用函数属性定义的一个计数器函数,其实它存在一个问题:恶意代码可以修改counter属性值,从而让uniqueInteger函数计数出错。

//初始化函数对象的计数器属性。
uniqueInteger.counter = 0;
//先返回计数器的值,然后计数器自增1。
function uniqueInteger() {
    return uniqueInteger.counter+=1;
}

闭包可捕捉到单个函数调用的局部变量,并将这些局部变量用作私有状态,故我们可以利用闭包的特性来重写uniqueInteger函数。

//利用闭包重写。
var uniqueInteger = (function () { //定义函数并立即调用
    var counter = 0; //函数的私有状态
    return function () {
        return counter += 1;
    };
})();
//调用。
uniqueInteger(); //=>1
uniqueInteger(); //=>2
uniqueInteger(); //=>3

当外部函数返回后,其他任何代码都无法访问counter变量,只有内部的函数才能访问。根据输出结果可以看出,闭包会使得函数中的变量都被保存在内存中,内存消耗大,所以要合理使用闭包。

counter一样的私有变量在多个嵌套函数中都可以访问到它,因为这多个嵌套函数都共享同一个作用域链,看下面一段代码:

function counter() {
    var n = 0;
    return {
        count: function () { return n += 1; },
        reset: function () { n = 0; }
    };
}
var c = counter(), d = counter(); //创建两个计时器
c.count(); //=>0
d.count(); //=>0 能看出它们互不干扰
c.reset(); //reset和count方法共享状态
c.count(); //=>0 因为重置了计数器c
d.count(); //=>1 而没有重置计数器d

书写闭包的时候还需注意一件事,this是JavaScript的关键字,而不是变量。因为闭包内的函数只能访问闭包内的变量,所以this必须要赋给that才能引用。绑定arguments的问题与之类似。

var name = "The Window";
var object = {
    name: "My Object",
    getName: function () {
        var that = this;
        return function () {
            return that.name;
        };
    }
};
console.log(object.getName()()); //=>"My Object"

到这里如果你还不明白我在说什么,这里推荐两篇前辈们写的关于“闭包”的文章。
阮一峰,学习Javascript闭包(Closure)
russj,JavaScript 闭包的理解

7.函数属性、方法和构造函数

前文已经介绍过,在JavaScript中函数也是对象,它也可以像普通对象一样拥有属性和方法。

length属性
在函数体里,arguments.length表示传入函数的实参的个数。而函数本身的length属性表示的则是“形参”,也就是在函数调用时期望传入函数的实参个数。

function check(args) {
    var actual = args.length; //参数的真实个数
    var expected = args.callee.length; //期望的实参个数
    if (actual!=expected) { //如果不同则抛出异常
        throw Error("Expected "+ expected+"args;got "+ actual);
    }
}
function f(x,y,z) {
    check(arguments); //检查实参和形参个数是否一致。
    return x + y + z;
}

prototype属性
每个函数都包含prototype属性,这个属性指向一个对象的引用,这个对象也就是原型对象。当将函数用作构造函数的时候,新创建的对象会从原型对象上继承属性。

call()方法和apply()方法
上文提到,这两个方法可以用来间接调用函数。call()apply()的第一个实参表示要调用函数的母对象,它是调用上下文,在函数内通过this来引用母对象。假如要想把函数func()以对象obj方法的形式来调用,可以这样:

func.call(obj);
func.apply(obj);

call()apply()的区别之处是,第一个实参(调用上下文)之后的所有实参传入的方式不同。

func.call(obj, 1, 2); //实参可以为任意数量
func.apply(obj, [1, 2]); //实参都放在了一个数组中

下面看一个有意思的函数,他能将一个对象的方法替换为一个新方法。这个新方法“包裹”了原始方法,实现了AOP。

//调用原始方法之前和之后记录日志消息
function trace(o, m) {
    var original = o[m]; //在闭包中保存原始方法
    o[m] = function () { //定义新方法
        console.log(new Date(), "Entering:", m); //输出日志消息
        var result = original.apply(o, arguments); //调用原始方法
        console.log(new Date(), "Exiting:", m); //输出日志消息
        return result; //返回结果
    }
}

这种动态修改已有方法的做法,也被称作“猴子补丁(monkey-patching)”。

bind()方法
bind()方法是ES5中新增的方法,这个方法的主要作用是将函数绑定至某个对象。该方法会返回一个新的函数,调用这个新的函数会将原始函数当作传入对象的方法来调用。

function func(y) { return this.x + y; } //待绑定的函数
var o = { x: 1 }; //将要绑定的对象
var f = func.bind(o);//通过调用f()来调用o.func()
f(2); //=>3

ES3中可以通过下面的代码来实现bind()方法:

if (!Function.prototype.bind) {
    Function.prototype.bind = function (o /* , args */) {
        //将this和arguments保存在变量中,以便在嵌套函数中使用。
        var self = this, boundArgs = arguments;
        //bind()方法返回的是一个函数。
        return function () {
            //创建一个参数列表,将传入bind()的第二个及后续的实参都传入这个函数。
            var args = [], i;
            for (var i = 1; i < boundArgs.length; i++) {
                args.push(boundArgs[i]);
            }
            for (var i = 0; i < arguments.length; i++) {
                args.push(boundArgs[i]);
            }
            //现在将self作为o的方法来调用,传入这些实参。
            return self.apply(o,args);
        }
    }
}

Function()构造函数
定义函数时需要使用function关键字,但是函数还可以通过Function()构造函数来定义。Function()构造函数可以传入任意数量字符串实参,最后一个实参字符串表示函数体,每两条语句之间也需要用分号分隔。

var f = Function("x", "y", "return x*y;");
//等价于下面的函数
var f = function f(x, y) { return x * y; }

关于Function()构造函数需要注意以下几点:

  • Function()构造函数允许Javascript在运行时动态创建并编译函数;
  • 每次调用Function()构造函数都会解析函数体并创建新的函数。如果将其放在循环代码块中执行,执行效率会受到影响;
  • 最重要的一点,它所创建的函数并不是使用词法作用域,相反,函数体代码的编译总是会在顶层函数执行。比如下面代码所示:

    var scope = "global scope";
    function checkscope() {
    var scope = "local scope";
    return Function("return scope;"); //无法捕获局部作用域
    }
    checkscope(); //=>"global scope"

    Function()构造函数可以看作是在全局作用域中执行的eval(),在实际开发中很少见到。

8.函数式编程

JavaScript中可以像操控对象一样操控函数,也就是说可以在JavaScript中应用函数式编程技术。

使用函数处理数组
假设有一个数组,数组元素都是数字,我们想要计算这些元素的平均值和标准差。可以利用map()reduce()等数组方法来实现,符合函数式编程风格。

//首先定义两个简单的函数。
var sum = function (x, y) { return x + y; }
var square = function (x) { return x * x }
//将上面的函数和数组方法配合使用计算出平均数和标准差。
var data = [1, 1, 3, 5, 5];
var mean = data.reduce(sum) / data.length;
var deviations = data.map(function (x) { return x - mean; });
var stddev = Math.sqrt(deviations.map(square).reduce(sum) / (data.length - 1));

高阶函数
所谓高阶函数就是函数操作函数,它接收一个或多个函数作为参数,并返回一个新的函数。

//返回传入函数func返回值的逻辑非。
function not(func) {
    return function () {
        var result = func.apply(this, arguments);
        return !result;
    };
}
//判断传入参数a是否为偶数。
var even = function (x) {
    return x % 2 === 0;
}
var odd = not(even); //odd为新的函数,所做的事和even()相反。
[1, 1, 3, 5, 5].every(odd); //=>true 每个元素都是奇数。

这里是一个更常见的例子,它接收两个函数f()g(),并返回一个新的函数用以计算f(g())

//返回一个新的函数,计算f(g(...))。
function compose(f, g) {
    return function () {
        //需要给f()传入一个参数,所以使用f()的call()方法。
        //需要给g()传入很多参数,所以使用g()的apply()方法。
        return f.call(this, g.apply(this, arguments));
    }
}

var square = function (x) { return x * x; }
var sum = function (x, y) { return x + y; }
var squareofsum = compose(square, sum);
squareofsum(2, 3); //=>25

记忆
能将上次计算的结果缓存起来,在函数式编程当中,这种缓存技巧叫做“记忆”。下面的代码展示了一个高阶函数,memorize()接收一个函数作为实参,并返回带有记忆能力的函数。

//返回f()的带有记忆功能的版本。
function memorize(f) {
    //将值保存在闭包中。
    var cache = {};
    return function () {
        //将实参转换为字符串形式,并将其用做缓存的键。
        var key = arguments.length + Array.prototype.join.call(arguments, ",");
        if (key in cache) {
            return cache[key];
        } else {
            return cache[key] = f.apply(this, arguments);
        }
    }
}

memorize()所返回的函数将它的实参数组转换成字符串,并将字符串用做缓存对象的属性名。如果缓存中存在这个值,则直接返回它,否则调用既定的函数对实参进行计算,将计算结果缓存起来并保存。下面代码展示了如何使用memorize()

//返回两个整数的最大公约数。
function gcd(a, b) {
    var temp;
    if (a < b) { //确保 a >= b
        temp = b;
        b = a;
        a = temp;
    }
    while (b != 0) { //这里是求最大公约数的欧几里德算法
        temp = b;
        b = a % b;
        a = temp;
    }
    return a;
}
var gcdmemo = memorize(gcd);
gcdmemo(85, 187);

//当写一个递归函数时,往往需要实现记忆功能。
var factorial = memorize(function (n) {
    return (n <= 1) ? 1 : n * factorial(n - 1);
});
factorial(5); //=>120

9.参考与扩展

本篇内容源自我对《JavaScript权威指南》第8章 函数 章节的阅读总结和代码实践。总结的比较粗糙,你也可通过原著或MDN更深入了解函数。

[1] David Flanagan,JavaScript权威指南(第6版)
[2] MDN,JavaScript 参考文档 - Functions - JavaScript | MDN

作者:gao-yang

出处:http://www.cnblogs.com/gao-yang/p/6256157.html

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

JavaScript权威指南 - 函数的更多相关文章

  1. JavaScript权威指南 - 对象

    JavaScript对象可以看作是属性的无序集合,每个属性就是一个键值对,可增可删. JavaScript中的所有事物都是对象:字符串.数字.数组.日期,等等. JavaScript对象除了可以保持自 ...

  2. JavaScript权威指南 - 数组

    JavaScript数组是一种特殊类型的对象. JavaScript数组元素可以为任意类型,最大容纳232-1个元素. JavaScript数组是动态的,有新元素添加时,自动更新length属性. J ...

  3. 《javascript权威指南》读书笔记——第一篇

    <javascript权威指南>读书笔记——第一篇 金刚 javascript js javascript权威指南 由于最近想系统学习下javascript,所以开始在kindle上看这本 ...

  4. 《JavaScript权威指南 第六版 中文版》(一)

    <JavaScript权威指南 第六版 中文版> 第二章 词法结构 2.1字符集 JavaScript是使用Unicode字符集编码写的. 2.1.1区分大小写 JavaScript是区分 ...

  5. javascript权威指南第6版学习笔记

    javascript权威指南第6版学习笔记 javascript数组.函数是特殊对象 看一点少一点. 3.1.4 hello.js内容是 var x=.3-.2;var y=.2-.1 console ...

  6. 《JavaScript权威指南》学习——js闭包

    序:闭包这个玩意啊~在很多没有代码块的语言中都会出现,已经成为大多程序员入门的一道坎,闭包让很多程序员觉得晦涩(事实上百度一下这个名词,真的说的很晦涩啊亲==|||),我第一次知道闭包这个名词是从&l ...

  7. 《JavaScript权威指南》读书笔记——JavaScript核心

    前言 这本由David Flanagan著作,并由淘宝前端团队译的<JavaScript权威指南>,也就是我们俗称的“犀牛书”,算是JS界公认的“圣经”了.本书较厚(有1004页),读起来 ...

  8. 【笔记】javascript权威指南-第六章-对象

    对象 //本书是指:javascript权威指南    //以下内容摘记时间为:2013.7.28 对象的定义: 1.对象是一种复合值:将很多值(原始值或者对象)聚合在一起,可以通过名字访问这些值. ...

  9. 【笔记】javascript权威指南-第三章-类型,值和变量

    javascript中的原始类型和对象类型(基本类型和引用类型) //本书是指:javascript权威指南    //以下内容摘记时间为:2013.7.27   计算机程序运行时需要对值(value ...

随机推荐

  1. HTML URL地址解析

    通过JavaScript的location对象,可获取URL中的协议.主机名.端口.锚点.查询参数等信息. 示例 URL:http://www.akmsg.com/WebDemo/URLParsing ...

  2. 【疯狂造轮子-iOS】JSON转Model系列之一

    [疯狂造轮子-iOS]JSON转Model系列之一 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 之前一直看别人的源码,虽然对自己提升比较大,但毕竟不是自己写的,很容易遗 ...

  3. ExtJS 4.2 组件介绍

    目录 1. 介绍 1.1 说明 1.2 组件分类 1.3 组件名称 1.4 组件结构 2. 组件的创建方式 2.1 Ext.create()创建 2.2 xtype创建 1. 介绍 1.1 说明 Ex ...

  4. ASP.NET MVC with Entity Framework and CSS一书翻译系列文章之第一章:创建基本的MVC Web站点

    在这一章中,我们将学习如何使用基架快速搭建和运行一个简单的Microsoft ASP.NET MVC Web站点.在我们马上投入学习和编码之前,我们首先了解一些有关ASP.NET MVC和Entity ...

  5. 算法与数据结构(十四) 堆排序 (Swift 3.0版)

    上篇博客主要讲了冒泡排序.插入排序.希尔排序以及选择排序.本篇博客就来讲一下堆排序(Heap Sort).看到堆排序这个名字我们就应该知道这种排序方式的特点,就是利用堆来讲我们的序列进行排序.&quo ...

  6. MAVEN学习-第一个Maven项目的构建

    MAVEN安装成功之后就可以进行项目的构建和管理了: 为什么要用maven进行项目的构建和管理? 对于初学者来说一个最直接的也是最容易里的优点在于JAR包的管理,相对于以前开发一个项目的时候我们需要用 ...

  7. javascript中变量提升的理解

    网上找了两个经典的例子 var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar(); // 10 var ...

  8. [原]HAproxy 代理技术原理探究

    HAproxy 技术分享 简介 HAProxy是一款提供高可用性.负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件 Features 1.免费 2.能够做到4层以上代理 3.高性能 ...

  9. 代码的坏味道(22)——不完美的库类(Incomplete Library Class)

    坏味道--不完美的库类(Incomplete Library Class) 特征 当一个类库已经不能满足实际需要时,你就不得不改变这个库(如果这个库是只读的,那就没辙了). 问题原因 许多编程技术都建 ...

  10. DOM的小练习,两个表格之间数据的移动

    本次讲的是两个表格之间数据的移动,左边的表格移动到右边,并且左边表格移动内容消失. <head>   <meta http-equiv="Content-Type" ...