内容预览
1. js 中的作用域
2.闭包的理解和运用
3.this 的理解和运用
【一】 js中的作用域
一段简单的代码来说明
var outFunc = function() {
var out_name = "outFunc";
var out_num = 130;
var inFunc = function() {
var in_name = "inFunc";
var in_num = 3;
alert(out_name);
alert(out_num);
alert(in_name);
alert(in_num);
};
inFunc();
// 调用 inFunc 函数执行的结果是,弹出:outFunc、130、inFunc、3
alert(out_name);
alert(out_num);
alert(in_name);
alert(in_num);
};
outFunc();
// 调用 inFunc 函数执行的结果是,弹出:outFunc、130、undefined、undefined
内部函数可以访问外部函数的变量,外部不能访问内部函数的变量。上面的例子中内部函数inFunc可以访问变量 out_name和out_num,而外部函数 outFunc 不可以访问 inFunc 中的变量 in_name和in_num,因此会抛出没有定义变量的异常。
很重要的一点,如果忘记 var,那么变量或者函数就会被声明为全局变量或者全局函数了。下面例子的写法,in_name 变量和 test 函数 是全局的变量和全局函数,不属内部作用域了。
var outFunc = function() {
var out_name = "outFunc";
var out_num = 130;
var inFunc = function() {
in_name = "inFunc";
var in_num = 3;
};
test function(){
alert('Test');
}
};
【二】 闭包的理解和运用
闭包这个概念,在函数式编程里很常见,简单的说常见的两大用处,一是使外部函数可以突破作用域从而访问定义在内部函数中的变量,二是让变量的值始终保存在内存中。当在一个函数中定义另个函数就会产生闭包。如果要深入理解闭包,可以查看这篇博客http://coolshell.cn/articles/6731.html
//javascript 中特殊形式的函数,自调用函数
var a = function() {
function setUp() {
//定义方法时可以做首次的初始化,这个只会调用一次
alert('初始化');
}
setUp();
function doSomething() {
alert('要执行的操作')
}
return doSomething; //这里返回的不是一个函数,而是一个引用
}(); //加()进行首次调用初始化,既首次执行setUp函数(自调用函数)
// a(); //弹出 初始化
// a(); //弹出 要执行的操作
//闭包的应用一: 通过闭包突破全局作用域链
var n;
function f() {
var a = 'king'; //这是局部变量
n = function() { //外部可通过 n 函数访问局部变量a
return a;
};
//这个test函数 不加var 默认为全局的函数,加var 则为局部的
test = function() {
alert('默认全局函数');
}
}
//闭包的应用二: 定义私有变量的取值和赋值
var setValue, getValue;
(function() {
var n = 0; //私有变量
getValue = function() {
return n;
}
setValue = function(x) {
n = x;
}
})(); //这样写为自调用函数
//闭包的应用三:迭代器
function test(x) {
var i = 0;
return function() {
return x[i++];
}
}
var next = test(['a', 'b', 'c', 'd']);
// alert(next());//弹出a
// alert(next());//弹出b
// alert(next());//弹出c
// alert(next());//弹出d
//理解不到位常犯的错误,这种错误通常不容易被发现
function f() {
var a = [];
var i;
for (var i = 0; i < 3; i++) {
a[i] = function() {
return i; //这里只是对 i 这个指针进行了引用
};
}
return a;
}
var test = f();
// alert(test[0]());//弹出 3
// alert(test[1]());//弹出 3
// alert(test[2]());//弹出 3
//出现这个问题原因在于 i 是一个指针,也就是一个地址,闭包只是引用了这个指针。当for 循环遍历结束 指针 i 指向的值为 3
// 可采用自调用函数的方式来避免上述的问题,如下所示
function f() {
var a = [];
var i;
for (var i = 0; i < 3; i++) {
a[i] = (function(x) {
return function() {
return x;
}
})(i);
}
return a;
}
var test = f();
alert(test[0]()); //弹出 0
alert(test[1]()); //弹出 1
alert(test[2]()); //弹出 2
【三】this 的理解和运用
在函数执行时,this 总是指向调用该函数的对象。要判断 this 的指向,其实就是判断 this 所在的函数属于谁。
在《javaScript语言精粹》这本书中,把 this 出现的场景分为四类,简单的说就是:
1) 有对象就指向调用对象
var myObject = {value:111};
myObject.getValue = function(){
console.log(this.value);//输出100
console.log(this);//输出 { value: 100, getValue: [Function] }
}
myObject.getValue();
// getValue() 属于对象 myObject,并由 myOjbect 进行 . 调用,因此 this 指向对象 myObject。
2) 没调用对象就指向全局对象
var myObject = { value: 100 };
myObject.getValue = function() {
var foo = function() {
console.log(this.value) // 输出 undefined
console.log(this); // 输出全局对象 global
//foo 函数虽然定义在 getValue 的函数体内,但实际上它既不属于 getValue 也不属于 myObject。
// foo 并没有被绑定在任何对象上,所以当调用时,它的 this 指针指向了全局对象 global。
};
foo();
return this.value; //这个this 在 getValue中,从而指向 myObject。
};
console.log(myObject.getValue()); // 输出 100
3) 用new构造就指向新对象
//js 中,我们通过 new 关键词来调用构造函数,此时 this 会绑定在该新对象上。
var SomeClass = function() {
this.value = 100;
}
var myCreate = new SomeClass();
console.log(myCreate.value); // 输出100
4) 通过 apply 或 call 或 bind 来改变 this 的所指
// apply 和 call 调用以及 bind 绑定: 指向绑定的对象
// apply() 方法接受两个参数第一个是函数运行的作用域, 另外一个是一个参数数组(arguments)。
// call() 方法第一个参数的意义与 apply() 方法相同, 只是其他的参数需要一个个列举出来。
// 简单来说, call 的方式更接近我们平时调用函数, 而 apply 需要我们传递 Array 形式的数组给它。 它们是可以互相转换的。
var myObject = { value: 100 };
var foo = function() {
console.log(this);
};
foo(); // 全局变量 global
foo.apply(myObject); // { value: 100 }
foo.call(myObject); // { value: 100 }
var newFoo = foo.bind(myObject);
newFoo(); // { value: 100 }</span>