IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

从另外两道题说起

Miller 2010-08-17 23:05:33 累计浏览 2,876 次
本机暂存

最近貌似流行做Javascript题,Dmitry A. Soshnikov这又出了几道题-The quiz,还可以自我评分,有兴趣的可以去试试看自己可以得几分。本文主要挑了2道比较绕的题目来说几个知识点:

1. Javascript中的”,”(逗号)操作符

2. Javascript中”;”(分号)的重要性

3. Javascript中with块中的作用域

下面请看题目。

题目1

以下是代码片段:
var
  b = 10,
  c = (
    20,
    function (x) { return x + 100},
    function () { return arguments[0]}
  );

a = b + c
({x: 10}).x;

要说这道题先来说说Javascript中的逗号,Javascript中的逗号大概在以下几处会用到:

以下是代码片段:
//1. 变量申明
var v1, v2;

//2. 数组定义
var arr = [1,2,3];

//3. 函数参数
function func(arg1,arg2){};
func(1,2);

//4. 操作符(for语句中的循环执行表达式)
for( var i = 0, j = 0; i < len; i++,j++){}

其中用法1-3是比较常见的,而用法4中很多人并没有注意,for语句最后的”i++,j++”正式一个包含逗号操作符的表达式,在MDC中对逗号操作符做了如下描述:

You can use the comma operator when you want to include multiple expressions in a location that requires a single expression.

实际上,逗号操作符会从左往右依次计算每个表达式的值并返回最后一个表达式的计算结果。会到题中,变量c的赋值正是一个逗号操作符运算,因此c的值为function(){return arguments[0]}。

之后看a的赋值”b+c”,表面看貌似一个整数加一个函数,实际上因为c之后没有分号,因此c会与第二行的”({x:10})”结合,相当于”c({x:10})”,因此最后a的值为”10+10″。关于分号问题,下面有一段更常见的代码:

以下是代码片段:
var a = function(){ return arguments[0];}
(function(x){
    return x;
})(100);

最后a的值为100,因此在给变量申明时务必记得加分号。

题目2

以下是代码片段:
({
  x: 10,
  foo: function () {
    function bar() {
      console.log(x);
      console.log(y);
      console.log(this.x);
    }
    with (this) {
      var x = 20;
      var y = 30;
      bar.call(this);
    }
  }
}).foo();

这里主要是要搞清楚with块的作用,with(obj)使用时只是将obj放置在作用域链的最前端,而并不会像函数那样形成一个完整的活动对象(包括局部变量、arguments、函数等),因此在with块中使用var声明变量时,而实际上还是在with块之外创建了局部变量,并不是with块的局部变量。同样,在with块中定义的函数实际上也是属于with块外层。另外,在with块中给变量赋值时则会先从obj对象中查找变量,如果找不到则依次按照作用域链查找。 因此,以上的with块的代码可以这样分解:

以下是代码片段:
({
  x: 10,
  foo: function () {
    function bar() {
      console.log(x);
      console.log(y);
      console.log(this.x);
    }

    var x,y;
    with (this) {
      x = 20;
      y = 30;
      bar.call(this);
    }
  }
}).foo();

在代码解析的时候,会在foo函数中创建两个局部变量x,y(初始值都为undefined)。而在运行时的with块中,给x赋值时因为首先找到的变量是this(也就是最外层的那个对象)中的x属性,因此this.x=20;这也造成了作用域链中位于this上一级的foo的上下文(context)中的局部变量x没有被赋值。同理,with块中给y赋值时,按作用域链查找到得是foo中的局部变量,因此局部变量y=30。最后bar在执行的时候,x/y均是访问foo中的局部变量,因此一个为undefined,一个为30,而this.x为20。

呃…要说清楚还真绕……!

同分类推荐文章

  1. translateZ() (2026-06-25 21:18:56)
  2. translateY() (2026-06-25 21:17:56)
  3. translateX() (2026-06-25 21:16:01)

查看更多 前端 文章 →

建议继续学习

  1. JQuery实现Excel表格呈现 (累计阅读 48,350)
  2. 深入理解Javascript之执行上下文(Execution Context) (累计阅读 18,404)
  3. 从输入 URL 到页面加载完成的过程中都发生了什么事情? (累计阅读 15,933)
  4. 图片动态局部毛玻璃模糊效果的实现 (累计阅读 14,849)
  5. 天朝第二代身份证号码的验证机制 (累计阅读 14,762)
  6. HTML 5 的data-* 自定义属性 (累计阅读 14,349)
  7. 分享一个JQUERY颜色选择插件 (累计阅读 14,223)
  8. 什么是全栈工程师? (累计阅读 14,038)
  9. 快速排序(Quicksort)的Javascript实现 (累计阅读 11,735)
  10. 7 天打造前端性能监控系统 (累计阅读 11,187)