Daily-Interview-Question
Daily-Interview-Question copied to clipboard
第 33 题:下面的代码打印什么内容,为什么?
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."
不知道我这回答有没有问题
我的理解是,先不看函数自执行,直接fn b() 首先函数声明比变量要高,其次b = 20 没有var 获取其他,说明是window最外层定义的变量。 js作用域中,先找最近的 那就是b fn ,直接打印了,如果 b = 20 有var 那就是打印20
1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;
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 的规范吗?
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."不知道我这回答有没有问题
关键function b() { b = 20; console.log(b) }这是一个具名函数,
(function b() { b = 20; console.log(b) })()那这还是IIFE吗?
@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);
如上所提供的函数表达式的名称的作用域仅仅是该函数自身。这允许引擎去做更多的优化,并且这种实现更可读、友好。该名称也显示在调试器和一些堆栈跟踪中,节省了调试时的时间。
@jjeejj
这个目前暂时还没有去确认下是不是ES5规范,只是看到了一篇博客上是这么说的

@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是函数表达式,而不是函数声明,但发现是个具名函数了...
几个例子:
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
})();
var b = 10; (function b() { b = 20; console.log(b); })();
具名自执行函数的变量为只读属性,不可修改
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 的规范吗?
所以重点是:非匿名自执行函数,函数名只读。
@jefferyE 匿名函数是可以递归调用的,只不过在严格模式下会报错
(function(counter){
if (counter) {
return;
}
return arguments.callee(1);
})()
@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 变量指的是函数表达式的函数名。试想一下:如果你在函数里面拿不到该函数的函数名,那你怎么进行递归?
// 验证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,就会形成死循环,递归调用.所以这是一个执行环境的问题
原题
var b = 10; (function b() { b = 20; console.log(b); })()//输出函数b针对这道题我提一下我的想法,有不正确的地方还希望各位大佬指出
IIFE会创建一个块级作用域,
根据作用域链的知识,当出现同名的变量的时候,会优先访问更"近"的变量
在题目中的IIFE里面
b=20其实访问的是window下的b变量,所以IIFE中其实没有b变量,
那么最近的b变量就是这个函数。
我觉得这个最棒的也最好理解的回答 如果执行体内加了var声明 那就是声明的值
我简单点再说下自己的看法: 因为具名函数的函数名标识符(这在例子中的b)只能在函数体内可以访问,并且是不可修改的。所以对b重新赋值也是无效的,所以输出的结果是一个函数。 详细解析请访问:https://segmentfault.com/q/1010000002810093/a-1020000002810564
当JS 解释器遇到非匿名立即执行函数时,会创建一个辅助的特定对象,然后将函数名称当作这个对象的属性,因此函数内部才可以访问到b,但是这个值又是只读的,所以对他的赋值并不生效,所以打印的结果还是这个函数,并且外部的值也没有发生更改 这里说的很清楚了,各位大佬可以看看~~(咦,这个链接不能直接在这里打开,要复制到浏览器中才能打开?) https://yuchengkai.cn/docs/frontend/#%E6%89%A7%E8%A1%8C%E4%B8%8A%E4%B8%8B%E6%96%87
非匿名自执行函数,函数名只读
var b = 10; (function b(){ b = 20; console.log(this.b); })(); // 打印:10 var b = 10; (function b(){ var b = 20; console.log(b); })(); // 打印:20
问:这个函数还是不是立即执行函数,立即执行函数不得是一个匿名函数吗
(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()
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."不知道我这回答有没有问题
常量的话没必要,这只是严格模式下为了规范代码,防止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是函数自身的一个引用,对于全局变量来说,它是不可见的。
1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;
只读状态为什么没报错呢?
var b = 10; (function b() { var b = 20; console.log(b) })()
为什么用了 var b = 20,输出变成20呢。不用var输出b()
@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 是函数表达式,而函数表达式的函数名是常量,无法二次赋值(在正常模式下静默失效,在严格模式下报错),赋值失败,所以输出的还是该函数
@daiyunchao 严格模式下会报错
把()中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
var b = 10;
(function b(){
b = 20;
console.log(b);
})();
1打印结果内容如下: ƒ b() { b = 20; console.log(b) } 2原因: 作用域:执行上下文中包含作用于链: 在理解作用域链之前,先介绍一下作用域,作用域可以理解为执行上下文中申明的变量和作用的范围;包括块级作用域/函数作用域; 特性:声明提前:一个声明在函数体内都是可见的,函数声明优先于变量声明; 在非匿名自执行函数中,函数变量为只读状态无法修改;
我有个疑问,函数声明的确优于变量声明,但是却不优于变量赋值,所以我的疑问是跟优先级没有关系,不知对不对
可以写成这个,配合作用域和变量提升,就可以知道为什么打印的是函数b了
var b = 10;
var c = function b () {
b = 20;
console.log(b);
}
c();
1.函数表达式中的函数名只在函数体内部可用,指代函数表达式本身,其他地方都不可用 2.函数表达式中的函数名是只读的,所以b=20;会赋值失败
- 非匿名自执行函数,函数名只读(类似常量)
- 非严格模式下给常量命名静默失败
- 严格模式下给常量命名报错 TypeError

good answer
考察知识点
- closure
- IIFE
- hoisting
- scope
- function declaration / function expression
- 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 variablevar 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 })();
1.IIFE中的函数是一个函数表达式,不是函数声明。
区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。比如这里的第一个词是"(",不是function,所有这里的函数是一个函数表达式。
2.函数声明中的的函数名被绑定在它声明所在的作用域中。函数表达式中的函数名被绑定在函数自身的函数体中。
在IIFE中的函数名不会污染外部作用域。
(function b() {
console.log(b);
})()
这里函数名"b"只在函数内部有效,它是函数内部的局部变量。
3.在函数表达式的内部只能通过函数名访问该函数,但是不能通过函数名对该函数重新赋值
(function b() {
b = 20; // 无效
console.log(b);
})()
1.IIFE中的函数是一个函数表达式,不是函数声明。
区分函数声明和表达式最简单的方法是看function关键字出现在声明中的位置(不仅仅是一行代码,而是整个声明中的位置)。如果function是声明中的第一个词,那么就是一个函数声明,否则就是一个函数表达式。比如这里的第一个词是"(",不是function,所有这里的函数是一个函数表达式。
2.函数声明中的的函数名被绑定在它声明所在的作用域中。函数表达式中的函数名被绑定在函数自身的函数体中。
在IIFE中的函数名不会污染外部作用域。
(function b() { console.log(b); })()这里函数名"b"只在函数内部有效,它是函数内部的局部变量。
3.在函数表达式的内部只能通过函数名访问该函数,但是不能通过函数名对该函数重新赋值
(function b() { b = 20; // 无效 console.log(b); })()
你真棒棒。。。麽麽噠
下面的代码打印什么内容,为什么
var b = 10;
(function b(){
b = 20;
console.log(b);
})();
输出函数体,原因: IFFE中的函数是一个函数表达式,不是函数声明,类似于 const a = function(){} 常量绑定, 加入对一个常量进行赋值,非strict模式默认无效,strict模式报错, 所以a=20不会覆盖原有的函数名b,而是会在全局,也就是window下添加一个名为b的属性,值为20, 输出 function(){ xxx }
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)走的原型链
我可能搞错了,但是我觉得以下这个代码片段
/* 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 才会优先指向《命名函数》本身,《命名函数》本身必须处于一种“流离失所”的状态
自执行函数会被编译成函数表达式,函数表达式的函数名所在的作用域为函数本身,且函数名是只读的,不可被重新赋值。
// function b(){
// b=20;
// console.log(b)
// }
// var b;
// b=10;
// b()
执行是这样执行的 在window环境下查找 函数执行 环境决定的预估跟左右查询变量有关系 但说不上问题出在哪里了
var b = 10; (function b() { b = 20; console.log(b); })();具名自执行函数的变量为只读属性,不可修改
我记得你不知道的js里面有说这个,但是找不到在哪里了。
首先运行结果是打印 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了。
@.***
非匿名函数,函数名只在函数内有效,且不可赋值
@.***