首页 > 编程语言 >javascript-cnblog

javascript-cnblog

时间:2023-02-05 10:24:38浏览次数:42  
标签:obj 函数 javascript return const array cnblog name

1. 原型和原型链

1.1 原型

  • js中,函数可以有属性,每个函数都有一个特殊的属性叫做原型prototype(原型)

1.2 原型链

  • 当我们访问某个对象的属性时,如果该对象本身没有,就会到对象的原型中去寻找定义,如果原型也没有,就再向原型对象的原型中寻找,依此类推,如果最顶层的对象也没有,则返回undefined,整个查找过程为链式,连接对象和对象的原型的链条就叫做原型链

1.3 原型链存在的意义

  • 可以使实例对象共享原型的属性和方法,节省代码量,减小内存的开销

2. 作用域

  • 代码在运行时某些特定部分中的变量,函数,对象,代表对上述资源的可访问性
  • 分类
    • 全局作用域
      • 在代码的任何地方都能访问到的变量,对象,函数
    • 局部作用域
      • 函数作用域
    • 块级作用域
      • {} 包裹起来的区域

2.1 作用域链

  • 在某一个地方访问一个变量,函数,或对象时,首先在当前作用域中查找,如果没有找到,则向父级的作用域中进行查找,以此类推,如果最终没有找到,则报undefined的错误,这种一层层嵌套的关系,就叫做作用域链

2.2 作用域存在的意义

  • 变量隔离,不同作用域下的同名变量互不干扰

3. 闭包

  • 能够访问其他函数内部变量的函数,称为闭包

  • 即一个函数在调用时,其内部找不到相应需要的变量或对象,需要在作用域链上寻找,找到后会维持对该变量的引用(一个函数和对其周围环境的引用捆版在一起)

  • 产生的问题

    • 维持对父级作用域变量的引用,会导致父级作用域中的变量常驻内存
  • 使用的场景

    • 防抖节流函数实现

    • 事件函数的封装

    • 循环注册事件函数:基本思想:如果循环变量i为全局变量,则循环注册最终事件处理函数引用的为同一个i

    • 闭包:每个循环都是一个立即执行函数,函数里面注册事件,这里的i(for循环的i->立即执行函数形参->事件处理函数的i引用形参)

      • 则事件处理函数与立即执行函数作用域的变量i的形成的闭包
    • 隐藏变量

      • 外层函数,类似java的类class,其中的局部变量==》java的private 变量

      • 提供一些修改局部变量的方法,return 回去(setPrivateLoacl,getPrivateLocal)(目的是为了外层函数外,即全局作用域中可以通过方法进行修改)

      • return不是必须的,之所以return 无非是为了提供一个操作私有数据的接口

      • 例如上一个循环注册事件,无需return

4. call,bind,apply 方法

  • 相同点:都可以改变this的指向
  • 不同点 :apply传递的第二个参数为数组(即如果有1个或多个参数,以数组的形式传递)
    • call 和 apply改变this指向同时也会调用函数,返回值为函数的调用
    • bind 返回的是改变this指向后的新函数

4.1 call的使用场景

  • 判断数据类型
    • Object.prototype.toString.call(this指向(调用者))
  • 类数组(伪数组,对象表示的数组)转数组
    • Array.prototype.slice.call(调用者)

4.2 apply的使用场景

  • 关键,传递的第二个参数为数组
  • 求最大值,最小值(Math.max(...array))
  • 使用apply,(Math.max.apply(null,array))

4.3 bind的使用场景

  • 改变this指向的同时不立即调用

  • 事件处理的回调函数,因为事件处理函数直接调用,相当于

    • function callback(){
          // 处理逻辑
      }
      
    • function里面的this为undefined

    • this.callback=this.callback.bind(this) ,绑定this

// * 判断数据类型
// * 类数组转数组

const array = [1, 2, 3, 4];

const type = array.toString()

console.log(array);

// const type = Object.prototype.toString.call(array);

console.log(`type`, type)

// const arrayLike = { 
//   0: "name",
//   1: "age",
//   2: "gender",
//   length: 3
// }

// const res =  Array.prototype.slice.call(arrayLike);
// console.log(`res`, res)
// // ["name","age","gender"]



// apply  对给定数组求最大值/最小值

// const array = [1,2,3,4,5];

// const max = Math.max.apply(null,array)
// const min = Math.min.apply(null,array)
// // Math.max(1,2,3,4,5)
// console.log(`max`, max)
// console.log(`min`, min)
// bind

// class App extends React.Component {
//   constructor(props) {
//     super(props);  
//     this.name = 'freemen'
//     this.handleClick = this.handleClick.bind(this)
//   }
//   handleClick(){
//     console.log(`this.name`, this.name)
//   }
//   render(){
//     return (
//       <button onClick={this.handleClick}>
//         点击
//       </button>
//     )
//   }
// }

5.数组去重

5.1 前置知识

  • 数组的indexOf()方法
    • 参数数组项,返回值,数组项的下标
  • filter方法
    • 返回值新数组
  • sort
    • 参数(a,b),return a-b 从小到大排,b-a 从大到小排
    • 返回值排序后的新数组
  • push
    • 参数:需要push进去的项
    • 返回值:数组push后的长度
    • 改变了原数组

5.2 filter +indexOf数组去重

array.filter((item,index)=>{
    return array.indexOf(item)===index
})
  • 原理
    • for循环一遍数组
    • 循环每一项时看该项是不是在之前出现过,即判断当前项的下标,与第一次出现相同项的下标是否相同

5.3 sort+移动零原理

// 先排序
array=array.sort()
let arr=[]
for(let i=0;i<array.length;i++){
    if(array[i]!==array[i-1]){
        arr.push(array[i])
    }
}
  • 原理
    • 对原数组进行排序,从小到大
    • 则相同的元素会成组出现,如111222333
    • 我们需要从中获取到我们需要的部分
      • 即每组的分界点的元素
        • undefined和1
        • 1和2
        • 2和3

5.4 Set + 解构赋值

[...newSet(array)]
  • Set不允许出现重复元素

5.5 set+Array.from

Array.from(new Set(array))

对象数组去重(根据某个key)

  • 临时对象缓存key值实现
    • 存储key值
    • 没有则存储一个新的key值
    • 有则直接过滤掉
const array=[{name:'666',age:20},{name:'999',age:20}]
// 去除age相同的
let template={}

let result=[]

for(let i=0;i<array.length;i++){
    if(template[array[i]['age']]){
        continue;
    }
    
    template[array[i]['age']]=true;
    result.push(array[i])
}
  • reduce函数实现
const array=[{name:'666',age:20},{name:'999',age:20}]
// 去除age相同的
let template={}

array.reduce((prev,curr)=>{
    if(!template[curr['age']]){
        template[curr['age']]=true
        prev.push(curr)
    }
    
    return prev;
},[])
  • prev最初为[] 数组

6.数组最大值

  • Math.max()
    • Math.max(...array)
    • Math.max.apply(array)
  • Array.reduce()
    • array.reduce((prev,curr)=>{
      • return curr>prev? curr:prev
    • })
  • sort+lastIndexOf()
    • 排序后找最后一个

7.节流

  • 单位事件内触发多次事件,第一次有效
  • 场景
    • 轮播图单位事件内多次被点击
    • movemouse事件,获取鼠标的位置,控制鼠标样式图标跟随移动
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        // 实现节流函数

        function throttle(fn, timeOut) {

            // 定义一个timer
            let timer = null



            // 返回一个函数调用,注意,这里形成的闭包
            return (event) => {
                if (timer) {
                    return
                }
                timer = setTimeout(function() {
                    // 计时结束后的逻辑
                    clearTimeout(timer)
                    timer = null
                    fn(event)
                }, timeOut)
            }
        }

        // 监听窗口resize事件

        window.onresize = throttle((event) => {
            console.log(event);
        }, 1000)
    </script>
</body>

</html>

8.防抖

  • n秒内多次触发同一事件,最后一次有效
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input type="text" id="q">

    <script>
        // 实现防抖
        const debounce = (fn, timeOut) => {

            let timer = null;

            return () => {

                // 每次触发,都会进入这里
                // 清除原先的定时器,当不进入时,最后一个就生效了
                clearTimeout(timer)

                timer = null

                // 形成了闭包
                timer = setTimeout(function() {

                    // 指向搜索的逻辑
                    fn()

                }, timeOut)
            }
        }

        const search = document.getElementById('q')

        search.oninput = debounce(() => {
            console.log('saerch');
        }, 1000)
    </script>
</body>

</html>

9.数组拍平

  • 数组降维

  • 实现方法

    • reduce函数
    • es6的flat函数
    • while循环+Array

9.1 reduce

  • 原理:递归调用
// reduce函数

// function flatter(array) {
//     return array.reduce(function(prev, current) {
//         return prev.concat(Array.isArray(current) ? flatter(current) : current)
//     }, [])
// }

9.2 flat函数

  • Infinity为数组的维数,Infinity为最大值
array.flat(Infinity)

9.3 while循环+展开运算符

  • 每次循环,判断当前数组是否存在数组元素
  • 有就展开,然后再合并
while(array.some(Array.isArray)){
    array=[].concat(...array)
}

10.实现new操作符

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>

        // 构造函数
        const TMap = function (options) {
            this.name = options.name;
            this.address = options.address;
        }

        // const map  = new TMap({
        //   name: 'tmap',
        //   address:"BJ"
        // });

        // console.log('map :>> ', map);

        //1. 实例化对象  2.返回值的问题: 构造函数中如果有值返回 那实例化后的对象就是这个返回值。

        const ObjectFactory = (...args) => {
            const obj = {};
            // [].shift.call 等价于 Array.prototype.shift.call
            // 因为args为伪数组
            const Constructor = [].shift.call(args)
            // 实例对象的原型链和构造函数的原型指向相同
            obj.__proto__ = Constructor.prototype;

            // obj.Constructor(args) Constructor==>Tmap 
            // this.name = options.name; ==>obj.name==args.name
            // this.address = options.address; ==>obj.address=args.address

            // 这里函数并无返回值,即Tmap没有写返回值,如果写了,返回的就不是obj这个对象了
            const ret = Constructor.apply(obj, args);

            console.log('ret', ret, obj);
            return typeof ret === 'object' ? ret : obj;
        }

        const map = ObjectFactory(TMap, {
            name: "MAP",
            address: "BJ"
        });

        console.log('map :>> ', map);
    </script>
</body>

</html>

11. 实现一个bind函数

function origin(a, b) {
    console.log(this.name);
    console.log([a, b]);
}

const obj = {
    name: "freemen"
}

// const func = origin.bind(obj,2);
// func(1)

Function.prototype.bindFn = function() {
    // 1 获取源函数
    // this为函数的调用者,即origin()函数
    const fn = this;
    // 2 获取目标对象
    // 获取第一个参数,即需要修改到的this指向
    // const func = origin.bind(obj,2);
    const obj = arguments[0];
    // 3. 获取源函数参数列表
    const args = [].slice.call(arguments, 1)
        // 4. 返回函数
    return function() {
        // 5 获取返回函数的参数列表
        // func(1)
        // 即返回的新函数(this指向已经修改)在调用时传递的参数
        const returnArgs = [].slice.call(arguments);
        // 6 执行源函数
        fn.apply(obj, args.concat(returnArgs));
    }
}

12. apply 和 call函数的实现

  • 原理,都是在目标对象obj(修改后this指向)中将调用的(需要修改指向)方法加入obj中
    • obj的调用作为返回结果

const obj = {
  name: "freemen"
}

function testFunc(a,b){
  console.log('a :>> ', a);
  console.log('b :>> ', b);
  console.log('this.name :>> ', this.name);
}

// testFunc.call(obj,'a','b')

// testFunc.apply(obj,['a','b'])

const core = (context,args,_this) => {
  args = args || [];
  const key = Symbol();
  context[key] = _this;
  /* 
    obj={
      key:testFunc
    }

    obj.key(args)
    // 调用者是不是变成了obj this指向改变
  */

  const result = context[key](...args)
  delete context[key]
  return result; 
}

Function.prototype.callFn = function(context,...args){
  // context 为this指向,obj对象
  // this为方法的调用者 即testFunc
  return core(context,args,this);
}

Function.prototype.applyFn = function(context,args){
  return core(context,args,this);
}

testFunc.callFn(obj,'a','b');
testFunc.applyFn(obj,['a','b']);
// 

13. instanseof 运算符

  • 用于检测构造函数的prototype属性是否出现在实例对象的原型链上
  • 实现原理
    • 实例对象的原型链 __ proto __
    • 构造函数的prototype显示原型
    • 判断对象的 __ proto __ === prototype,找到返回,找不到,对象的原型链上移
function Persion(){
  this.name = "freemen"
}

const obj = new Persion

// console.log(obj instanceof Persion)

// instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
function instance_of(Obj, Constructor){
  let implicitPrototype = Obj.__proto__;  // 获取实例对象的隐式原型
  let displayPrototype = Constructor.prototype; // 获取构造函数的prototype 属性
  // while 循环 -> 在原型链上不断向上查找
  while(true){
      // 直到 implicitPrototype = null 都没找到, 返回false
      if(implicitPrototype === null){
        return false
        // 构造函数的 prototype 属性出现在实例对象的原型链上 返回 true
      }else if (implicitPrototype === displayPrototype){
        return true
      }
      // 在原型链上不断查找 构造函数的显式原型
      implicitPrototype = implicitPrototype.__proto__
  }
}

const has = instance_of(obj,Persion)

console.log(`has`, has)

标签:obj,函数,javascript,return,const,array,cnblog,name
From: https://www.cnblogs.com/lingxin1123/p/17092943.html

相关文章

  • css基础-cnblog
    1.盒模型定义css规范的一个模块定义一个长方形的盒子包含内外边距,边框标准定义上分分类IE盒模型width=width+padding+borderheight=height+padding+bord......
  • 浏览器-cnblog
    事件流捕获目标冒泡回流和重绘减少回流和重绘的次数css样式一次性修改constroot=document.getElementById('root')root.style.cssText='padding:10px2......
  • 设计模式-cnblog
    设计模式1.装饰者模式不改变对象自身代码的基础上新增功能//装饰者模式//不改变对象自身代码的基础上新增功能leta=()=>{console.log('a');}//开闭......
  • webpack-cnblog
    1.webpack定义用于现代JavaScript的静态模块打包工具解决的问题模块依赖代码编写less转cssts转js开发效率热加载项目优化压缩,打包2.load......
  • 打包JavaScript的代码 (ES67891011 转为 ES5)
    NodeJS安装必要的工具包#初始化项目npminit-yes##安装babelbrowserify等包npmibabel-clibabel-preset-envbrowserify-D使用##babel转换指定文件夹下的代......
  • JavaScript学习笔记—DOM:通过属性读取样式
    读取的样式都是只读,无法修改获取元素内部的宽度和高度(包括内容区和内边距)element.clientHeightelement.clientWidth获取元素的可见框的大小(包括内容区、内边距和边框)......
  • 【JavaScript】2_数据类型
    1、数值数值(Number)在JS中所有的整数和浮点数都是Number类型JS中的数值并不是无限大的,当数值超过一定范围后会显示近似值Infinity是一个特殊的数值表示无穷所以在JS中进行......
  • 修改表时先删除后添加思想-cnblog
    4.3.2修改菜品信息4.3.2.1代码实现点击保存按钮,页面发送ajax请求,将修改后的菜品相关数据以json形式提交到服务端。在修改菜品信息时需要注意,除了要更新dish菜品表,还需......
  • 线程变量-cnblog
    1.3.2ThreadLocalThreadLocal并不是一个Thread,而是Thread的局部变量。当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程......
  • spring-data-redis-cnblog
    5.3SpringDataRedis5.3.1介绍SpringDataRedis是Spring的一部分,提供了在Spring应用中通过简单的配置就可以访问Redis服务,对Redis底层开发包进行了高度封装......