JS知识点总结01

121 阅读3分钟

一、基础部分

(一)基本类型

  • 值类型

    • 存储在栈内存中

    • 包括: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定义的属性,无法用inObject.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(数组、函数、普通对象、正则、日期等等)

    注意:

    1. null

    有的观点认为null是值类型;有的观点认为null是特殊的引用类型,代表一个空指针。

    typeof null 返回'null'

    1. 对象的属性名一定不能是引用类型,默认会把引用类型值转换为字符串
  • 类型检测

    • 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;
    };