Symbol原理 用来生成一个独一无二的值
Symbol是ES6规范中的一种原生数据类型,也就是说所有支持ES6规范的JavaScript都应该实现Symbol这一基本数据类型
那么对于V8而言,就应该在底层实现Symbol对象
src/builtins/builtins-symbol.cc
17
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 BUILTIN(SymbolConstructor) { HandleScope scope (isolate) ; if (!args.new_target()->IsUndefined(isolate)) { THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kNotConstructor, isolate->factory()->Symbol_string())); } Handle<Symbol> result = isolate->factory()->NewSymbol(); Handle<Object> description = args.atOrUndefined(isolate, 1 ); if (!description->IsUndefined(isolate)) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, description, Object::ToString(isolate, description)); result->set_description(String::cast(*description)); } return *result; }
我们可以看到这个最终的函数返回结果是 result,
result = isolate -> factory() -> NewSymbol();
src/torque/earley-parser.h
437
1 2 3 4 5 6 Symbol* NewSymbol (std ::initializer_list <Rule> rules = {}) { auto symbol = std ::make_unique<Symbol>(rules); Symbol* result = symbol.get(); generated_symbols_.push_back(std ::move(symbol)); return result; }
可以看出Symbol 是从 make_unique 函数中创建的
参考 https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique ,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 namespace detail {template <class >constexpr bool is_unbounded_array_v = false ;template <class T >constexpr bool is_unbounded_array_v<T[]> = true ; template <class >constexpr bool is_bounded_array_v = false ;template <class T , std : :size_t N>constexpr bool is_bounded_array_v<T[N]> = true ;} template <class T , class ... Args >std ::enable_if_t <!std ::is_array<T>::value, std ::unique_ptr <T>>make_unique(Args&&... args) { return std ::unique_ptr <T>(new T(std ::forward<Args>(args)...)); } template <class T >std ::enable_if_t <detail::is_unbounded_array_v<T>, std ::unique_ptr <T>>make_unique(std ::size_t n) { return std ::unique_ptr <T>(new std ::remove_extent_t <T>[n]()); } template <class T , class ... Args >std ::enable_if_t <detail::is_bounded_array_v<T>> make_unique(Args&&...) = delete ;
可以看出
make_unique 是从unique_ptr中派生出来的
参考 https://en.cppreference.com/w/cpp/memory/unique_ptr
std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope.
也就是说unique_ptr是一个对象.
看一下Symbol在pollyfill中的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 function Symbol (description ) { if (!(this instanceof Symbol )) return new Symbol (description, secret); if (this instanceof Symbol && arguments [1 ] !== secret) throw TypeError (); var descString = description === undefined ? undefined : String (description); set_internal(this , '[[SymbolData]]' , unique(128 )); set_internal(this , '[[Description]]' , descString); symbolMap[this ] = this ; return this ; }
可以看出,就是一个构造函数, 只是这个函数在使用的时候有点特殊,return 了一个Symbol自身的实例,也就是一个对象.
问题一: 那么一个对象,是不能在对象中作为key来使用的 1 2 3 4 5 6 7 Object .defineProperty(Symbol .prototype, 'toString' , { value: function toString ( ) { var s = strict(this ); var desc = s['[[Description]]' ]; return 'Symbol(' + (desc === undefined ? '' : desc) + s['[[SymbolData]]' ] + ')' ; }, configurable: true , writeable : true , enumerable : false });
在一下返回值,'Symbol(' + (desc === undefined ? '' : desc) + s['[[SymbolData]]'] + ')';
这个只是一个以Symbol字符串description开头的字符串, 按道理是应该没有后面的s['[[SymbolData]]']
,为了保持唯一性就加上了这个,唯一标示.
问题二, Object.getPropertyNames 是不是会打印出 Symbol,答案 是 ,所以需要改写 getPropertyNames 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 define( Object , 'getOwnPropertyNames' , function getOwnPropertyNames (o ) { if (Object .prototype.toString.call(o) === '[object Window]' ) { try { return $getOwnPropertyNames(o).filter(isStringKey); } catch (_) { return $window_names.slice(); } } return $getOwnPropertyNames(o).filter(isStringKey); }, !nativeSymbols); define( Object , 'getOwnPropertySymbols' , function getOwnPropertySymbols (o ) { return $getOwnPropertyNames(o).filter(symbolForKey).map(symbolForKey); }, !nativeSymbols);
问题三 JSON在序列化的时候,不能序列化Symbol,但是目前而言,它只是一个String,也就是说会被序列化. 没有办法, JSON.stringify 后 会变成 一个随机字符串
问题四 typeof symbol 怎么被改写 没有办法, typeof 是一个不能被改写的操作, 如此依赖 typeof symbol === ‘object’
Symbol 不是能是一个构造函数,它没有 prototype,
同时 symbol实例是没有__proto__属性的,因此 instanceof 不能被修改