Javacript 中有一系列作用域的概念。对于新的JS的开发人员无法理解这些概念,甚至一些经验丰富的开发者也未必能。这篇文章主要目的帮助理解JavaScript中的一些概念如:scope,closure, this, namespace, function scope, global scope, lexical scope and public/private scope. 希望从这篇文章中能回答如下的问题:
// Scope A
var myFunction = function () {
// Scope B
var name = 'Todd'; // defined in Scope B
var myOtherFunction = function () {
// Scope C: `name` is accessible here!};
};
var myFunction = function () {
var name = 'Todd';
var myOtherFunction = function () {
console.log('My name is ' + name);
};
console.log(name);
myOtherFunction(); // call function
};
// Will then log out:// `Todd`
// `My name is Todd`
词汇作用域用起来比较方便,任何父作用域中定义的变量、对象和函数在其域作用链中都可以使用。例如:
var name = 'Todd';
var scope1 = function () {
// name is available here
var scope2 = function () {// name is available here too
var scope3 = function () {// name is also available here!};
};
};
唯一需要注意的事情是词汇域不后项起作用,下面的方式词汇域是不起作用的:
// name = undefined
var scope1 = function () {
// name = undefined
var scope2 = function () {// name = undefined
var scope3 = function () {var name = 'Todd'; // locally scoped};
};
};
sayHello('Todd'); // nothing happens, no errors, just silence...
函数返回一个函数,也就意味着需要先赋值再调用:
var helloTodd = sayHello('Todd');
helloTodd(); // will call the closure and log 'Hello, Todd'
好吧,欺骗大家感情了。在实际情况中可能会遇到如下调用闭包的函数,这样也是行的通的。
sayHello2('Bob')(); // calls the returned function without assignment
Angular js 在$compile方法中使用上面的技术,可以将当前引用域传入到闭包中
$compile(template)(scope);
意味着我们能够猜出他们的代码(简化)应该如下:
var $compile = function (template) {
// some magic stuff here// scope is out of scope, though...
return function (scope) {// access to `template` and `scope` to do magic with too};
};
var myFunction = function () {
console.log(this); // this = global, [object Window]};
myFunction();
var myObject = {};
myObject.myMethod = function () {
console.log(this); // this = Object { myObject }};
var nav = document.querySelector('.nav'); //
var nav = document.querySelector('.nav'); //
var toggleNav = function () {
var that = this;
console.log(that); // element
setTimeout(function () {
console.log(that); // element}, 1000);
};
nav.addEventListener('click', toggleNav, false);
myFunction.call(scope); // invoke myFunction using .call() 10、.bind()
和上面不一样的是,.bind()并不触发函数,它仅仅是在函数触发前绑定值。非常遗憾的是其只在 ECMASCript 5中才引入。我们都知道,不能像下面一样传递参数给函数引用:
// works
nav.addEventListener('click', toggleNav, false);
// will invoke the function immediately
nav.addEventListener('click', toggleNav(arg1, arg2), false);
通过在内部创建一个新的函数,我们能够修复这个问题(译注:函数被立即执行):
nav.addEventListener('click', function () {
toggleNav(arg1, arg2);}, false);
var Module = (function () {
var privateMethod = function () {};
return {publicMethod: function () {
// has access to `privateMethod`, we can call it:
// privateMethod();}};})();
var Module = (function () {
var myModule = {};
var privateMethod = function () {};
myModule.publicMethod = function () {};
myModule.anotherPublicMethod = function () {};
return myModule; // returns the Object with public methods})();
// usage
Module.publicMethod();
通常私有方法的命名开头使用下划线,从视觉上将其与公有方法区别开。
var Module = (function () {
var _privateMethod = function () {};
var publicMethod = function () {};})();
当返回匿名对象的时候,通过简单的函数引用赋值,Module可以按照对象的方式来用。
var Module = (function ()
{var _privateMethod = function () {};
var publicMethod = function () {};
return {
publicMethod: publicMethod,anotherPublicMethod: anotherPublicMethod}
})();