Javascript语言精粹(二)

闭包

// 创建一个构造函数quo
// 它带有get_status方法和status私有属性
var quo = function(status){
    return {
        get_status: function(){
            return status;
        }
    };
};
var myQuo = quo(‘amazing‘);
alert(myQuo.get_status());

当我们调用quo时,它返回一个对象:

①该对象包含一个get_status方法,②该对象的一个引用保存在myQuo中。

即使quo已经返回了(return status;),但get_status方法仍然有访问status属性的特权。

get_status方法访问的并不是status参数的副本,而是status参数本身!

因为该函数可以访问它被创建时所处的上下文环境。也因此该函数被称为闭包。

再看一个更有用的栗子:

// 定义一个函数,它使一个DOM节点的背景色由黄变白
var fade = function(node){
    var level = 1;
    var step = function(){
        var hex = level.toString(16);
        node.style.backgroundColor = ‘#FFFF‘ + hex + hex;
        if(hex < 15){
            level += 1;
            setTimeout(step, 100);
        }
    };
    setTimeout(step, 100);
};

fade(document.body);

只要fade的内部函数step需要levellevel变量就会持续保留。

糟糕的栗子:

// 弹出节点的序号
var add_the_handlers = function(nodes){
    var i;
    for(i=0; i<nodes.length; i++){
        nodes[i].onclick = function(){
            alert(i);  //总是弹出节点的数目
        };
    }
};

未能达到目的的原因,是因为onclick时间处理器函数绑定了变量 i 本身,而不是函数在构造时的变量 i 的值

(个人理解:js解析的时候,把for循环解析了一遍, 运行的时候 i 已经等于节点数目了。绑定了 i 本身,故弹出的 i 等于节点数目。我们需要弹出的 i 是在它被构造时的值。)

解决糟糕的栗子:

var add_the_handlers = function(nodes){
    var helper = function(i){
        return function(){
            alert(i);
        };
    };

    var i;

    for(i=0; i<nodes.length; i++){
        nodes[i].onclick = helper(i);
    }
};

避免在循环中创建函数,这会带来无谓的计算,还会引起混淆。

可以在循环之外先创建一个辅助函数helper,让辅助函数返回一个绑定了当前 i 值的函数,这样就不会混淆了。

模块

我们可以使用函数和闭包来构建模块,这几乎可以完全摒弃全局变量的使用。

模块是一个提供接口却隐藏状态和实现的函数或对象。

模块模式也可以用来产生安全的对象。

我们来构造一个产生序列号的对象:

var serial_maker = function(){
// 该对象包含一个设置前缀的方法
// 该对象包含一个设置序列号的方法
// 和一个生成字符串的方法

    var prefix = ‘‘; //前缀
    var seq = 0; //序列号
    return {
        set_prefix: function(p){
            prefix = String(p);
        },
        set_seq: function(s){
            seq = s;
        },
        generate: function(){
            var result = prefix + seq;
            seq += 1;
            return result;
        }
    };
};

// 调用
var seqer = serial_maker();
seqer.set_prefix(‘Q‘);
seqer.set_seq(1000);
var unique = seqer.generate(); // "Q1000"

如果我们把seqer.generate作为一个值传递给第三方函数,这个函数能产生唯一的字符串,但却不能通过它来改变prefix和seq的值。

时间: 2024-10-19 10:14:24

Javascript语言精粹(二)的相关文章

Javascript语言精粹-毒瘤和糟粕

Javascript语言精粹-毒瘤和糟粕 博客分类: Web前端-JS语言核心 javascript 作者:zccst Javascript是一门语言,用久了肯定能够发现其中的好与不好的地方.不过大多数普通人没那么细心,所以也就忽略了,很难说出一二三来.但对于极客版的牛人就不同了,他们理解的远比普通人透彻. 二.糟粕(轻微) 一.毒瘤(严重) 1,全局变量 var foo = value; window.foo = value; foo = value; 隐患是很多时候是忘加var了 2,作用域

《JavaScript语言精粹》之函数化

写在前面 看到好多书评和读书笔记都说<JavaScript语言精粹>字字珠玑,名不虚传..当然,要看得懂才行 其实个人认为函数化部分不是很好,举的例子不是十分恰当,之前看不懂是因为被成功误导了,就像<Head First>设计模式第一章<策略模式>一样,作者有些偏离章节主题,读者容易被误导 声明:姑且把函数化部分给出的用来创建对象的函数称为“创造函数”吧,为了与“构造函数”区分开..不是很好听,将就着用吧 一.源码中需要注意的点 很容易就能拿到源码,和中文版书上的代码一

JavaScript语言精粹 笔记01

内容比较简单,只是从头梳理一下JS的知识 语法空白标识符数字字符串语句 对象对象字面量检索更新引用原型反射枚举删除减少全局变量污染  语法 1 空白 空白可能表现为格式化字符或注释的形式.空白通常没有意义,但是偶尔必须用它来分割字符序列,否则它们就会被合并成一个单一的符号.例如: var that = this; var 和that之间的空格是不能去掉的,其他的空格都可以被移除. JS提供两种注释: /* */ // 建议使用//,因为/* */中要注释的内容可能包括字符 */ 而报错,例如:

javascript语言精粹----笔记【转载】

javascript语言精粹----笔记 1.6种值会为假(==false),分别是false,null,undefined,' ',0,NaN 2.typeof有6种值,分别是'number','string','boolean','undefined','function','object';其中typeof(null),结果是'object' 3.number类型总是64位浮点数,两个整数相除也可能出现非整数结果 4.如果第一个运算数的值为假,那么运算符&&产生它的第一个运算数的值.

《javascript语言精粹》——第3章

第三章:对象: 属性名字:可以是包括空字符串在内的任意字符串: 属性值:是除undefined值之外的任何值; [1].对象字面量: var obj={}; //空对象 var newobj={ name:"小明", age:17, school:{ class:"一班" } }; 属性名可加引号,也可不加 [2].检索 newobj["name"] //小明 newobj.age  //17  推荐使用.可读性更加好,紧凑 newobj[&qu

《javascript语言精粹》——第4章函数

函数就是对象 [1].函数字面量即(函数表达式)包括四部分: 第一部分:保留字function: 第二部分:函数名称,可有可无: 第三部分:包围在一对小括号的一组参数,参数用逗号隔开: 第四部分:包围在一对花括号的一组语句,是函数的主体: 函数字面量可以出现在任何允许表达式出现的地方. [2].调用有四种调用模式: 除了声明时定义的形参,每个函数接收附加的的参数:this和arguments  ,this的值取决于调用的模式. 第一种:方法调用模式: var aa={ value:0, incr

JavaScript语言精粹笔记

JavaScript语言精粹笔记 掌握语言的每个特性可以让你出风头,但是并不推荐,因为一部分的特性带来的麻烦可能远超本身的价值.正如书中所言,坏的材料并不能雕刻出好的作品,要成为一名更好的程序员,要取其精华去其糟粕.当你知道要做什么的时候,它还能表现的更好,编程时一件相对困难的事情,绝不应该在懵懂的状态下开始编程之旅. JS中的注意为//或者/*content*/,注释一定要精确地描述代码,不然没有用的注释比没有注释更糟糕. JS中的代码块不会创建新的作用域,因此变量应该被定义在函数的头部,而不

JavaScript语言精粹 笔记03

继承伪类对象说明符原型函数化部件 继承 JS不是基于类的,而是基于原型的,这意味着对象直接从其他对象继承. 1 伪类 JS提供了一套丰富的代码重用模式,它可以模拟那些基于类的模式,因为JS实际上没有类,所以把模拟的类称为伪类.我们可以定义一个构造器并扩充它的原型: var Mammal = function (name) { this.name = name; }; Mammal.prototype.get_name = function ( ) { return this.name; }; M

JavaScript语言精粹 笔记02

函数函数对象函数字面量调用参数返回异常给类型增加方法递归作用域闭包回调模块级联套用记忆   函数 1 函数对象 在JS中函数就是对象.对象是“名/值”对的集合并拥有一个连接到原型对象的隐藏连接.对象字面量产生的对象连接到Object.prototype.函数对象连接到Function.prototype(该原型本身连接到Object.prototype).每个函数在创建时附有两个附加的隐藏属性:函数上下文和实现函数行为的代码. 因为函数是对象,所以它可以像任何其他的值一样被使用.函数可以存放在变