JavaScript技能深入记录及学习——3

104 阅读5分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 15 天,点击查看活动详情

前言

我觉得我也不见得比别人差太多


BEGIIN

js——常识总结

判断方式:数组,对象

判断数组方式?

arr.**proto**=== Array.prototype

Array.isArray(arr)

arr instanceOf Array

Array.prototype.isPrototypeOf(arr)

Array.prototype.toString.call(arr).slice(8, -1) ==== 'Array'

判断对象方式?

Array.prototype.toString.call(obj)

obj.constructor === Object

obj instanceOf Object

typeof (null 也是Object)

遍历对象方式

for in 依次访问一个对象以及原型链上所有可访问的属性

Object.keys 返回一个数组 包含所有可枚举的属性名称

Object.getOwnPropertyNames 返回一个数组包含不可枚举的属性

深浅拷贝、赋值

赋值

定义:赋值都是该对象的栈中地址,而不是堆中的数据 所有类型全部都相互影响

浅拷贝

Object.assign()

function shallowClone(obj) {\
    return Object.assign({}, obj); 
}

展开运算符(...)

function shallowClone(obj) { 
    return {...obj}; 
}

使用数组的 slice() 函数或对象的 Object.keys() 函数`

let arr = [a,3]

let arr2 = arr.slice()

函数库loadsh中的_.clone 方法

深拷贝

常见的方法包括使用 JSON.parseJSON.stringify

const original = { a: 1, b: { c: 2 } }; 
const copy = JSON.parse(JSON.stringify(original));

使用递归算法:deepClone()

const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const objectTag = '[object Object]';

const boolTag = '[object Boolean]';
const dateTag = '[object Date]';
const errorTag = '[object Error]';
const numberTag = '[object Number]';
const regexpTag = '[object RegExp]';
const stringTag = '[object String]';
const symbolTag = '[object Symbol]';
function isObject(target) {
    const type = typeof target;
    return target !== null && (type === 'object' || type === 'function');
}
function getType(target) {
    return Object.prototype.toString.call(target);
}
function getInit(target) {
    const Ctor = target.constructor;
    return new Ctor();
}
function clone(target, map = new WeakMap()) {

    // 克隆原始类型
    if (!isObject(target)) {
        return target;
    }

    // 初始化
    const type = getType(target);
    let cloneTarget;
    if (deepTag.includes(type)) {
        cloneTarget = getInit(target, type);
    }

    // 防止循环引用
    if (map.get(target)) {
        return map.get(target);
    }
    map.set(target, cloneTarget);

    // 克隆set
    if (type === setTag) {
        target.forEach(value => {
            cloneTarget.add(clone(value,map));
        });
        return cloneTarget;
    }

    // 克隆map
    if (type === mapTag) {
        target.forEach((value, key) => {
            cloneTarget.set(key, clone(value,map));
        });
        return cloneTarget;
    }

    // 克隆对象和数组
    const keys = type === arrayTag ? undefined : Object.keys(target);
    forEach(keys || target, (value, key) => {
        if (keys) {
            key = value;
        }
        cloneTarget[key] = clone(target[key], map);
    });

    return cloneTarget;
}

使用 lodash_.cloneDeep 方法

bind实现原理

  1. 可以指定this

  2. 返回一个函数

  3. 可以传入参数

  4. 可以用new 操作符

     注:不是函数调用会报错
     
    
Function.prototype.bind1 = function(context){
        if(typeof this !== 'function'){
            throw new Error(this must be function);
        }
        var self = this;
        var args = Array.prototype.slice.call(arguments,1);
        let fNop = function(){};// 作为中介,重写原型对象,代之为构造函数的实例
        let fBound =  function(){ 
            var bindArgs = Array.prototype.slice.call(arguments);
            return self.apply(this instanceof fBound ? this:context ,args.concat(bindArgs)); 
        }
        fNop.prototpye = this.prototype; 
        fBound.prototype = new fNop(); // 
        return fBound;
    }

bind VS call VS apply

new实现原理

  1. 创建了一个对象
  2. 设置原型 将对象的原型设置为函数的prototype对象
  3. 吧this 指向对象,执行构造函数的代码
  4. 判断函数的返回值类型
  5. 如果是值 返回创建的对象 若是引用对象 就返回这个引用类型的对象
function news(constructor, ...param) {
  const obj = {}
  obj.__proto__ = constructor.prototype  
  const res = constructor.apply(obj, param)
  return res instanceof **Object** ? res : obj
}

instanceof实现原理

instanceof主要用于判断某个实例是否属于某个类型,也可用于判断某个实例是否是其父类型或者祖先类型的实例。

instanceof 主要的实现原理就是只要右边变量的 prototype 在左边变量的原型链上即可。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,如果查找失败,则会返回 false。

function instanceofs (left, right) {
  let B = right.prototype  
 while(true) {
    if (left === null) {
      return false  
   }
    if (left === B) {
      return true  
   }
    left = left.__proto__  
 }
}
typeof VS instanceof

①返回值不同: typeof 返回数据类型;instanceof返回布尔值

②null,对象,数组都会返回‘object’,局限性;instanceof用于判断对象,形式为:obj1 instanceof obj2(obj1 是否是 obj2的实例),obj2必须是对象,否则会报错。

js——闭包

定义:有权访问另一个函数作用域的变量的一个函数 / 函数块以及函数定义时所在的词法环境两者的结合就是闭包

作用:

  • 希望变量长期驻扎在内存中
  • 避免全局变量的污染

JS执行上下文

要经过浏览器V8编译后才能执行。比如 变量提升函数提升

js代码运行需要一个环境,就是js执行上下文。js运行前的预编译也是这个环境进行的

全局执行上下文:代码开始执行时首先进入的环境
函数执行上下文:函数调用时,会开始执行函数中的代码
eval执行上下文 :不建议使用

周期:

  • 创建阶段

    • 创建词法环境
    • 生成变量对象(vo),建立作用域链
    • 确认this指向, 并绑定this
  • 执行阶段

    • 这个阶段进行变量复制,函数引用及执行代码

预编译发生在函数执行之前

  • 四步:

    • 创建AO对象
    • 找形参和变量声明,将变量和形参作为AO属性名,值为undefined
    • 将实参和形参相统一
    • 在函数体里找到函数声明,值赋予函数体,最后程序输出变量值的时候,就是从AO拿

js——设计模式

最重要思想:

  • 开放封闭原则
  • 对扩展开放
  • 对修改封闭

工厂模式

定义: 用一个工厂函数,来创建实例,隐藏new

如:jQuery $函数;React createElement 函数

image.png

单例模式

定义:全局唯一的实例

如:Vuex Redux 的store; 全局唯一的dialog modal

JS是单线程,创建单例很简单

image.png

代理模式

定义:使用者不能直接访问对象,必须要通过代理。如:proxy

观察者模式

image.png

观察者 和发布订阅区别

image.png

END