Dies sind die beiden extrahierten Codezeilen var name = Symbol('test') 一直提示 无法转换,是关键字保留?还是其他原因?为什么换一个var name1 = Symbol('test')却可以通过编译?其他普通的var s1 s2Sie können auch kompiliert werden.
var name = Symbol('test')
var name1 = Symbol('test')
var s1 s2
这问题挺有意思的,我也从来没有注意到,翻了翻资料,发现原来是很多事情巧合的凑合到一块儿,然后出现了这个问题。准确的来说,是浏览器的默认行为和JavaScript的隐式类型变换捣的鬼。
浏览器的默认行为
隐式类型变换
一点一点来,首先,var和let的区别在哪里?
var
let
var声明的变量会被提升至当前函数作用域顶端,如果是在全局那么这个变量将会成为window的一个属性。 而对于let声明的变量,它会将变量提升至当前块级作用域,并且如果是在全局,当前变量也不会成为window的属性。
window
所以,在全局中会出现这样的事情:
var test1 = 'test1'; let test2 = 'test2'; console.log(window.test1); // test1 console.log(window.test2); // undefined
然后,name为名的变量和别的变量有什么区别? 上面我们知道了,var name = 'test1';实际上可以等同于window.name = 'test1',很容易就能想到,name是不是固定的保留字?
name
var name = 'test1';
window.name = 'test1'
翻翻规范,还真是的。 window.name属性表示的是当前窗口上下文的名称。下面是window的部分接口:
window.name
[ReplaceableNamedProperties] interface Window { // the current browsing context readonly attribute WindowProxy window; readonly attribute WindowProxy self; readonly attribute Document document; attribute DOMString name; //.. }
name属性在这里的最后一行,没有readonly的前缀,说明它是可读可写的,它的数据类型则是DOMString。 DOMString是指UTF-16的字符串,在JavaScript中它会直接映射到String。
readonly
DOMString
String
所以当我们给window.name赋值的时候,这个值会被强制转换为String。
我们可以试试看:
var name = { a:1, b:2 }; console.log(window.name); // [object Object] var name = [0, 1, 2, 3]; console.log(window.name); // 0,1,2,3
到了这里大概就能猜到,var name = Symbol('test');的错误,应该是Symbol变量在做类型转换的时候出了问题。而实际报的错误也证实了我们的猜测:TypeError: Cannot convert a Symbol value to a string。
var name = Symbol('test');
Symbol
TypeError: Cannot convert a Symbol value to a string
但是,似乎不太对,Symbol变量是可以转换成字符串的啊,比如:
let test = Symbol('test'); console.log(test.toString()); // Symbol(test) console.log(String(test)); // Symbol(test)
嘛,这就是比较老生常谈的东西了,JavaScript的隐式类型变换和显式的强制转换对于部分变量是不同的。很不幸,在这里Symbol就是这么一类。
Symbol被隐式的转换时,它会首先调用其内部的ToPrimitive接口,拿到其原始值,然后在其中再调用ToString函数转换为字符串。注意,这里的这个ToString函数是其内部的抽象方法,和暴露在外的Symbol.prototype.toString()不是一个东西。
ToPrimitive
ToString
Symbol.prototype.toString()
对于Symbol变量而言,当其调用ToString的时候就会报错,更详细的我就不展开了,有兴趣的可以自己看看规范:ToString ( argument )。
我刚刚也在控制台试了一下,确实是个很神奇的BUG,不过你将
var name = Symbol("test"); //改成 let name = Symbol("test"); //试试。。
然后惊奇的发现BUG又没了。。我猜跟浏览器是怎么解析语法有关,但这些东西我也不懂啊。
name是window的特有属性,如果你换个变量试试就不会报错了。。。
name 是 window 的特有属性,在全局环境下定义的name变量,赋任何值都会自动转化成字符串,而Symbol类型不能直接转化为字符串,所以报错了。
你可以
var name = 1; console.log(name);
就知道了。
这问题挺有意思的,我也从来没有注意到,翻了翻资料,发现原来是很多事情巧合的凑合到一块儿,然后出现了这个问题。准确的来说,是
浏览器的默认行为
和JavaScript的隐式类型变换
捣的鬼。一点一点来,首先,
var
和let
的区别在哪里?var
声明的变量会被提升至当前函数作用域顶端,如果是在全局那么这个变量将会成为window
的一个属性。而对于
let
声明的变量,它会将变量提升至当前块级作用域,并且如果是在全局,当前变量也不会成为window
的属性。所以,在全局中会出现这样的事情:
然后,
name
为名的变量和别的变量有什么区别?上面我们知道了,
var name = 'test1';
实际上可以等同于window.name = 'test1'
,很容易就能想到,name
是不是固定的保留字?翻翻规范,还真是的。
window.name
属性表示的是当前窗口上下文的名称。下面是window
的部分接口:name
属性在这里的最后一行,没有readonly
的前缀,说明它是可读可写的,它的数据类型则是DOMString
。DOMString
是指UTF-16的字符串,在JavaScript中它会直接映射到String
。所以当我们给
window.name
赋值的时候,这个值会被强制转换为String
。我们可以试试看:
到了这里大概就能猜到,
var name = Symbol('test');
的错误,应该是Symbol
变量在做类型转换的时候出了问题。而实际报的错误也证实了我们的猜测:TypeError: Cannot convert a Symbol value to a string
。但是,似乎不太对,
Symbol
变量是可以转换成字符串的啊,比如:嘛,这就是比较老生常谈的东西了,JavaScript的隐式类型变换和显式的强制转换对于部分变量是不同的。很不幸,在这里
Symbol
就是这么一类。Symbol
被隐式的转换时,它会首先调用其内部的ToPrimitive
接口,拿到其原始值,然后在其中再调用ToString
函数转换为字符串。注意,这里的这个ToString
函数是其内部的抽象方法,和暴露在外的Symbol.prototype.toString()
不是一个东西。对于
Symbol
变量而言,当其调用ToString
的时候就会报错,更详细的我就不展开了,有兴趣的可以自己看看规范:ToString ( argument )。我刚刚也在控制台试了一下,确实是个很神奇的BUG,不过你将
然后惊奇的发现BUG又没了。。我猜跟浏览器是怎么解析语法有关,但这些东西我也不懂啊。
name是window的特有属性,如果你换个变量试试就不会报错了。。。
name 是 window 的特有属性,在全局环境下定义的name变量,赋任何值都会自动转化成字符串,而Symbol类型不能直接转化为字符串,所以报错了。
你可以
就知道了。