究竟是怎么样的一道面试题,能让我拿出来说说呢?下面请看代码:

function fun(a,b) {    console.log(b)    return {        fun: function(c) {            return fun(c,a);        }    };}var d = fun(0); d.fun(1); d.fun(2);d.fun(3);var d1 = fun(0).fun(1).fun(2).fun(3);var d2 = fun(0).fun(1);d2.fun(2);d2.fun(3);复制代码




如何判断两种函数的方法呢?

可以用fn.name来判断,如果有name就是具名函数,如果没有name就是匿名函数。

需要注意的是在IE浏览器上无法获取具名函数的name,会返回undefined的结果,而在谷歌浏览器上就可以获取。

// 获取名称function getFunctionName(fun){ if(fun.name !== undefined)  return fun.name;  var funName = fun.toString();  funName = funName.substr('function '.length);  funName = funName.substr(0, funName.indexOf('('));  return funName;}复制代码

2

函数创建的方法有哪些?

第一种是:声明函数,声明函数方法,包括函数名和函数体。

function funDa() {}复制代码

第二种是:创建匿名函数的表达式。

创建一个变量,这个变量的内容是一个函数,为匿名函数

var funDa = function() {}复制代码

这样这个函数就没有了name

var funDa = function(){}getFunctionName(funDa).length;// 0复制代码

第三种是:创建具名函数表达式。

var funDa = function dada(){};复制代码

创建一个变量,变量赋值的内容为一个带有名称的函数。具名函数表达式的函数名只能在创建函数内部使用,函数的外层只能使用funData,dada函数名只能在创建函数内部使用。



在对象内定义函数,也是属于函数表达式。

第四种是:Function构造函数


Function("alert(1)");ƒ anonymous() {alert(1)}Function("dada");ƒ anonymous() {dada}new Function("alert(1)");ƒ anonymous() {alert(1)}new Function("dada");ƒ anonymous() {dada}复制代码

Function构造函数传一个函数字符串,返回包含这个字符串命令的函数。

第五种是:自执行函数




( function(){    alert(1);})();undefined( function(){    alert(1);})ƒ (){    alert(1);}复制代码


(function da1(){    alert(1);})();复制代码

自执行函数也是“函数表达式”。

第六种是:其他

运用eval,setTimeout,setInterval等方法。

3


第一个fun函数是属于标准的具名函数声明,是新创建的函数,返回的是一个对象字面量表达式,属性一个新的Object。

这返回,对象内部包含一个fun的属性,属于匿名函数表达式,这个fun属性存放的是一个新创建匿名函数表达式,所有声明的匿名函数都是一个新函数。则第一个fun函数和第二个fun函数不同,都是新创建的函数。

4

函数作用域链的问题


对象内部的函数表达式:


var d = {    fn: function(){        console.log(fn);    }};d.fn();VM1879:3 Uncaught ReferenceError: fn is not defined    at Object.fn (<anonymous>:3:21)    at <anonymous>:6:3fn @ VM1879:3(anonymous) @ VM1879:6var d1 = {    fn: function(){        console.log("dada");    }};d1.fn();VM1973:3 dadaundefined复制代码

非对象内部的函数表达式:


var da = function () {    console.log(da);};da();VM2270:2 ƒ () {    console.log(da);}undefined复制代码

使用var可以访问到存放当前函数的变量,var da,da()访问函数的变量,在对象内部不能访问到。

5

函数作用域链:

function fun(a,b) {    console.log(b)    return {        fun: function(c) {            return fun(c,a);        }    };}var d = fun(0); d.fun(1); d.fun(2);d.fun(3);var d1 = fun(0).fun(1).fun(2).fun(3);var d2 = fun(0).fun(1); d2.fun(2);d2.fun(3);复制代码
var d = fun(0); d.fun(1); d.fun(2);d.fun(3);复制代码
undefinedVM2273:2 0VM2273:2 0VM2273:2 0复制代码

第一个fun(0)在调用第一层fun函数,第二个fun(1)是在调用前一个fun的返回值的fun函数。即就是fun(1),fun(2),fun(3)函数独使在调用第二层fun函数,第一次调用fun(0)时,b为undefined,第二次调用fun(1),c为1,a为0。

var d = fun(0);调用的是第一层

而d.fun->fun(0).fun调用第二层

fun:function(1),return fun(1,a),fun(1,0),此时fun闭包了外层函数的a,也就是第一次调用的a=0。这样子第一层fun函数为fun(1,0),所以为0。

第一次:

function fun(0,undefined) {    console.log(undefined)    return {        fun: function(c) {            return fun(c,0);        }    };}复制代码

fun(0),b为undefined,fun(0).fun(1),c=1,此时fun闭包外层函数的a,也就是第一次调用的a=0,即c=1,a=0,并在内部调用第一层fun函数fun(1,0),所以b=0。

function fun(a,b) {    console.log(b)    return {        fun: function(1) {            return fun(1,0);        }    };}复制代码

第三次调用fun(2)时,c为2,还是调用d.fun,还是闭包了第一次调用时的a,fun(2,0)所以输出b为0。

function fun(a,b) {    console.log(b)    return {        fun: function(c) {            return fun(c,a);        }    };}var d = fun(0); d.fun(1); d.fun(2); d.fun(3);复制代码

6

var d1 = fun(0).fun(1).fun(2).fun(3);复制代码


从fun(0)调用第一层fun函数,返回值为一个对象,第二个fun(1)调用的是第二层fun函数,后面的也是第二层fun函数。

第一层fun(0),b为undefined,第二层.fun(1)时c为1,c=1,a=0,内部调用第一层fun函数fun(1,0),所以b为0。

调用你.fun(2)时,c为2,此时当前的fun函数不是第一次执行的返回对象,而是第二次执行的返回对象,第二次执行第一层fun函数是:

fun(1,0),a=1,b=0。第三次执行fun函数,c=2,a=1

function fun(a,b) {    console.log(b)    return {        fun: function(1) {            return fun(1,0);        }    };}fun(1,0),a=1,b=0。第三次执行fun函数,c=2,a=1function fun(a,b) {    console.log(b)    return {        fun: function(2) {            return fun(2,1);        }    };}// 1function fun(2,1) a=2, b=1复制代码

第四次调用.fun(3)为c为3

// a=2function fun(a,b) {    console.log(b)    return {        fun: function(3) {            return fun(3,2);        }    };}复制代码

7

var d2 = fun(0).fun(1);d2.fun(2);d2.fun(3);复制代码



var d2=fun(0).fun(1); // undefined, 0 此时的return(c=1,a=0),return fun(1,0),所以b为0


d2.fun(2); 第三次调用.fun(2),c为2

// c为2,a=1,b=0function fun(a,b) {    console.log(b)    return {        fun: function(2) {            return fun(2,a);        }    };}所以return fun(2,1)function fun(a=2,b=1),所以为 1复制代码

d2.fun(3),c为3,还是调用的第二次的返回值,最终调用第一层的 fun(a,b)

// c为3,a=1,b=0function fun(a,b) {    console.log(b)    return {        fun: function(3) {            return fun(3,a);        }    };}所以return fun(3,1)function fun(a=3,b=1),所以为 1复制代码

注意这里的:

// c为3,a=1,b=0这是调用这个代码的结果a=1,b=0复制代码
var d2 = fun(0).fun(1);复制代码

好了,这样就知道大概的答案和讲解了:

8

总的来说,你明白了!讲的好辛苦,给个赞哦!求奖励,我来了


function fun(a,b) {    console.log(b)    return {        fun: function(c) {            return fun(c,a);        }    };}var d = fun(0); d.fun(1); d.fun(2);d.fun(3);var d1 = fun(0).fun(1).fun(2).fun(3);var d2 = fun(0).fun(1); d2.fun(2);d2.fun(3);undefinedVM1036:2 0VM1036:2 0VM1036:2 0VM1036:2 undefinedVM1036:2 0VM1036:2 1VM1036:2 2VM1036:2 undefinedVM1036:2 0VM1036:2 1VM1036:2 1{fun: ƒ}







function fun(a,b) { console.log(b) return { fun: function(c) { return fun(c,a); } }; } var d = fun(0); d.fun(1); d.fun(2); d.fun(3); var d1 = fun(0).fun(1).fun(2).fun(3); var d2 = fun(0).fun(1); d2.fun(2); d2.fun(3); 复制代码

undefinedVM1036:2 0VM1036:2 0VM1036:2 0VM1036:2 undefinedVM1036:2 0VM1036:2 1VM1036:2 2VM1036:2 undefinedVM1036:2 0VM1036:2 1VM1036:2 1{fun: ƒ}复制代码
//答案://undefined,0,0,0//undefined,0,1,2//undefined,0,1,1复制代码

JS函数分两种:具名函数(命名函数)和匿名函数。


©著作权归作者所有:来自51CTO博客作者qq6048445b266f9的原创作品,如需转载,请注明出处,否则将追究法律责任

好知识,才能预见未来

赞赏

0人进行了赞赏支持

更多相关文章

  1. 闪存出现“位置不可用无法访问函数不正确”的解决方法
  2. js 中的作用域与闭包,类与继承 ---- 0402
  3. JavaScript知识:作用域与闭包以及类与类的继承
  4. 数组函数的练习
  5. 搞懂作用域与闭包
  6. 课程学习记录之python迭代器和生成器
  7. 工具需用好,阅读源码没烦恼
  8. 用 Hypothesis 来自动化单元测试
  9. Python_学习之Pycharm配置技巧

随机推荐

  1. Android(安卓)判断Root的方法
  2. Android 线程优先级设置方法
  3. Google手机操作系统Android应用开发入门
  4. Android 数据库简单操作
  5. Android缓存理解
  6. Android(安卓)frameworks中Bn*和Bp*的区
  7. Android系统启动流程 -- android
  8. Android笔记-2
  9. 配置并使用Android支持的库
  10. Android(安卓)向系统发送一条短信