一、基础部分
(一)基本类型
-
值类型
-
存储在栈内存中
-
包括:undefined string number boolean symbol
-
值类型没有方法,
'1'.toString()合法是因为'1'被包装成了String对象 -
Symbol
Symbol代表独一无二的值- 声明
let s1 = Symbol() let s2 = Symbol() console.log(s1 === s2) // false // 可以给Symbol传一个字符串参数作为对Symbol的描述,类似于给Symbol起个名字 let s3 = Symbol('foo') let s4 = Symbol('bar') // 对象作为参数,调用对象的toString方法(注意这个方法是可以重写的) const onj = { name: 'xxx', toString() { return this.name } } let s5 = Symbol(obj) console.log(s) //Symbol(xxx) // 使用description api可以获得Symbol的描述 let s6 = Symbol('hahaha') console.log(s6.description) // hahaha // 即使传递的参数相同,创造的也是不同的Symbol,如果想要创造相同的Symbol可以使用for api let s7 = Symbol.for('111') let s8 = Symbol.for('111') console.log(s7 === s8) // true /* Symbol 和 Symbol.for的区别: Symbol(‘foo’)不会在全局中声明,每次声明都生成一个新的 Symbol.for('foo')相当于在全局中声明一个(无论定义的时候是否在全局下定义,都是相当于在全局环境下声明,和定义的位置无关),即便重复100次也只声明一个。 */ // Symbol.keyFor(),获取注册在全局的Symbol的key,和Symbol.for是一套 const s9 = Symbol.for('222') console.log(Symbol.keyFor(s9)) // 222-
应用:
- 场景1:对象中的key相同。比如,用对象存储班级同学的信息,以姓名为key,如果有重名的情况,直接定义会产生覆盖,此时可以用Symbol
const stu1 = Symbol('张三') const stu2 = Symbol('张三') const grade = { [stu1]: {address: 'xxx', tel: '111'}, [stu2]: {address: 'yyy', tel: '222'} } console.log(grade) console.log(grade[stu1]) console.log(grade[stu2])- 场景二
一定程度上隐藏属性,使用
Symbol定义的属性,无法用in、Object.keys遍历到。使用
getOwnPropertySymbols可以遍历到Symbol但是无法得到普通的属性 使用Reflect.ownKeys可以遍历到全部const sym = Symbol('sss') class User = { constructor(name) { this.name = name this[sym] = 'ddd' } getName() { return this.name + this[sym] } } const user = new User('蛤') console.log(user.getName())- 场景三:消除魔术字符串
-
-
引用类型
- 由于一般体积较大,存储在堆内存中,栈内存中存一个指向这个堆内存的地址
- 包括:object(数组、函数、普通对象、正则、日期等等)
注意:
null
有的观点认为null是值类型;有的观点认为null是特殊的引用类型,代表一个空指针。
typeof null返回'null'- 对象的属性名一定不能是引用类型,默认会把引用类型值转换为字符串
-
类型检测
-
typeof- 能够识别所有的值类型
- 能识别函数
- 能判断是不是引用类型,但不能细分(如果
null也算引用类型的话)
typeof NaN // "number" NaN == NaN // false // 检测是否为有效数字需要用isNaN()
-
-
constructor-
[].constructor === Array,返回true -
Object.prototype.toString.call() -
Object.prototype.toString.call([]),返回"[object Array]" -
instanceof- 可以识别引用类型
- 沿着原型链寻找,如果找到返回
true instanceof可以自定义行为,比如让instanceof识别基础类型
class PrimitiveString { static [Symbol.hasInstance](x) { return typeof x === 'string' } } console.log('hello world' instanceof PrimitiveString) // true- 手写
instanceof
function instanceOf(left,right) { let proto = left.__proto__; let prototype = right.prototype while(true) { if(proto === null) return false if(proto === prototype) return true proto = proto.__proto__; } } 作者:前端劝退师 链接:https://juejin.im/post/5c9c3989e51d454e3a3902b6 来源:掘金 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 -
类型检测工具函数
var class2type = {}; var toString = class2type.toString; var hasOwn = class2type.hasOwnProperty; var fnToString = hasOwn.toString; var ObjectFunctionString = fnToString.call(Object); "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ).forEach(function anonymous(item){ class2type[ "[object " + name + "]" ] = name.toLowerCase(); }); function toType( obj ) { if ( obj == null ) { return obj + ""; } return typeof obj === "object" || typeof obj === "function" ? class2type[ toString.call( obj ) ] || "object" : typeof obj; } /*================*/ var isFunction = function isFunction(obj) { return typeof obj === "function" && typeof obj.nodeType !== "number"; }; var isWindow = function isWindow(obj) { return obj != null && obj === obj.window; }; var isPlainObject = function isPlainObject(obj) { var proto, Ctor; if (!obj || toString.call(obj) !== "[object Object]") { return false; } proto = Object.getPrototypeOf(obj); // Objects with no prototype (`Object.create( null )`) if (!proto) { return true; } // Objects with prototype are plain iff they were constructed by a global Object function Ctor = hasOwn.call(proto, "constructor") && proto.constructor; return typeof Ctor === "function" && fnToString.call(Ctor) === ObjectFunctionString; }; var isEmptyObject = function isEmptyObject(obj) { var name; for (name in obj) { return false; } return true; }; var isArrayLike = function isArrayLike(obj) { var length = !!obj && "length" in obj && obj.length, type = toType(obj); if (isFunction(obj) || isWindow(obj)) { return false; } return type === "array" || length === 0 || typeof length === "number" && length > 0 && (length - 1) in obj; }; -