深拷贝,原型关系,this,bind函数,闭包

值类型和引用类型

值类型

  • 占用空间小
  • 有string、number、boolean、undefine以及es6的symbol
    值类型

引用类型

  • 占用空间大
  • 有Object、Array以及特殊引用类型null(特殊引用类型,不用于存储数据function)
  • 引用类型使用堆,key指向堆得内存地址
    引用类型

typeof判断类型

  • 所有值类型:string、number、boolean、undefine、symbol
  • 引用类型将array、object、null都归于object一类,能判断function
const fn = function () {}
const fnType = typeof fn   // function

instanceof判断类型

只能用来判断对象、函数和数组,不能用来判断字符串和数字
instanceof只能检测引用类型的,不能检测基本数据类型

a = {}  c = []   d = 'abc'  e = 123              
b = function() {} 

a instanceof Object     // true
b instanceof Object     // true
b instanceof Function   // true
c instanceof Array     // true
d instanceof String     // false
e instanceof Number     // false
null instanceof Object  // false

深拷贝代码

function deepClone( obj = {} ) {
  if (typeof obj !== 'object' || obj == null) {
    // obj是null,或者不是对象或数组,直接返回
    return obj
  }
  
  // 初始化返回结果
  let result
  if (obj instanceof Array) {
    result = []
  } else {
    result = {}
  }

  for (let key in obj) {
    if(obj.hasOwnProperty(key)) {
      // 递归调用
      result[key] = deepClone(obj[key])
    }
  }
  
  // 返回结果
  return result
}

运算符

==运算符

100 = '100' // true
0 = '' // true
0 = false // true
false = '' // true
null = undefined // true

以下是falsely变量,除此之外都是truly变量

!! 0 === false
!! NaN === false
!! '' === false
!! null === false
!! undefined === false
!! false === false

原型相关

// 通过类new 对象/实例
class Student {
  constructor(name, number) {
    this.name = name
    this.number = number
  }

  sayHi() {
    console.log(`姓名${this.name},学号${this.number}`)
  }
}

const xiaLuo = new Student('夏洛', 12)

// 父类
class People{
  contractor(name) {
    this.name = name
  }
  eat() {
    console.log(`${this.name}`)
  }
}

// 子类
class Student extends People {
  contractor(name,number) {
    super(name) // 调用父类的contractor(name)
    this.number = number
  }
  sayHi() {
    console.log(`姓名${this.name},学号${this.number}`)
  }
}
  • es6要求,子类构造函数必须执行一次super函数,否则在新建实例时会报错。
  • 如果不加super方法,子类就得不到this对象
  • 在子类的构造函数中,只有调用了super方法之后,才可以使用this关键字。这是因为子类实例的构建是基于对父类实例的加工,只有super方法才能返回父类的实例

原型关系

  • 每个class都有显示原型prototype
  • 每个实例都有隐式原型__proto__
  • 实例的__proto__指向对应class的prototype

原型的执行规则

  • 现在自身的属性和方法寻找
  • 如果找不到则自动去__proto__中查找
    原型
    原型链
    原型链

构造函数、实例、原型对象三者之间的关系

Star.prototype = {
    constructor: Star,
    sing: function() {
        console.log('我会唱歌')
    }
    movie: function() {
        console.log('我会看电影')
    }
}
const ldh = new Star()
  • 只要是对象就__proto__原型,指向原型对象
  • Star原型对象里面的__proto__原型指向的就是Object.prototype
  • Object.prototype原型对象里面的__proto__原型,指向为null
    在这里插入图片描述
    在这里插入图片描述

原型对象指向问题

  • 在构造函数中,里面的this指向的是对象实例 ldh
  • 原型对象里面的this指向的是实例对象ldh (函数的调用者)

手写jquery

class jQuery  {
  contractor(selector) {
    const result = document.querySelectorAll(selector) 
    const length = result.length
    for(let i = 0; i < length; i++) {
      this[i] = result[i] 
    }
    this.length = length
  }
  get(index) {
    return this[index]
  }
  each(fn) {
    for (let i = 0; i < length; i++) {
      const elem = this[i]
      fn(elem)
    }
  }
  on(type, fn) {
    return this.each(elem => {
      elem.addEventListener(type, fn, false)
    })
  }
}

const $p = new jQuery('p')
$p.get(1)
$p.each((elem) => console.log(elem.nodeName))
$p.on('click', ()=> alert('clicked'))
}

class myJquery extends jQuery {
  contractor(selector) {
    super(selector)
  }
  // 扩展自己的方法
  addClassName(className) {}
}

作用域

this

  • 作为普通函数
  • 使用call apply bind
  • 作为对象方法被调用
  • 在class方法中调用
  • 箭头函数

this不同引用场景如何取值

// this取值是在函数的时候定义的,不是在函数定义的时候确认的
// bind返回一个函数,需要重新执行函数
function fn1() {
  console.log(this)
}
fn1() // window

fn1.call({x: 100}) // {x: 100}

const fn2 = fn1.bind({x: 200})
fn2() // {x: 200}

箭头函数取得是上级作用域的this
this

call/apply/bind

相同点:三个函数都会改变this的指向
不同点:

  • bind会产生新函数
  • call和apply不会产生新函数,只是在调用的时候绑定一下
  • call和apply的区别,第一个参数都是表示要改变指向的那个对象,apply第二个参数是数组,call是将参数列举出来

手写bind函数

Bind函数创建一个新的函数,在bind被调用时,这个新函数的this被指定为bind的第一个参数,而其余参数将作为新函数的参数,供调用时使用

Function.prototype.bind1 = function() {
  // 将参数拆解为数组 Arguments可以获取所有的参数 
  const args = Array.prototype.slice.call(arguments) 
  const t = args.shift() // 获取this(数组第一项) 
  const self = this  // fn1.bind(...)中的fn1 
  return function() { // 返回一个函数
    return self.apply(t, args)
  }
}

chatGTP

if (!Function.prototype.myBind) {
    Function.prototype.myBind = function (context, ...argsPrepend) {
        const self = this; // 保存原函数引用
        let args = [...argsPrepend]; // 保存预置参数

        // 返回一个新的函数,该函数在调用时会设置正确的上下文并传递预置参数
        return function (...argsAppend) {
            // 构建最终调用原函数时的参数列表,预置参数在前,调用时传入的参数在后
            const allArgs = [...args, ...argsAppend];

            // 确保在严格模式下也能正确设置this
            const fnContext = Object(self);
            const boundFn = function () {
                return self.apply(this instanceof boundFn ? this : context, allArgs);
            };

            // 继承原函数的原型
            if (typeof self.prototype !== 'undefined') {
                boundFn.prototype = Object.create(self.prototype);
            }

            return boundFn;
        };
    };
}

// 示例使用
function MyClass() {
    this.name = 'Original Class';
}

MyClass.prototype.sayHello = function (firstName, lastName) {
    console.log(`Hello ${firstName} ${lastName}, I'm ${this.name}`);
};

const obj = { name: 'Bound Object' };
const boundSayHello = MyClass.prototype.sayHello.myBind(obj, 'John');
boundSayHello('Doe'); // 输出 "Hello John Doe, I'm Bound Object"

异步

  • 异步解决单线程等待问题
  • 异步应用场景:网络请求,定时任务

闭包

闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。

// 闭包隐藏数据,只提供api
function createCache() {
  const data = {}
  return {
    set: function(key, val) {
      data[key] = val
    }
    get: function(key) {
      return daka[key]
    }
  }
}

const c = createCache()
c.set('a', 100)
console.log(c.get('a')) // 100

闭包:自由变量的查找,是在函数定义的地方向上级作用域查找,不是在执行的地方

function print(fn) {
  const a =200
  fn()
}
const a = 100
function fn() {
  console.log(a)
}
print(fn) // 100
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值