你不知道的js总结(上)

欺骗词法中的with和eval(不推荐使用)

eval的使用是为了占位作用,将需要引用的代码先声明在需要的作用域中

function foo(str, a) {
	eval( str ); // 欺骗!
	console.log( a, b );
}
var b = 2;
foo( "var b = 3;", 1 ); // 1, 3

with 通常被当作重复引用同一个对象中的多个属性的快捷方式,可以不需要重复引用对象
本身。

var obj = {
	a: 1,
	b: 2,
	c: 3
};
// 单调乏味的重复 "obj"
	obj.a = 2;
	obj.b = 3;
	obj.c = 4;
// 简单的快捷方式
with (obj) {
	a = 3;
	b = 4;
	c = 5;
}

eval(…) 函数如果接受了含有一个或多个声明的代码,就会修改其所处的词法作用域,而
with 声明实际上是根据你传递给它的对象凭空创建了一个全新的词法作用域。(如果出现未声明的对象会出现自动声明的全局变量)
如果代码大量使用 with 或者 eval(),那么运行起来一定会变得非常慢。无论引擎多聪明,试图将这些悲观情况的副作用限制在最小范围内,也无法避免如果没有这些优化,代码会运行得更慢的事实。

匿名和具名

setTimeout( function() {
	console.log("I waited 1 second!");
}, 1000 );

这叫作匿名函数表达式,因为 function()… 没有名称标识符。函数表达式可以是匿名的,
而函数声明则不可以省略函数名——在 JavaScript 的语法中这是非法的,带来的弊端是

  1. 匿名函数在栈追踪中不会显示出有意义的函数名,使得调试很困难。
  2. 如果没有函数名,当函数需要引用自身时只能使用已经过期的 arguments.callee 引用,比如在递归中。另一个函数需要引用自身的例子,是在事件触发后事件监听器需要解绑自身。
  3. 匿名函数省略了对于代码可读性 / 可理解性很重要的函数名。一个描述性的名称可以让
    代码不言自明。
setTimeout( function timeoutHandler() { // <-- 快看,我有名字了!
console.log( "I waited 1 second!" );
}, 1000 );

行内函数表达式非常强大且有用——匿名和具名之间的区别并不会对这点有任何影响。给函
数表达式指定一个函数名可以有效解决以上问题。

立即执行函数表达式 (function foo(){ … })()

由于函数被包含在一对 ( ) 括号内部,因此成为了一个表达式,通过在末尾加上另外一个 ( ) 可以立即执行这个函数,
第一个 ( ) 将函数变成表达式,第二个 ( ) 执行了这个函数。

匿名表达式

	var a = 2;
	(function foo() {
	var a = 3;
	console.log( a ); // 3
	})();
	console.log( a ); // 2在这里插入代码片

具名表达式

	var a = 2;
	(function IIFE() {
	var a = 3;
	console.log( a ); // 3
	})();
	console.log( a ); // 2

传参式的表达式

	var a = 2;
	(function IIFE( global ) {
		var a = 3;
		console.log( a ); // 3
		console.log( global.a ); // 2
	})( window );
	console.log( a ); // 2

我们将 window 对象的引用传递进去,但将参数命名为 global,因此在代码风格上对全局
对象的引用变得比引用一个没有“全局”字样的变量更加清晰。当然可以从外部作用域传
递任何你需要的东西,并将变量命名为任何你觉得合适的名字。这对于改进代码风格是非
常有帮助的。

块作用域

  1. for循环
  2. with
  3. try/catch
  4. let

模块

模块有两个主要特征:(1)为创建内部作用域而调用了一个包装函数;(2)包装函数的返回值必须至少包括一个对内部函数的引用,这样就会创建涵盖整个包装函数内部作用域的闭包。

function CoolModule() {
	var something = "cool";
	var another = [1, 2, 3];
	function doSomething() {
		console.log( something );
	}
	function doAnother() {
		console.log( another.join( " ! " ) );
	}
	return {
		doSomething: doSomething,
		doAnother: doAnother
	};
}
var foo = CoolModule();
foo.doSomething(); // cool
foo.doAnother(); // 1 ! 2 ! 3

CoolModule() 只是一个函数,必须要通过调用它来创建一个模块实例。如果不执行
外部函数,内部作用域和闭包都无法被创建。

  • 现代的模块机制
var MyModules = (function Manager() {
	var modules = {};
	function define(name, deps, impl) {
		for (var i=0; i<deps.length; i++) {
		deps[i] = modules[deps[i]];
	}
	modules[name] = impl.apply( impl, deps );
	}
	function get(name) {
		return modules[name];
	}
	return {
		define: define,
		get: get
	};
})();

这段代码的核心是 modules[name] = impl.apply(impl, deps)。为了模块的定义引入了包装
函数(可以传入任何依赖),并且将返回值,也就是模块的 API,储存在一个根据名字来管
理的模块列表中。

  • 未来的模块机制
bar.js
	function hello(who) {
		return "Let me introduce: " + who;
	}
	export hello;
foo.js
	// 仅从 "bar" 模块导入 hello()
	import hello from "bar";
	var hungry = "hippo";
	function awesome() {
		console.log(
			hello( hungry ).toUpperCase()
		);
	}
	export awesome;
baz.js
	// 导入完整的 "foo" 和 "bar" 模块
	module foo from "foo";
	module bar from "bar";
	console.log(
	bar.hello( "rhino" )
	); // Let me introduce: rhino
	foo.awesome(); // LET ME INTRODUCE: HIPPO

需要用前面两个代码片段中的内容分别创建文件 foo.js 和 bar.js。然后如第三个代码片段中展示的那样,bar.js 中的程序会加载或导入这两个模块并使用它们。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值