IIFE
http://benalman.com/news/2010/11/immediately-invoked-function-expression/#iife
知识点:
1.函数的声明方式
2.参数 返回值
3.声明前置
4.作用域
5.立即执行函数表达式
6.递归
函数
JavaScript函数指一个特定代码块,可能包含多条语句,
可以通过名字来供其他语句调用以执行函数包含的代码
语句。
function doSomething() {
statment1;
statment2;
statment3;
}
doSomething();
//三种声明函数的方式
1.构造函数
首先函数也是对象的一种,我们可以通过其构造函数
使用new来创建一个函数对象
//不推荐使用
var sayHello = new Function("console.log('hello world');")
2.函数声明
//使用function关键字可以声明一个函数
//函数声明
function sayHello(){
console.log('hello')
}
//函数调用
sayHello()
声明不必放在调用前面
3.函数表达式
var sayHello = function(){
console.log('hello');
}
sayHello()
声明必须放到调用的前面
本质上是一个表达式
参数
function sayHello(name){
console.log('hello' + name)
}
sayHello('fem')
sayHello('lem')
//声明的时候不执行
//调用的时候才执行
多个参数
function printInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
}
printInfo('fem', 25, 'man')
//只是按次序传递
arguments
//在函数内部,你可以使用arguments对象获取到
//该函数的所有传入参数
function printInfo(name, age, sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
console.log(arguments[0])
}
printInfo(2, 'boy')
//arguments 类数组对象
重载
在JS中 没有重载! 同名函数会覆盖
但可以在函数体针对不同的参数调用执行相应的逻辑
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
返回值
//有时候我们希望在函数执行后得到一个结果
//供别人使用,可以通过return实现
function sum(a, b){
a++;
b++;
return a + b;
}
var result = fn(2, 3);
console.log(result);
//注意点!
//1.如果不写return语句,函数也会默认给我们返回undefined
//2.函数在执行过程中,只要遇到return就会立即结束退出函数体
function fn(a){
if(a < 0){
return;
}
//下面没用else,但效果一样
a++;
return a + a;
}
//3.函数的返回值和console.log() 是两个不同的东西
千万不要
function getAge(age){
return console.log(age);
}
应该
function getAge(age){
console.log(age);
return age;
}
声明前置
var和function的声明前置
在一个作用域下 var声明的变量和function声明的函数会前置
console.log(a); //undefined
var a = 3;
console.log(a); //3
sayHello();
function sayHello(){
console.log('hello')
}
实际上是
var a
function sayHello(){
}
a = 3
sayHello()
console.log(fn); //undefined
fn(); //报错
var fn = function() { }
函数表达式和var一个变量没有区别
先有 再用
函数内部的声明前置
function fn(){
console.log(a) //undefined
var a = 3
console.log(a)
}
当命名冲突时
先前置 再覆盖
var fn = 3;
function fn() {}
console.log(fn); //3
function fn(){}
var fn = 3;
console.log(fn); //3
参数重名
function fn(fn){
console.log(fn)
var fn = 3;
console.log(fn);
}
//相当于
//function fn(10){
// var fn = 10
// var fn
// console.log(fn)
// fn = 3
// console.log(fn)
//}
fn(10) //10 3
ES5以前
作用域
在JS中只有函数作用域,没有块作用域
函数才有作用域
function fn(){
var a = 1;
if( a > 2){
var b = 3; //也会声明前置
// b = 3没有执行
}
console.log(b);
}
fn(); //undefined
console.log(a) //"ReferenceError: a is not defined"
//全局作用域下没有a
声明一个已经存在的变量
function fn(){}
var fn
console.log(fn)
var a = 1
var a
var a
console.log(a)
var 重复声明一个已经存在的变量,原变量值不变
不加var作用
function fn(){
a = 1;
}
fn();
console.log(a); //1
可以看到不写var会声明一个全局的变量,
这是我们在编程中应该要避免的,即使真
的需要全局变量,也应该在最外层作用域使用var声明
递归
1.自己调用自己
2.设定终止条件
3.优点 算法简单
4.缺点 效率低
求n的阶乘n!
function factor(n){
if( n === 1) {
return 1
}
return n * factor(n-1)
}
factor(5)
求1+2+...+n的值
function sum(n){
if( n === 1) {
return 1
}
return n + sum( n - 1)
}
sum(10)
立即执行函数表达式
(function say(){
var a = 1;
})()
(function(){
var a = 1;
})()
(function(){
var a = 1;
})()
console.log(a); //undefined
//作用: 隔离作用域
其他写法
(function fn1() {});
//在数组初始化器内只能是表达式
[function fn2() {}];
//逗号也能操作表达式
1, function fn3() {};
!function(){
var a = 1;
}
只有函数才有作用域
console.log(j); //undefined
console.log(i); //undefined
//var i 也是全局变量
for(var i = 0; i<10; i++){
var j = 100;
}
console.log(i); //10
console.log(j); //100
fn();
var i = 10;
var fn = 20;
console.log(i);
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2() {
i = 100;
}
}
作用域链
1.执行上下文 executionContext
2.活动对象
3.Scope属性
var x = 10
bar()
function foo() {
console.log(x)
}
function bar() {
var x = 30
foo() //输出什么
}
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//声明 foo时 得到下面
foo.[[scope]] = globalContext.AO
//声明bar时 得到下面
bar.[[scope]] = globalContext.AO
//注意 在当前的执行上下文内声明的函数,这个函数的[[scope]]就执行当前执行上下文的AO
当调用bar() 时 进入bar的执行上下文
barContext = {
AO: {
x: 30
},
Scope: bar.[[scope]] //globalContext.AO
}
当调用foo() 时,先从bar执行上下文中的AO里面找,
找不到再从bar的[[scope]]里面找 找到后即调用
当调用foo() 时,进入foo的执行上下文
fooContext = {
AO: {},
Scope: foo.[[scope]] //globalContext.AO
}
所以console.log(x)是10
var x = 10;
bar() //输出什么
function bar(){
var x = 30;
function foo() {
console.log(x)
}
foo();
}
1.
globalContext = {
AO: {
x: 10
bar: function(){}
}
}
bar.[[scope]] = globalContext.AO
barContext = {
AO:{
x: 30
foo: function(){}
},
Scope: bar.[[scope]] = globalContext.AO
}
foo.[[scope]] = barContext.AO
fooContext = {
AO: {},
Scope: foo.[[scope]] = barContext.AO
}
//30
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);
globalContext = {
AO: {
a: 200,
fn: function
fn3: function
}
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO
fnContext = {
AO: {
a: 6
fn2: function(){}
},
Scope: globalContext.AO
}
fn2.[[scope]] = fnContext.AO
fn3Context = {
AO: {},
Scope: globalContext.AO
}
fn2Context = {
AO: {},
Scope: globalContext.AO
}
//undefined 5 1 6 20 200
题目1:函数声明和函数表达式有什么区别
函数声明:
function sayHello(){
console.log('hello')
}
sayHello()
//声明不必放在调用的前面,但要在同一个作用域下
函数表达式:
var sayHello = function(){
console.log('hello');
}
sayHello()
//声明必须放在调用的前面
题目2:什么是变量的声明前置?什么是函数的声明前置
变量声明前置:
js引擎工作方式是,先解析代码,获取所有被声明的变量,然后
再逐行运行,造成的结果是,所有的变量的声明语句,都会被提
升到代码的头部,这就叫做变量提升
函数声明前置:
和变量声明前置类似,如果我们使用函数声明的方式,那么即使函数
写在最后也可以在前面语句调用,前提是函数声明部分已经被下载到
本地
fn()
function fn(){
console.log('1');
}
题目3:arguments 是什么
//在函数内部,可以使用arguments对象获取到该函数的所有传入参数
//arguments是一个类数组对象
function printPersonInfo(name,age,sex){
console.log(name);
console.log(age);
console.log(sex);
console.log(arguments);
console.log(arguments[0]);
}
function printPersonInfo(){
console.log(arguments[0])
}
printPersonInfo(2,'boy')
//arguments[0] 类数组对象可使用该方法
//arguments[1]
题目4:函数的"重载"怎样实现
//重载是函数具有相同的名字,但是由于传入的参数不同,执行不同操作。在js中没有类似其他语言的重载,因为同名函数会被覆盖。但是js可以通过在函数内部对传入参数进行判断来达到重载的目的
//js没有重载,同名函数会覆盖,
//但可以在函数体针对不同的参数调用执行响应的逻辑
function printPeopleInfo(name, age, sex){
if(name){
console.log(name);
}
if(age){
console.log(age);
}
if(sex){
console.log(sex);
}
}
printPeopleInfo('Byron', 26);
printPeopleInfo('Byron', 26, 'male');
题目5:立即执行函数表达式是什么?有什么作用
(function(){
var a = 1;
})()
//隔离作用域,避免变量污染全局
题目6:求n!,用递归来实现
function factor(n) {
if( n === 1){
return 1;
}else{
return n * factor(n-1);
}
}
//不递归
function factor(n){
var result = 1;
for(var i=1; i<n+1; i++){
result = i*result
}
return result;
}
题目7:以下代码输出什么?

结果:
getInfo('饥人谷', 2, '男');
//name: 饥人谷
//age: 2
//sex: 男
//arguments(3)['饥人谷', 2, '男']
//name: valley
getInfo('小谷', 3);
//name:小谷
//age: 3
//sex: undefined
//arguments(2)['小谷', 3]
//name: valley
getInfo('男');
//name: 男
//age: undefined
//sex: undefined
//arguments['男']
//name: valley
题目8:写一个函数,返回参数的平方和?

function sumOfSquares(){
var h = 0;
for(var i=0; i<arguments.length; i++){
h = h + arguments[i] * arguments[i]
}
return h
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
//更严谨的写法
function sumOfSquares(){
var res = 0;
for (var i in arguments){
if (typeof arguments[i] !== 'number') {
return 'you entered a wrong number';
}
}
for (var j in arguments){
res += arguments[j]*arguments[j];
}
return res;
}
题目9:如下代码的输出?为什么

console.log(a) //undefined
console.log(b) //Reference error
题目10:如下代码的输出?为什么

输出:
//hello world
//Uncaught TypeError: sayAge is not a function
//第一个是函数声明 调用可以放在任何地方
//第二个是函数表达式 调用必须放在声明之后
题目11. 如下代码输出什么? 写出作用域链查找过程伪代码

先声明前置
globalContext = {
AO: {
x: 10
foo: function
bar: function
},
Scope: null
}
//声明foo时 得到下面
foo.[[scope]] = globalContext.AO
//声明foo时 得到下面
bar.[[scope]] = globalContext.AO
//注意: 在当前的执行上下文内声明的函数,
//这个函数的[[scope]]就执行当前执行上下文的AO
barContext = {
AO: {
x: 30
},
Scope: bar.[[scope]]
}
fooContext = {
AO: null
Scope: foo.[[scope]]
}
//结果为10
题目12. 如下代码输出什么? 写出作用域链查找过程伪代码

globalContext{
AO: {
x: 10
bar: function
},
Scope: null
}
bar.[[Scope]] = globalContext.AO
barContext {
AO: {
x: 30
foo: function
},
Scope: bar.[[scope]] = globalContext.AO
}
foo.[[scope]] = barContext.AO
fooContext = {
AO: {},
Scope: foo.[[scope]] = barContext.AO
}
题目13. 如下代码输出什么? 写出作用域链查找过程伪代码

题目14. 如下代码输出什么? 写出作用域链查找过程伪代码

globalContext{
AO:{
a: 1
fn: function
fn3: function
}
}
fn.[[scope]] = globalContext.AO
fn3.[[scope]] = globalContext.AO
fnContext{
AO:{
}
}
fn3Context{
AO:{
}
}
网友评论