Daily-Interview-Question icon indicating copy to clipboard operation
Daily-Interview-Question copied to clipboard

第 33 题:下面的代码打印什么内容,为什么?

Open jefferyE opened this issue 6 years ago • 51 comments

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

  1. 函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。
  2. 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。
  3. IIFE中的函数是函数表达式,而不是函数声明。

实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

const foo = function () {
  foo = 10;
  console.log(foo)
}
(foo)() // Uncaught TypeError: Assignment to constant variable.

我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 例如下面的:

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

不知道我这回答有没有问题

jefferyE avatar Mar 14 '19 01:03 jefferyE

我的理解是,先不看函数自执行,直接fn b() 首先函数声明比变量要高,其次b = 20 没有var 获取其他,说明是window最外层定义的变量。 js作用域中,先找最近的 那就是b fn ,直接打印了,如果 b = 20 有var 那就是打印20

blockmood avatar Mar 14 '19 01:03 blockmood

1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;

GeekQiaQia avatar Mar 14 '19 02:03 GeekQiaQia

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

  1. 函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。
  2. 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。
  3. IIFE中的函数是函数表达式,而不是函数声明。

实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

const foo = function () {
  foo = 10;
  console.log(foo)
}
(foo)() // Uncaught TypeError: Assignment to constant variable.

我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 例如下面的:

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

不知道我这回答有没有问题

这个回答主要表达的是:函数表达式的函数名只在该函数内部有效,且绑定是常量类似 const,不能修改

解答了一部分疑问,但是这个是ES 的规范吗?

jjeejj avatar Mar 14 '19 02:03 jjeejj

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

  1. 函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。
  2. 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。
  3. IIFE中的函数是函数表达式,而不是函数声明。

实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

const foo = function () {
  foo = 10;
  console.log(foo)
}
(foo)() // Uncaught TypeError: Assignment to constant variable.

我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 例如下面的:

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

不知道我这回答有没有问题

关键function b() { b = 20; console.log(b) }这是一个具名函数, (function b() { b = 20; console.log(b) })()那这还是IIFE吗?

ghost avatar Mar 14 '19 02:03 ghost

@jessie-zly 这个上面有回答 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Functions 里面说明一个潜在问题——既然匿名函数没有名字,那该怎么递归调用它呢?在这一点上,JavaScript 允许你命名这个函数表达式。你可以命名立即调用的函数表达式(IIFES——Immediately Invoked Function Expressions) 例如:

var charsInBody = (function counter(elm) {
  if (elm.nodeType == 3) { // 文本节点
       return elm.nodeValue.length;
   }
   var count = 0;
   for (var i = 0, child; child = elm.childNodes[i]; i++) {
       count += counter(child);
   }
   return count;
})(document.body);

如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。

jefferyE avatar Mar 14 '19 02:03 jefferyE

@jjeejj 这个目前暂时还没有去确认下是不是ES5规范,只是看到了一篇博客上是这么说的 image

jefferyE avatar Mar 14 '19 03:03 jefferyE

@jefferyE

@jessie-zly 这个上面有回答 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Functions 里面说明一个潜在问题——既然匿名函数没有名字,那该怎么递归调用它呢?在这一点上,JavaScript 允许你命名这个函数表达式。你可以命名立即调用的函数表达式(IIFES——Immediately Invoked Function Expressions) 例如:

var charsInBody = (function counter(elm) {
  if (elm.nodeType == 3) { // 文本节点
       return elm.nodeValue.length;
   }
   var count = 0;
   for (var i = 0, child; child = elm.childNodes[i]; i++) {
       count += counter(child);
   }
   return count;
})(document.body);

如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。

如果是这样的话,那很好奇预编译后的代码了... ps: 我第一眼也认为是IIFE是函数表达式,而不是函数声明,但发现是个具名函数了...

ghost avatar Mar 14 '19 03:03 ghost

几个例子:

var b = 10;
(function b() {
   // 内部作用域,会先去查找是有已有变量b的声明,有就直接赋值20,确实有了呀。发现了具名函数 function b(){},拿此b做赋值;
   // IIFE的函数无法进行赋值(内部机制,类似const定义的常量),所以无效。
  // (这里说的“内部机制”,想搞清楚,需要去查阅一些资料,弄明白IIFE在JS引擎的工作方式,堆栈存储IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();

所以严格模式下能看到错误:Uncaught TypeError: Assignment to constant variable

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

其他情况例子:

window

var b = 10;
(function b() {
    window.b = 20; 
    console.log(b); // [Function b]
    console.log(window.b); // 20是必然的
})();

var:

var b = 10;
(function b() {
    var b = 20; // IIFE内部变量
    console.log(b); // 20
   console.log(window.b); // 10 
})();

giscafer avatar Mar 14 '19 03:03 giscafer

var b = 10; (function b() { b = 20; console.log(b); })(); 具名自执行函数的变量为只读属性,不可修改

dingLeiOnly avatar Mar 14 '19 07:03 dingLeiOnly

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。 IIFE中的函数是函数表达式,而不是函数声明。 实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

const foo = function () {
  foo = 10;
  console.log(foo)
}

(foo)() // Uncaught TypeError: Assignment to constant variable. 我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 例如下面的:

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)

})() // "Uncaught TypeError: Assignment to constant variable." 不知道我这回答有没有问题

这个回答主要表达的是:函数表达式的函数名只在该函数内部有效,且绑定是常量类似 const,不能修改

解答了一部分疑问,但是这个是ES 的规范吗?

ghost avatar Mar 14 '19 10:03 ghost

所以重点是:非匿名自执行函数,函数名只读。

LasyIsLazy avatar Mar 14 '19 13:03 LasyIsLazy

@jefferyE 匿名函数是可以递归调用的,只不过在严格模式下会报错

(function(counter){
	if (counter) {
		return;
	}
	return arguments.callee(1);
})()

ghost avatar Mar 16 '19 11:03 ghost

@wasonal

在题目中的 IIFE 里面 b = 20 其实访问的是 window 下的 b 变量

按照你这种说法,外面 b 变量的值会变成 20,但是最后验证发现:外面 b 变量的值仍然是 10。所以从侧面验证,你上面的这句话是错误的。

	var b = 10;

	var _b = function b() {
		b = 20;
		console.log(b);
	}();

根据作用域链的知识,当出现同名的变量的时候,会优先访问更 "近" 的变量

这句话是正确的,具体解释可以去看这篇文章

所以 IIFE 中其实没有 b 变量

这句话是错误,b 变量指的是函数表达式的函数名。试想一下:如果你在函数里面拿不到该函数的函数名,那你怎么进行递归?

ghost avatar Mar 19 '19 09:03 ghost

// 验证1 var b = 10; // 报错 function b () { b =20; console.log(b); } b(); // 验证2 var b =10; (function b(b){ b = 20; console.log(b); // 20,说明如果函数作用域挂载了名为b的变量,那么就会赋值改变 })() // 验证3 var b =10; (function b(){ var b = 20; console.log(b); // 20 })() // 验证4 var b =10; (function a(b){ b = 20; console.log(b); // 20 })() // 验证5 function b () { alert(0) } (function b(){ b() console.log(b); // 无限循环,而不是alert(0) })() 从上面的验证其实就可以看到,在自执行函数b的执行环境中是没有变量b,但是有函数b的,因为没有进行实参传入和var,let声明,所以b=20会顺着作用域链往外找,就找到了b=10,那个地方,对应b=20,改变的也是全局环境的b变量.所以,当你在函数b中打印b,这时是不分变量和函数的,因为b的执行环境中挂载的有函数b,函数b就会被打印出来.你可以参考我最后一个验证,不是b=20,而是直接调用b,就会形成死循环,递归调用.所以这是一个执行环境的问题

YYYCondi avatar Mar 19 '19 09:03 YYYCondi

原题 var b = 10; (function b() { b = 20; console.log(b); })()//输出函数b

针对这道题我提一下我的想法,有不正确的地方还希望各位大佬指出

IIFE会创建一个块级作用域,

根据作用域链的知识,当出现同名的变量的时候,会优先访问更"近"的变量

在题目中的IIFE里面b=20其实访问的是window下的b变量,

所以IIFE中其实没有b变量,

那么最近的b变量就是这个函数。

我觉得这个最棒的也最好理解的回答 如果执行体内加了var声明 那就是声明的值

formattedzzz avatar Apr 18 '19 11:04 formattedzzz

我简单点再说下自己的看法: 因为具名函数的函数名标识符(这在例子中的b)只能在函数体内可以访问,并且是不可修改的。所以对b重新赋值也是无效的,所以输出的结果是一个函数。 详细解析请访问:https://segmentfault.com/q/1010000002810093/a-1020000002810564

ablikim915 avatar Apr 30 '19 08:04 ablikim915

当JS 解释器遇到非匿名立即执行函数时,会创建一个辅助的特定对象,然后将函数名称当作这个对象的属性,因此函数内部才可以访问到b,但是这个值又是只读的,所以对他的赋值并不生效,所以打印的结果还是这个函数,并且外部的值也没有发生更改 这里说的很清楚了,各位大佬可以看看~~(咦,这个链接不能直接在这里打开,要复制到浏览器中才能打开?) https://yuchengkai.cn/docs/frontend/#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87

sisi529 avatar May 30 '19 03:05 sisi529

非匿名自执行函数,函数名只读

chenzesam avatar Jul 09 '19 11:07 chenzesam

var b = 10; (function b(){ b = 20; console.log(this.b); })(); // 打印:10 var b = 10; (function b(){ var b = 20; console.log(b); })(); // 打印:20

gdrpAPeng avatar Jul 12 '19 04:07 gdrpAPeng

问:这个函数还是不是立即执行函数,立即执行函数不得是一个匿名函数吗

tyktianxia avatar Jul 18 '19 17:07 tyktianxia

(function b(){
  b = 20;
  console.log(b); 
})

上式function用括号括起来了,说明这是一个函数表达式,而不是一个函数声明。括号可以改变运算符的优先级,在这里它是一个分组符。可参考文章:https://www.cnblogs.com/TomXu/archive/2011/12/29/2290308.html 具名函数表达式中的函数名在函数内部是可以访问的,但函数外面是无法访问到的,这点和函数声明有很大的不同。没有括号的话,全局变量是可以访问到b的。至于函数里面的b是全局变量自然不必细说。因此,console.log里面的b肯定现在函数内部找,然后再在全局找,所有b就是funcition b{}。 因此,代码等价于:

var b = 10;
fun=function b(){
  b = 20;
  console.log(b); 
};
fun()

qiannianchong25 avatar Jul 23 '19 11:07 qiannianchong25

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

针对这题,在知乎上看到别人的回答说:

  1. 函数表达式与函数声明不同,函数名只在该函数内部有效,并且此绑定是常量绑定。
  2. 对于一个常量进行赋值,在 strict 模式下会报错,非 strict 模式下静默失败。
  3. IIFE中的函数是函数表达式,而不是函数声明。

实际上,有点类似于以下代码,但不完全相同,因为使用const不管在什么模式下,都会TypeError类型的错误

const foo = function () {
  foo = 10;
  console.log(foo)
}
(foo)() // Uncaught TypeError: Assignment to constant variable.

我的理解是,b函数是一个相当于用const定义的常量,内部无法进行重新赋值,如果在严格模式下,会报错"Uncaught TypeError: Assignment to constant variable." 例如下面的:

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

不知道我这回答有没有问题

常量的话没必要,这只是严格模式下为了规范代码,防止b被修改罢了。但是在非严格模式下,就是说可以修改的,不必当成常量。因为要考虑到具名函数声明的情况下,函数的名称在其所在的执行环境下,都是可以访问的,也是可修改的。

function test(){
  'use strict';
  function b(){
    console.log(23)
  }
  b=null;
  console.log(b)
}
test()
```js
函数如果是声明的话,那么在其声明所在的执行环境内,其函数名可做为一个执行环境的一个变量;如果是表达式的话,在其所声明的执行环境内,是不可访问的,只是单纯的作为一个函数名称,它的引用可通过name属性来获取它;在函数内部,除非被重新声明,它是指向自身的引用值。这个题中,是因为括号的存在,导致它变成了一个函数表达式,而不是一个函数声明。参见帖子:https://www.cnblogs.com/TomXu/archive/2011/12/29/2290308.html
所以console.log(b)中的b是函数自身的一个引用,对于全局变量来说,它是不可见的。

qiannianchong25 avatar Jul 23 '19 12:07 qiannianchong25

1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;

只读状态为什么没报错呢?

daiyunchao avatar Aug 20 '19 09:08 daiyunchao

var b = 10; (function b() { var b = 20; console.log(b) })()

为什么用了 var b = 20,输出变成20呢。不用var输出b()

ravencrown avatar Sep 22 '19 08:09 ravencrown

@ravencrown

两种情况:

var b = 20

var b 则在函数 b 内申明了一个局部变量,当执行 b = 20 时,顺着作用域链向上找,于是在函数内找到了局部变量 b(也就是 var b 的), 将其修改为 20。console.log(b)同理,顺着作用域链向上找,找到了局部变量 b,且其值为 20.

b = 20

执行 b = 20 时,顺着作用域链向上找,找到函数 b, 尝试给 b 赋值为 20,由于函数 b 是函数表达式,而函数表达式的函数名是常量,无法二次赋值(在正常模式下静默失效,在严格模式下报错),赋值失败,所以输出的还是该函数

AnaniZhu avatar Sep 24 '19 09:09 AnaniZhu

@daiyunchao 严格模式下会报错

AnaniZhu avatar Sep 24 '19 09:09 AnaniZhu

把()中IIFE函数执行过程这样理解试一下:

var b = function () {
  b = 20;
  console.log(b);
};

Object.defineProperty(window, "b", {
  writable: false,
  configurable: false
});

b();

An anonymous function that is called immediately is most often called an immediately invoked function expression (IIFE). It resembles a function declaration, but because it is enclosed in parentheses it is interpreted as a function expression.

这段话引用自:《javascript高级程序设计第4版》大概意思是立即执行函数,写法上看着像是个“函数声明” 实际上是按“函数表达式”解析的。

回过头来,我们看IIFE为什么要这样设计?

var b = 10;
(function b() {
  b = 20;
  console.log(b)
})()

这里的局部变量b(函数体b)我们外部能调用吗? 不能,该变量只能在函数体内部被访问,它代表命名空间函数本身。

我们没有理由去声明一个与命名空间函数名冲突的变量名,也没有理由更改这个变量,很显然这与命名空间的思想冲突,我们应该保持该变量的纯净。

因此,这种“命名空间函数名”被作为常量的设计是合理的,建议使用新的变量名存储自己的变量。

至于具体是如何实现的,懂C的同学可以去扒一下v8的源码,臣妾真的是做不到了。

Note:其中不明白的术语,请自行Google

woshidamaomao avatar Nov 29 '19 07:11 woshidamaomao

var b = 10;
(function b(){
    b = 20;
    console.log(b); 
})();

yygmind avatar Dec 16 '19 02:12 yygmind

1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;

我有个疑问,函数声明的确优于变量声明,但是却不优于变量赋值,所以我的疑问是跟优先级没有关系,不知对不对

TheHtmler avatar Dec 18 '19 08:12 TheHtmler

可以写成这个,配合作用域和变量提升,就可以知道为什么打印的是函数b了

var b = 10;
var c = function b () {
	b = 20;
	console.log(b);
}
c();

lovelmh13 avatar Jan 29 '20 07:01 lovelmh13

1.函数表达式中的函数名只在函数体内部可用,指代函数表达式本身,其他地方都不可用 2.函数表达式中的函数名是只读的,所以b=20;会赋值失败

15025639392 avatar Apr 13 '20 18:04 15025639392

  1. 非匿名自执行函数,函数名只读(类似常量)
  2. 非严格模式下给常量命名静默失败
  3. 严格模式下给常量命名报错 TypeError

zuoyi615 avatar Apr 16 '20 14:04 zuoyi615

image

lianglixiong avatar Apr 17 '20 09:04 lianglixiong

good answer

考察知识点

  1. closure
  2. IIFE
  3. hoisting
  4. scope
  5. function declaration / function expression
  6. named function / anonymous function

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions

几个例子:

var b = 10;
(function b() {
   // 内部作用域,会先去查找是有已有变量b的声明,有就直接赋值20,确实有了呀。
   // 发现了具名函数 function b(){},拿此b做赋值;
   // IIFE的函数无法进行赋值(内部机制,类似const定义的常量),所以无效。
   //(这里说的“内部机制”,想搞清楚,需要去查阅一些资料,
   // 弄明白IIFE在JS引擎的工作方式,堆栈存储IIFE的方式等)
    b = 20;
    console.log(b); // [Function b]
    console.log(window.b); // 10,不是20
})();

所以严格模式下能看到错误:Uncaught TypeError: Assignment to constant variable

var b = 10;
(function b() {
  'use strict'
  b = 20;
  console.log(b)
})() // "Uncaught TypeError: Assignment to constant variable."

其他情况例子:

window

var b = 10;
(function b() {
    window.b = 20; 
    console.log(b); // [Function b]
    console.log(window.b); // 20是必然的
})();

var:

var b = 10;
(function b() {
    var b = 20; // IIFE内部变量
    console.log(b); // 20
   console.log(window.b); // 10 
})();

xgqfrms avatar Apr 18 '20 03:04 xgqfrms

1.IIFE中的函数是一个函数表达式,不是函数声明。

区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。比如这里的第一个词是"(",不是function,所有这里的函数是一个函数表达式。

2.函数声明中的的函数名被绑定在它声明所在的作用域中。函数表达式中的函数名被绑定在函数自身的函数体中。

在IIFE中的函数名不会污染外部作用域。

(function b() {
  console.log(b);
})()

这里函数名"b"只在函数内部有效,它是函数内部的局部变量。

3.在函数表达式的内部只能通过函数名访问该函数,但是不能通过函数名对该函数重新赋值

(function b() {
  b = 20;  // 无效
  console.log(b);
})()

Wluyao avatar May 22 '20 08:05 Wluyao

1.IIFE中的函数是一个函数表达式,不是函数声明。

区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。比如这里的第一个词是"(",不是function,所有这里的函数是一个函数表达式。

2.函数声明中的的函数名被绑定在它声明所在的作用域中。函数表达式中的函数名被绑定在函数自身的函数体中。

在IIFE中的函数名不会污染外部作用域。

(function b() {
  console.log(b);
})()

这里函数名"b"只在函数内部有效,它是函数内部的局部变量。

3.在函数表达式的内部只能通过函数名访问该函数,但是不能通过函数名对该函数重新赋值

(function b() {
  b = 20;  // 无效
  console.log(b);
})()

你真棒棒。。。麽麽噠

fariellany avatar May 25 '20 06:05 fariellany

下面的代码打印什么内容,为什么

var b = 10;
(function b(){
    b = 20;
    console.log(b); 
})();

输出函数体,原因: IFFE中的函数是一个函数表达式,不是函数声明,类似于 const a = function(){} 常量绑定, 加入对一个常量进行赋值,非strict模式默认无效,strict模式报错, 所以a=20不会覆盖原有的函数名b,而是会在全局,也就是window下添加一个名为b的属性,值为20, 输出 function(){ xxx }

soraly avatar Jun 19 '20 10:06 soraly

var fn1=function fn2(){ fn1=222; fn2=333; console.log(fn1); console.log(fn2); } fn1(); =>222 =>fn2()

var fn1=(function fn2(){ fn1=222; fn2=333; console.log(fn1); console.log(fn2); })() =>222 =>fn2()

结果是一样的,跟立即执行没啥关系 因为这个fn2是定义在fn2.prototype.constructor对象中,属性名为name console.log(fn2.prototype.constructor.name); => fn2 个人理解 fn2=333走的是作用域链 console.log(fn2)走的原型链

justsoup avatar Jul 02 '20 13:07 justsoup

我可能搞错了,但是我觉得以下这个代码片段

    /* part 1 */
    function a() { 
        a = 1;
        console.log("a1:", a); 
    };
    /* part 2 */
    function a() { 
        a = 2;
        console.log("a1:", a); 
    };
    a();
    console.log("a2:", a);

证明了它和 Function.name 的 Writable 属性 是没有关系的

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/name

Function.name 只是一个 Function 的命名和它是否可以被赋值无关

同时,另外一种说法,也就是《命名函数》如 function a() {...} 内《和命名函数同名的变量》会优先指向命名函数本身

这种说法应该也是错误的,为什么呢,因为以上的代码打印的是 a1: 2, a2: 2 也就是说,不仅《命名函数》/* part 2 */ function a() {...} 内的 a 可以被修改,打印为2,实际上 window.a 也被修改了,最终打印为2

也就是说实际上只有单纯有《命名函数》,是不构成函数内《和命名函数同名的变量》会优先指向命名函数本身这个现象,而以上片段实际上应该相当于

    /* part 1 */
    var a = function () { 
        a = 1;
        console.log("a1:", a); 
    };
    /* part 2 */
    var a = function () { 
        a = 2;
        console.log("a1:", a); 
    };
    a();
    console.log("a2:", a);

那么我们发现只有在《自启动命名函数》或《被赋值的命名函数》,也就是:

    void function a() { ... }

    var a = function a() { ... }

时,函数的内部作用域中的 《和命名函数同名的变量》 a 才会优先指向《命名函数》本身

实际上无论哪种写法,都是需要该命名函数《不被挂载在window对象上》,换而言之,需要使得《和命名函数同名的变量》 a 才会优先指向《命名函数》本身,《命名函数》本身必须处于一种“流离失所”的状态

aeroxy avatar Oct 19 '20 15:10 aeroxy

自执行函数会被编译成函数表达式,函数表达式的函数名所在的作用域为函数本身,且函数名是只读的,不可被重新赋值。

MrLeihe avatar Apr 23 '21 02:04 MrLeihe

// function b(){ // b=20; // console.log(b)
// } // var b; // b=10; // b()

执行是这样执行的 在window环境下查找 函数执行 环境决定的预估跟左右查询变量有关系 但说不上问题出在哪里了

lei334453 avatar Jun 09 '21 15:06 lei334453

var b = 10; (function b() { b = 20; console.log(b); })(); 具名自执行函数的变量为只读属性,不可修改

我记得你不知道的js里面有说这个,但是找不到在哪里了。

LeeRayno avatar Sep 05 '21 14:09 LeeRayno

首先运行结果是打印 b 函数; 我觉得这个问题想要考察的是:一个是 IIFE 有独立的词法作用域,第二是b=20是将 b 定义为全局变量。 词法检查的结果为:

window: {
    b: 20,
    IIFE: {
        b: function b() {}
    }
}

在执行 IIFE 的时候,第一行 b = 20,会将b挂到window上,并不会在这个IIFE 的词法作用域内,所以最终打印的是 b 函数。 另外,如果把函数b 中的 b = 20 改成 var b = 20 那么结果就会打印20了。

chxlvwh avatar Mar 14 '22 01:03 chxlvwh

@.***

jessie-zly avatar Mar 14 '22 01:03 jessie-zly

非匿名函数,函数名只在函数内有效,且不可赋值

Yangfan2016 avatar Aug 04 '22 12:08 Yangfan2016

@.***

jessie-zly avatar Aug 04 '22 12:08 jessie-zly