84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
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类型不能直接转化为字符串,所以报错了。
你可以
就知道了。