ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

最后亿遍js总结

2021-07-14 13:34:18  阅读:145  来源: 互联网

标签:总结 slice const Object js 亿遍 toString call prototype


原型原型链

继承

call,apply,bind用法及实现

  • 作用:简单来说就是改变this的指向,在一个对象中调用另一个对象的方法

用法

  • applycall的用法相似,会直接执行函数
A.sayName.call(B,'tom')
A.sayName.apply(B,['tom'])
  • bind用法与call相似,不同的是,她不会立即执行,他会返回原函数的拷贝
let bSay = A.sayName.bind(B,'tom') //拷贝
bSay()//调用

实现

//A.myCall(B,arg1,arg2)

//挂载到Function 的原型对象上,以便继承给函数对象调用
Function.prototype.myCall = function (originFun, ...args) {
	//A点出的myCall,这里this 指向A函数
    console.log(this)
    //在B里面定义一个私有属性指向A函数
    originFun.__thisFn__ = this
    //B调用A函数,this指向B
    let result = originFun.__thisFn__(...args) 
    //删除无用属性
    delete originFun.__thisFn__
    return result
}


判断类型的方法

  • typeofinstanceof

  • Object.prototype.toString.call();每个对象都存在toString()方法,默认情况下,被每个Object对象继承,如果未被覆盖,会返回[object type],type是对象的类型。比如:

    let obj= new Object()
    obj.toString() //输出 "[object Object]"
    

    但是对于其他情况

    var arr =new Array(1,2)
    arr.toString() // 输出 "1,2"
    

    这是因为所谓的ArrayString等类型在继承于基类Object时,重写了toString方法,在调用的时候,通过原型链向上查找方法时,找到Array上面的toString就停止查找,直接调用了,所以输出与预想的有偏差,那如何让arr去调用Object上面的该方法呢?显而易见借用call()

    Object.prototype.toString.call(arr) // 输出 "[object Array]"
    

    然后在利用 slice方法截取出来类型

    // 是否字符串
    export const isString = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'String'
    
    // 是否数字
    export const isNumber = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Number'
    
    // 是否boolean
    export const isBoolean = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Boolean'
    
    // 是否函数
    export const isFunction = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Function'
    
    // 是否为null
    export const isNull = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Null'
    
    // 是否undefined
    export const isUndefined = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Undefined'
    
    // 是否对象
    export const isObj = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Object'
    
    // 是否数组
    export const isArray = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Array'
    
    // 是否时间
    export const isDate = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Date'
    
    // 是否正则
    export const isRegExp = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'RegExp'
    
    // 是否错误对象
    export const isError = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Error'
    
    // 是否Symbol函数
    export const isSymbol = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Symbol'
    
    // 是否Promise对象
    export const isPromise = (o) => Object.prototype.toString.call(o).slice(8, -1) === 'Promise'
    

捕获与冒泡

  • 事件捕获与冒泡过程

image-20210701104838356

捕获

  • 事件捕获阶段,会由外到内,一层一层的检查是否注册了事件

  • 如何在捕获阶段注册事件?

    • 使用 addEventListener注册事件,第三个参数代表是否在捕获阶段处理事件,设置为true
    <div class="box">
        <button class="btn">按钮</button>
    </div>
    
    <script>
        //先显示div 后显示btn
        const box = document.querySelector('.box')
        box.addEventListener(
            'click',
            () => {
                alert('div被点击了')
            },
            true
        )
        const btn = document.querySelector('.btn')
        btn.addEventListener(
            'click',
            () => {
                alert('button被点击了')
            },
            true
        )
    </script>
    
    

冒泡

  • 与捕获相反,在事件冒泡阶段,会从里到外来检查是否注册事件

  • 默认情况下,所有的事件都是在冒泡阶段进行注册,如何阻止事件冒泡?

    • w3标准

      event.stopPropagation()
      
    • IE浏览器

      event.cancelBubble=true
      

事件委托

  • 多个元素注册了相同的事件,可以把这些事件委托到它的父元素上,比较常见的是ul里面的li标签点击事件
<ul>
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>

<script>
    const ul = document.querySelector('ul')
    ul.addEventListener('click', (e) => {
        if (e.target.nodeName == 'LI') {
            alert(e.target.innerText)
        }
    })
</script>

闭包问题

  • 在一个内层函数中访问到外层函数的作用域

隔离作用域

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },
    decrement: function() {
      changeBy(-1);
    },
    value: function() {
      return privateCounter;
    }
  }
};

// Counter1与Counter2互不影响,在闭包内修改变量,不会影响到另一个闭包中的变量
var Counter1 = makeCounter();
var Counter2 = makeCounter();
console.log(Counter1.value()); /* logs 0 */
Counter1.increment();
Counter1.increment();
console.log(Counter1.value()); /* logs 2 */
Counter1.decrement();
console.log(Counter1.value()); /* logs 1 */
console.log(Counter2.value()); /* logs 0 */

经典for循环闭包问题

for (var i = 1, arr = []; i < 5; i++) {
    setTimeout(() => {
        console.log(i)
    }, 500)
}// 5,5,5,5

//使用闭包

for (var i = 1, arr = []; i < 5; i++) {
    ;(function (i) {
        setTimeout(() => {
            console.log(i)
        }, 1000 * i)
    })(i)
}//1,2,3,4

new对象时发生了什么,实现一个new

const myNew = (constructorFn, ...args) => {
  // 创建一个新的对象
  let obj = {}
  // 创建一个私有属性,指向构造函数的原型对象
  obj.__proto__ = constructorFn.prototype
  // 执行构造函数
  constructorFn.call(obj, ...args)
  //返回这个对象
  return obj
}
function Person(name, age) {
  this.name = name
  this.age = age
}

const Per1 = new Person('Tom', 12)
console.log('Per1', Per1)
const Per2 = myNew(Person, 'Tom', 12)
console.log('Per2',Per2)

image-20210701174620575

防抖与节流

闭包

深浅拷贝

  • 基本类型 StringNumber等都是按值访问的,它的值存储在栈中
  • 引用类型都是 按引用访问的,它将引用地址存储在栈上,然后再去堆上开辟空间存放他们的值

浅拷贝

  • 如果是基本类型,就直接拷贝基本类型的值,如果是引用类型,就拷贝引用类型的引用地址
  • 浅拷贝对于基本类型来说,他们之间改变值不会相互影响,但是对于引用类型来说,由于拷贝的是地址,这些地址最终都指向同一个堆里面,所以会互相影响

实现方式

  • ES6展开运算符
let obj1 ={name:'tom',age:12,addr:{lng:26.0,lag:45.0},friends:['john','jerry']}
let obj2={...obj1}
obj2.name='jerry'
obj2.frinds[0]='tom'

image-20210702095035320

ES6展开运算符对于不同结构的数据,存在不同的表现.对于一维的对象或者数组,进行的深拷贝,对于多维的对象或者数组进行的是浅拷贝

  • Object.assign()
let obj1 ={name:'tom',age:12,addr:{lng:26.0,lag:45.0},friends:['john','jerry']}
let obj2= Object.assign({}, obj1);

与解构赋值的作用一样

  • lodash.clone()
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var shallow = _.clone(objects);
console.log(shallow[0] === objects[0]);

深拷贝

  • 主要针对于引用类型,他会在对上面重新开辟一空间存放对象,这样两个深拷贝的对象就不会互相影响了

实现方式

  • JSON.parse(JSON.stringfy() )
let obj1 ={name:'tom',friends:['jerry','john']}
let obj2 =JSON.parse(JSON.stringify(obj1))
obj2.name='jerry'
obj2.friends[0]='tom'

image-20210702134922212

  • lodash.cloneDeep()
var objects = [{ 'a': 1 }, { 'b': 2 }];
 
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
  • 递归遍历实现
function clone(targetObj) {
    //判断是否未对象,是对象去遍历拷贝
    if (typeof targetObj === 'object') {
        //判断源数据是对象还是数组
        let cloneTarget = Array.isArray(targetObj) ? [] : {}
        for (const key in targetObj) {
            //递归拷贝
            cloneTarget[key] = clone(targetObj[key])
        }
        return cloneTarget
    } else {
        //不是对象直接返回
        return targetObj
    }
}

标签:总结,slice,const,Object,js,亿遍,toString,call,prototype
来源: https://www.cnblogs.com/baifangzi/p/15010353.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有