ECMAScript 262 5th :执行环境一些概念解释

可执行代码

ECMAScript 5th规定了3种可执行代码:Global code、Eval code和Function code。

根据名字就已经知道,Global codeEval code分别对应全局代码和eval函数中执行的代码。

三种可执行代码中最为复杂的就是Function code,即函数代码。因为javascript的特性,所以Function code中还可以嵌入Function code,导致了Function的执行环境会较为复杂。

执行环境(执行上下文)

当javascript引擎开始执行(进入)一段可执行代码时,就会生成一个执行环境Execution Context,或称执行上下文)。

javascript引擎通过一个栈(Stack)来维护执行环境,当进入一个执行环境,则将当前运行的执行环境压入到这个栈的顶部,代码表示:

var ECStack = [];//维护执行环境的栈
function enterExecutabCode(){
    var ec = new ExecutionContext();
    ECStack.push(ec);
}

一个执行环境是由:LexicalEnvironmentVariableEvironmentThisBinding组成的。

function ExecutionContext(){
    return {
        LexicalEnvironment,
        VariableEnvironment,
        ThisBinding
    }
}

词法环境(Lexical Environments)注意是复数哦~

一个词法环境对象包括:环境数据(Environment Record)和外部环境(outer Lexical Environment)。

外部环境(outer Lexical Environment)

表示外层函数的词法环境,有两种:nullglobal环境),或者外层函数的词法环境(嵌套函数)

环境数据(记录)(Environment Record)

有两种环境数据:declarative environment recordsobject environment records,因为存在两种类型的环境数据,所以词法环境的实现类型包括了两种:DecarativeEnvironmentObjectEnvironment

Declarative environment records

常见标识符绑定基本都是这个类型,例如函数定义,var声明,trycatch子句

Object environment records

包括两种一种是程序级别的(Program),另外一种是with语句,因为这两种绑定标识符过程需要传入一个对象做为环境数据的属性值。

继续说环境数据,环境数据存在于词法环境或者变量环境中,它包含了一个绑定对象(bindingObject),这个对象是一种键值对象,即有name和value一一对应关系,其中name就是标识符,value则为对应的变量值。

既然环境数据是保存数据的地方,必然有一些方法用于存储数据和读取数据。所以环境数据常见的方法有:

js模块并行加载器:MixJS

自己写了一个js模块加载器,所谓的并行其实也不完全是并行的,只是依赖关系模块是并行的。当然我知道现在有很多类似的js框架,而且MixJS也没有做更加全面的浏览器测试,只是跟我的意识写的一个加载器。

项目放在github上面:https://github.com/ksky521/MixJS
算是给2012年的一个总结。

简单说下功能

跟玉伯的Seajs不同,也跟CMD和AMD不同,我使用的是依赖关系明确的声明模块方式,这样减少了扫描代码读取依赖关系的方式,开发者虽然有了一定的束缚,但是总体来说,后期的维护成本,代码效率和实时combo、上线打包都会大大的降低成本。

MixJS介绍

轻量级前端模块化解决方案,提供模块管理、php实时合并、打包工具等方案。可以用于提供给第三方开发者使用的小组件,核心文件可以单独拿出来作为框架core,在此基础上可以开发出一整套的前端框架

MixJS还在开发完善阶段,未作完整兼容性测试,多数代码是出于解决问题的想法而写的,当然也copy了很多牛人的代码,比如cssload回调借鉴了seajs,Deferred来自于jQuery。。。。

。。。。鉴于最近前端圈比较乱,我的小手都开始颤抖,造轮子必然会被喷,我只能说我是根据自己的意识码了这些的代码,据此操作后果自负。。。。

0.2开发完成,现在开发基于0.2模块的开放平台部分代码,主要包括:Deferred(延迟队列)、API(API接口调用)、Widget(小组件)和XDomain(跨域)

模块加载不是单纯的文件加载,需要根据模块规范来写模块哦~

MixJS代码示例

参考github项目readme文件。

用途

关于MixJS的用途,主要解决是模块开发中的管理、加载。

我赞成使用MixJS是:细模块,粗文件。总体来看MixJS适合Widget开发、开放平台开放js开发,也适合作为模块管理器来打造更加强大的前端架构。

不多说了,吹嘘会被喷的,哈哈~

感谢

MixJS也借鉴了不少大牛的代码(嗯,你可以说是抄袭),感谢seajs,jQuery,mass,curl.js等作者。

再探javascript作用域

对于javascript作用域的理解,之前整理过两篇文章:《javascript作用域和作用域链》《javascript的词法作用域》。最近读了周爱民老师的《javascript语言精髓》,对javascript作用域有了新的认识,特地整理下思路。

javascript的作用域广义来分:语法作用域变量作用域

javascript语法作用域

javascript语法作用域是讨论代码的组织结构上抽象,可以理解为讨论的是“圈地”问题,也有书籍中对纯粹的语法作用域称为“静态作用域”。

语法作用域分四级,下标依次增高

级别 作用域
级别一 表达式
级别二 语句/批语句
级别三 函数
级别四 全局(宿主)
  1. 同级别可以平行也可以相互嵌套(包含)
  2. 高级别可以嵌套(包含)低级别
  3. 低级别不可以嵌套(包含)高级别作用域;假如低级别嵌套高u别,可以理解成相互平行,例如下面的代码是完全等效的
if(true){
    //
    function fn(){
        //
    }
}

if(true){
    //
}
function fn(){
    //
}

开源个html5播放器

前言:人家都说没有几个项目在github,都不好意思说自己混前端的……

好吧,看见越来越多的人都推自己的github主页,我也把自己的之前写的一些东西整理下,从sae的svn迁移到github上,开了几个项目,虽然说代码的确乱糟糟的,但是也凑凑数吧,今天开源的是html5音乐播放器

html5音乐播放器

截图如下:

之前放出的是jquery版本的,见文章《写了一个html5音乐播放器》也整理到了这个项目中,文件夹是withjQuery内。

使用广播事件来实现模块解耦

模块化开发往往最大的问题是解耦,怎么设计一个低耦合的组件呢?这里我用到的方法是时间总线(eventBus)方法,也可以叫做广播事件,模块之间通过发送广播的方式来实现通信,事件发起者只需要派发事件,而不必关心事件是否被接收(订阅)。

广播事件也是自定义事件的一种,不同于自定义事件,广播事件没有绑定的主体,但是都是通过观察者设计模式来写的代码。
大体的javascript实现代码如下:其中包括一些简单方法没有列出,例如$.isUndefined

var _cache = {};
var broadcast = {
    /**
     * 派发
     * @param  {[type]} type 事件类型
     * @param  {[type]} data 回调数据
     * @return {[type]}      [description]
     */
    fire:function(type, data){
        var listeners = _cache[type],len = 0;
        if(!$.isUndefined(listeners)){
            var args = [].slice.call(arguments);
            args = args.length > 2 ? args.splice(2, args.length-1) : [];
            args = [data].concat(args);

            len = listeners.length;
            for(var i = 0; i<len;i++){
                var listener = listeners[i];
                if(listener && listener.callback) {
                    args = args.concat(listener.args);
                    listener.callback.apply(listener.scope, args);
                }
            }
        }
        return this;
    },
    /**
     * 订阅广播事件
     * @param  {[type]}   types     事件类型,支持,分隔符
     * @param  {Function} callback 回调函数
     * @param  {[type]}   scope    回调函数上下文
     * @return {[type]}            this
     */
    subscribe:function(types, callback, scope){
        types = types || [];
        var args = [].slice.call(arguments);

        if($.isString(types)){
            types = types.split(',');
        }
        var len = types.length;
        if(len===0){
            return this;
        }
        args = args.length > 3 ? args.splice(3, args.length-1) : [];
        for(var i = 0;i<len;i++){
            var type = types[i];
            _cache[type] = _cache[type] || [];
            _cache[type].push({callback:callback,scope:scope,args:args});
        }
        return this;
    },
    /**
     * 退订
     * @param  {[type]}   type     [description]
     * @param  {Function} callback 假如传入则移出传入的监控事件,否则移出全部
     * @return {[type]}            [description]
     */
    unsubscribe:function(type, callback, scope){
        var listeners = _cache[type];
        if (!listeners) {
            return this;
        }
        if(callback){
            var len = listeners.length,
                tmp = [];

            for(var i=0; i<len; i++) {
                var listener = listeners[i];
                if(listener.callback == callback && listener.scope == scope) {
                } else {
                    tmp.push(listener);
                }
            }
            listeners = tmp;
        }else{
            listeners.length = 0;
        }
        return this;
    },
    /**
     * 订阅别名
     * @return {[type]} [description]
     */
    on:function(){
        return this.subscribe.apply(this,arguments);
    },
    /**
     * 退订别名
     * @return {[type]} [description]
     */
    un:function(){
        return this.unsubscribe.apply(this,arguments);
    },
    dispatch:function(){
        return this.fire.apply(this,arguments);
    },

    removeAll:function(){
        _cache = {};
        return this;
    }
};

使用方法:

broadcast.fire('event name', json);
broadcast.on('event name', function(data){
    console.log(data);
});

VPS 上配置 iptables 防火墙

今天vps告急,ssh都登录不上去,上去很艰难的查了日志,发现几个ip访问异常,应该是某插件的爬虫,之前把图简单iptables禁用了,只能再次开启,主要命令如下:

# 查看状态
$ service iptables status

# 查看规则
$ iptables -L -n

# 清除默认规则
$ iptables -F
$ iptables -X
$ iptables -Z

#####建立新的规则######
# 允许本地回环 127.0.0.1
$ iptables -A INPUT -i lo -p all -j ACCEPT

# 允许已经建立的所有连接
$ iptables -A INPUT -p all -m state --state ESTABLISHED,RELATED -j ACCEPT

# 允许所有向外发起的连接
$ iptables -A OUTPUT -j ACCEPT

# 拒绝 ping
$ iptables -A INPUT -p icmp -m icmp --icmp-type 8 -j REJECT

# 允许 SSH 服务端口(一定要打开,不然就不能ssh了)
$ iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# 允许 Web 服务端口
$ iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# 拒绝其他所有未被允许的连接
$ iptables -A INPUT -j REJECT
$ iptables -A FORWARD -j REJECT

# 禁用ip
$ iptables -I INPUT -s 124.115.0.199 -j DROP
# 封IP段的命令是
$ iptables -I INPUT -s 124.115.0.0/16 -j DROP
# 封整个段的命令是
$ iptables -I INPUT -s 194.42.0.0/8 -j DROP
# 封几个段的命令是
$ iptables -I INPUT -s 61.37.80.0/24 -j DROP
$ iptables -I INPUT -s 61.37.81.0/24 -j DROP

dport表示目的,sport表示来源,output表示本机出,input表示访问本机

nginx1.2.4: [warn] "log_format" directive used only on "http" level 解决方法

将nginx升级到1.2.4稳定版之后,会发现之前的vhost/*.conf中的日志配置都报了如下的warn:

nginx: [warn] the “log_format” directive may be used only on “http” level

上网搜索解决方案如下:

将/vhost/xxx.conf里server段里的下面代码移出该server段即可。

但是这样的又会产生一个问题,就是各子域名的日志文件都会记录所有请求的日志,等了好久都没找到解决方案,后来请教了飞飞之后终于找到解决的方法了。

原来log_format需要在nginx.conf的http层定义,然后在分域名下面就不用定义log_format,直接引用即可,即:
在nginx.conf中http层添加:

log_format Main ‘$remote_addr – $remote_user [$time_local] “$request” ‘
‘$status $body_bytes_sent “$http_referer” ‘
‘”$http_user_agent” $http_x_forwarded_for $request_time’;

然后在vhost/*.conf中server中直接写:

access_log ./logs/blog.log Main;

但是注意include vhost/*.conf要放在log_format之后哦,不然会找不到Main

mysql导入导出数据乱码问题解决方法

最近在linux上面用mysqldump导出数据,放在windows系统中导入就会出现中文乱码,然后就会导致出现: Unknown MySQL server hostCan't connect to the server的错误。

解决mysql导入导出数据乱码问题就是统一导入导出的编码,linux默认的是utf8编码,而windows是gbk编码,所以会出现上面的乱码问题。

解决mysql导入导出数据乱码问题

首先要做的是要确定你导出数据的编码格式,使用mysqldump的时候需要加上--default-character-set=utf8,例如下面的代码:

将nodejs打包工具整合到鼠标右键

昨天放出了主要的nodejs打包代码(《nodejs写的简单项目打包工具》),今天放出整合到鼠标右键的代码,打包需要配置环境变量,添加NODE_PATH为node安装路径,打包用到的批处理文件代码如下:

@echo off
title Builder - 正在合并 ...

color 03
REM =====================================
REM     jsbuilder beta版
REM
REM =====================================
SETLOCAL ENABLEEXTENSIONS

echo.

REM 过滤文件后缀,只combo js文件
if "%~x1" NEQ ".js" (
    echo.
    echo **** 请选择JS文件
    echo.
    goto End
)

REM 检查NODE_PATH
if "%NODE_PATH%" == "" goto NoNodePath
if not exist "%NODE_PATH%\node.exe" goto NoNodePath

set RESULT_FILE=%~n1-combo%~x1

:ZIP_CHOICE

echo 选择是否【压缩】合并后的js文件?
set input=
set /p input= -^> 请选择(y/n):
if /i "%input%"=="n" goto UNZIP
if /i "%input%"=="y" goto ZIP

REM 调用build合并文件
:UNZIP
"%NODE_PATH%\node.exe" "%~dp0build.js" --unzip "%~n1%~x1" > "%RESULT_FILE%"
echo.
echo **** ~O(∩_∩)O~ 【合并】成功 ****
echo.
goto End

REM 调用build合并并且压缩文件
:ZIP
"%NODE_PATH%\node.exe" "%~dp0build.js" "%~n1%~x1" > "%RESULT_FILE%"
echo.
echo **** ~O(∩_∩)O~ 【合并并压缩】成功 ****
echo.
goto End

:NoNodePath
echo.
echo **** 请先安装NodeJS并设置NODE_PATH环境变量 ****
echo.

:End
ENDLOCAL
pause

nodejs写的一个简单项目打包工具

项目是模块加载的,类似require.js的用法,所以简单写了一个js打包工具。
项目的模块加载和定义部分代码是这样的:

XX.define('ns',['tool/cookie'],function(){
});
//或者
XX.define('ns.ns2','tool/cookie,tool/abc',function(){
})
//或者
XX.define('ns',function(){
})

所用到的js打包工具就是扫描文件,然后匹配出来需要加载的模块,然后先加载模块代码。
主要的nodejs打包工具代码如下: