函数与作用域
函数声明和函数表达式有什么区别?
函数声明:function functionName() {}
函数表达式:var fn = function() {}
- 函数声明会提前,函数表达式可以省略标识符(函数名)。
函数声明不必放到调用的前面,函数表达式声明必须放到调用的前面。
什么是变量的声明前置?什么是函数的声明前置
在一个作用域下,var 声明的变量和function 声明的函数会前置.前置到当前作用域的开头。
变量声明的前置:
console.log(i);
var i = 1; //undefined
代码执行过程:
var i;. //提前在程序最开始,声明一个变量i 未赋值 所以是 undefined
console.log(i);
i = 1; //console.log(i)在 i = 1 ;赋值语句之前,而变量声明前置所以打印的时候i是undefined;
函数的声明前置:
test(1)
function test(x){
console.log(x);
} // 1
通过函数声明的方式建立的函数表达式会提前,这段代码过程:
function test(x){};
test(1)
输出的结果为1;因为function test(x){} 整个函数 已经提前到了test(1)之前。
但是,同样的方法,使用函数表达式,其出现的结果是报错,因为其调用在其声明之前。
如下例子:
func1(); // 输出:我是函数声明
func2(); // 报错
console.log(a); // 输出:undefined
function func1() {
console.log("我是函数声明");
}
var func2 = function() {
console.log("我是函数表达式");
}
var a = 10;
arguments 是什么?
arguments是一个类数组对象。代表传给一个function的参数列表。
arguments对象是函数内部的本地变量;arguments 已经不再是函数的属性了。可以在函数内部通过使用 arguments 对象来获取函数的所有参数。这个对象为传递给函数的每个参数建立一个条目,条目的索引号从0开始。它包括了函所要调用的参数。object对象。类数组。
函数的"重载"怎样实现?
首先,要明确,在JS中,没有重载。同名函数会覆盖。但可以在函数体针对不同的参数调用执行相应的逻辑。
如下例:
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);//Byron 26
printPeopleInfo('Byron', 26, 'male');//Byron 26 male
javascript不能支持函数的重载,如下:
function f(length)
{
alert("高为:"+length);
}
function f(length,width)
{
alert("高为:"+length+",宽为:"+width);
}
上面那段代码其实是行不通的,因为函数定义时的参数个数和函数调用时的参数个数没有任何关系。在函数中可以用f.arguments[0]和f.arguments[1]得到调用时传入的第一和第二个参数,所以定义function(length),后面用f(10,10)调用是没有问题的。所以在上面这段代码中,第二个函数是永远不可能被调用到的,那么,要怎样才能实现像函数重载那样的功能呢?
那就是在函数定义中用f.arguments.length判断一下调用时传入的参数个数。然后对不同的情况采用不同的处理方式。 如下:
function f()
{
var len= arguments.length;
if(2 == len)
{
var length = arguments[0];
var width = arguments[1];
f2(length,width);
}
else
{
var length = arguments[0];
f1(length);
}
}
function f1(length)
{
alert("高为:"+length);
}
function f2(length,width)
{
alert("高为:"+length+",宽为:"+width);
}
*这样,你就可以给函数f()传入一个参数也可以传入两个参数了,比如f(10)和f(10,10); *
- 这样虽然可以实现重载,但也不是很好用,我们可以根据具体情况在一个函数中实现重载,如果要重载的两个函数相差较大,那就保留两个函数,而如果两个函数的实现基本差不多,那么可以在一个函数中进行判断,处理不同的部分,而不需要像上面那样写成三个函数,如下:
function f(length)
{
var len= arguments.length;
if(1 == len)
{
var width = arguments[1];
alert("高为:"+length+",宽为:"+width);
}
else
{
alert("高为:"+length);
}
}
立即执行函数表达式是什么?有什么作用
(function(){
var a = 1;
})()
作用: 隔离作用域。
JavaScript有很多致命缺陷,比如JavaScript中没有命名空间,而且只有function代码块内部可以隔离变量作用域,自调用匿名函数就用来防止变量弥散到全局,以免各种js库冲突。
求n!,用递归来实现
function fn(n) {
if(n < 0){
alert("error")
}
else if(n == 0 || n == 1) {
return 1;
}
return n * fn(n-1);
}
fn(5);
以下代码输出什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('饥人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
输出结果如下:
name: 饥人谷
age: 2
sex: 男
['饥人谷',2,'男']
name valley
name:小谷
age:2
sex: undefined
['小谷','3']
name valley
name:男
age:undefined
sex:undefined
['男']
name valley
写一个函数,返回参数的平方和?
function sumOfSquares(){
var sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i]*arguments[i]
}
return sum;
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
如下代码的输出?为什么
console.log(a);
var a = 1;
console.log(b);
// undefined
// ReferenceError: b is not defined
console.log(a)输出的是undefined、因为变量在当前作用域下被前置,结果在console.log(a)前面的var a;虽然声明了但是没有赋值,结果为undefined.
console.log(b) b完全是没有声明也没有赋值,结果是报错.//ReferenceError: b is not defined
*/
如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
// hello world
// TypeError: sayAge is not a function
sayNme('world');会返回'hello world'.
sayAge(10);因为是使用表达式定义,所以,当调用在定义之前就会报错,sayAge is not a function.
如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
/* 10
1.
globalContext = {
AO: {
x: 10, foo: function, bar: function
},
foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
}
2.调用bar()
barContext = {
AO: {
x: 30
}
Scope: bar.[[scope]] = globalContext.AO
}
3.调用foo()
fooContext = {
AO: {}
Scope: foo.[[scope]] = globalContext.AO
} */
如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
输出: 30
1.
globalContext={
AO:{
x:10,
bar : function
},
Scope:null
}
bar.[[scope]]=globalContext.AO
2. 调用bar
barContext={
AO:{
x: 30,
foo:function
},
Scope: bar.[[scope]]=globalContext.AO
}
foo.[[scope]]=barContext.AO
3. 调用foo
fooContext={
AO:{},
Scope: foo.[[scope]]=barContext.AO
}
以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
输出: 30
1.
globalContext={
AO:{
x: 10,
bar:function
}
Scope: null
}
bar.[[scope]]=globalContext.AO
2.调用bar
barContext={
AO:{
x:30,
function(){}
}
Scope:bar.[[scope]]=globalContext.AO
}
function().[[scope]]=barContext.AO
3. 调用function()
functionContext={
AO:{}
Scope:function().[[scope]]=barContext.AO
}
以下代码输出什么? 写出作用域链查找过程伪代码
var a = 1;
function fn(){
console.log(a)
var a = 5
console.log(a)
a++
var a
fn3()
fn2()
console.log(a)
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn()
console.log(a)
输出: undefined 5 1 6 20 200
1.
globalContext={
AO:{
a:200,
fn:function,
fn3:function
}
Scope: null
}
fn.[[scope]]=globalContext.AO
fn3.[[scope]]=globalContext.AO
2. 调用fn
fnContext={
AO:{
a:20,
fn2:function
}
Scope: fn.[[scope]]=globalContext.AO
}
fn2.[[scope]]=fnContext.AO
3. 调用fn3
fn3Context={
AO:{}
Scope:fn3.[[scope]]=globalContext.AO
}
4. 调用fn2
fn2Context={
AO:{}
Scope:fn2.[[scope]]=fnContext.AO
}