javascript - 奇怪的Symbol的问题

查看:198
本文介绍了javascript - 奇怪的Symbol的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

这是抽出来的两行代码 var name = Symbol('test') 一直提示 无法转换,是关键字保留?还是其他原因?
为什么换一个var name1 = Symbol('test')却可以通过编译?
其他普通的var s1 s2也可通过编译。

解决方案

这问题挺有意思的,我也从来没有注意到,翻了翻资料,发现原来是很多事情巧合的凑合到一块儿,然后出现了这个问题。准确的来说,是浏览器的默认行为和JavaScript的隐式类型变换捣的鬼。


一点一点来,首先,varlet的区别在哪里?

var声明的变量会被提升至当前函数作用域顶端,如果是在全局那么这个变量将会成为window的一个属性。
而对于let声明的变量,它会将变量提升至当前块级作用域,并且如果是在全局,当前变量也不会成为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是不是固定的保留字?

翻翻规范,还真是的。
window.name属性表示的是当前窗口上下文的名称。下面是window的部分接口:

[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

所以当我们给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

但是,似乎不太对,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()不是一个东西。

对于Symbol变量而言,当其调用ToString的时候就会报错,更详细的我就不展开了,有兴趣的可以自己看看规范:ToString ( argument )

这篇关于javascript - 奇怪的Symbol的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆