call/apply/bind

call是接收一个数组 apply是接受一串参数 bind返回一个函数,绑定到对象上,接受一串参数

核心

  • 方法绑定到Function.prototype上三者都是截取对象的方法作为参数绑定到对象上,所以在Function的prototype上所有对象都能访问。

  • this是要截取绑定的对象,(函数/方法也是一种对象)这里三个例子是Array的splice方法

  • 不能直接用this(…args)方式调用需要赋值给调用对象的属性,因为要绑定到对象上
  • 用完之后要删除fn,否则会在对象上新增一个fn属性

实现

  1. 绑定到Function.prototype原型对象上要实现的方法
  2. 要绑定的对象中加入截取的方法(实现绑定)
  3. 执行完成后删除刚刚绑定的属性(截取的方法)

    实现call,myCall

    ```javascript

/**

  • 函数原型上加上、
  • this —- 原生call截取的函数 这里是调用myCall的那个对象(函数也是一种对象)(函数,Array.prototype.splice.myCall)
  • @param {*} context 作用于的对象,不传递则作用在window上
  • @param {…any} args 其他参数 */ Function.prototype.myCall = function (context = window, …args) { context.fn = this; const result = context.fn(…args); // delete context.fn; return result; }

// 测试

const arr = [1, 2, 3, 4, 5, 6] const res = Array.prototype.slice.myCall(arr, 2) console.log(res) console.log(arr) // 如果不delete context.fn,则数组中将带一个fn函数

  1. ![image.png](https://cdn.nlark.com/yuque/0/2020/png/432716/1599794584008-e496c2ce-c96d-41ca-90f5-deb973173e37.png#align=left&display=inline&height=304&margin=%5Bobject%20Object%5D&name=image.png&originHeight=373&originWidth=814&size=31039&status=done&style=stroke&width=664)
  2. <a name="X2azD"></a>
  3. ### 实现apply myApply
  4. ```javascript
  5. /**
  6. * apply截取对象的方法,第二个为一堆参数
  7. *
  8. * 函数原型上加上
  9. *
  10. * this --- 原生call截取的函数 这里是调用myApply 的那个对象(函数也是一种对象)(函数,Array.prototype.splice.myApply )
  11. * @param {*} context 作用于的对象,不传递则作用在window上
  12. * @param {...any} args 其他参数
  13. */
  14. Function.prototype.myApply = function (context = window, ...args) {
  15. context.fn = this;
  16. let result;
  17. if (args.length === 0) {
  18. result = context.fn();
  19. } else {
  20. result = context.fn(...args);
  21. }
  22. delete context.fn;
  23. return result;
  24. }
  25. // 测试
  26. const arr = [1, 2, 3, 4, 5, 6]
  27. // 从0的位置删除1个添加7、8、9三个元素
  28. const res = Array.prototype.splice.myApply(arr)
  29. console.log(res, arr)
  30. // console.log(arr) // 如果不delete context.fn,则数组中将带一个fn函数

实现bind myBind

  1. /**
  2. * bind截取对象的方法,第二个为一堆参数
  3. *
  4. * 函数原型上加上
  5. *
  6. */
  7. Function.prototype.myBind = function () {
  8. if (typeof this !== 'function') throw new TypeError('not a function')
  9. // 将参数拆解为数组(arguments伪数组)
  10. let args = Array.prototype.slice.call(arguments);
  11. // 获取方法要要绑定到的对象(数组第一项)
  12. let _this = args.shift();
  13. // 获取原要绑定到对象上的函数
  14. let self = this;
  15. // 返回一个函数
  16. return function () {
  17. return self.apply(_this, args);
  18. }
  19. }
  20. // 测试
  21. const arr = [1, 2, 3, 4, 5, 6]
  22. // 从1的位置删除1个添加222一个元素
  23. const res = Array.prototype.splice.myBind(arr, 1, 1, 222)()
  24. console.log(res, arr)
  25. // console.log(arr) // 如果不delete context.fn,则数组中将带一个fn函数

instanceof

instanceof的用法
判断一个对象是否是一个类(构造函数)的实例
image.png
核心

  • 一个对象构造函数的prototype和这个对象的proto是一个对象
    • prototype是函数上才有的属性
    • proto是对象上的属性

实现

  1. 拿到构造函数的prototyoe,循环向上找要查询对象的proto,如果对象是构造函数的一个实例则一定会找到相同的原型对象

    循环

    ```javascript /**
    • @param {*} L instanceof 左边的参数
    • @param {} R instanceof 右边的参数 / function myInstanceOf(L, R) { // 拿到目标显式(非隐式)原型 let O = R.prototype; L = L.proto; while (true) { if (L === null || L === undefined) {
         return false;
      
      } if (O === L) {
         return true;
      
      } // 找L对象的原型 L = L.proto; } }

const a = [1, 2, 3, 4, 5, 6, 7] console.log(a instanceof Array) console.log(myInstanceOf(a, Array))

<a name="9mSfN"></a>
### 递归
```javascript
/**
 * 
 * @param {*} L instanceof 左边的参数 
 * @param {*} R instanceof 右边的参数
 */
function myInstanceOfWithRecu(L, R) {
    // 拿到目标显式(非隐式)原型
    let O = R.prototype;
    L = L.__proto__;
    if (L === null || L === undefined) {
        return false;
    }
    if (O === L) {
        return true;
    }
    // 递归找L对象的原型
    return myInstanceOf(L.__proto__, R)
}


const a = [1, 2, 3, 4, 5, 6, 7]
console.log(a instanceof Array)
console.log(myInstanceOf(a, Array))

Object.create

Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的proto
实现

  1. 创建一个函数
  2. 函数prototype指向要继承的对象
  3. 用这个函数创建一个实例 ```javascript /**
    • @param {} proto 要继承的原型 / function myCreate(proto) { function F() { }; F.prototype = proto; return new F(); }

const person = { isHuman: false, printIntroduction: function () { console.log(My name is ${this.name}. Am I human? ${this.isHuman}); } };

const me = myCreate(person);

me.name = ‘Matthew’; // “name” is a property set on “me”, but not on “person” me.isHuman = true; // inherited properties can be overwritten me.printIntroduction(); // expected output: “My name is Matthew. Am I human? true” console.log(person, me)

![image.png](https://cdn.nlark.com/yuque/0/2020/png/432716/1599808827224-ee440e80-6854-4633-b4ab-707343693698.png#align=left&display=inline&height=204&margin=%5Bobject%20Object%5D&name=image.png&originHeight=204&originWidth=581&size=14681&status=done&style=stroke&width=581)<br />MDN<br />[https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/create)

<a name="JBTgd"></a>
## map/filter/reduce
> 三个有代表性的迭代函数
> map react中遍历元素常用的
> filter 过滤后的值
> reduce 累加

<a name="Nv0o4"></a>
### map
**参数**<br />`[].map((item, index, arr)=>{})`<br />map是有返回值的,把数组迭代,每一个元素都应用传递进入的方法,生成一个新的数组<br />**核心**

- this是调用myMap的对象(数组也是一种对象)
- 新开辟一个数组res用于存放结果,遍历要处理的数组,把每一个元素应用传递进来的方法,把值push到这个开辟的res中,返回这个res
```javascript

/**
 * 
 * this --- 调用myMap方法的对象
 * @param {*} cb map方法接收的一个参数
 */
Array.prototype.myMap = function (cb) {
    if (typeof cb !== 'function') {
        return [];
    }
    const res = [];
    const arr = this
    for (let i = 0; i < arr.length; i++) {
        res.push(cb(arr[i], i, arr));
    }
    return res;
}


// const a = [1, 2, 3, 4, 5, 6, 7]
// const res = a.map(x => x * 2)
// console.log(a, res)

const a = [1, 2, 3, 4, 5, 6, 7]
const res = a.myMap(x => x * 2)
console.log(a, res)

filter

[].filter((item, index, arr)=>{})
返回一个满足条件的新数组
核心

  • 开辟一个数组res,遍历要处理的数组,把每一个元素应用传递进来的方法,把符合条件的元素push到这个开辟的res中,返回这个res ```javascript /**

    • this —- 调用myFilter方法的对象
    • @param {} cb filter方法接收的一个参数 / Array.prototype.myFilter = function (cb) { if (typeof cb !== ‘function’) {

      return [];
      

      } const res = []; const arr = [] for (let i = 0; i < this.length; i++) {

      // 满足条件的push到数组中
      if (cb(arr[i], i, arr)) {
          res.push(arr[i]);
      }
      

      }

      return res; }

// const a = [1, 2, 3, 4, 5, 6, 7] // const res = a.filter(x => x > 2) // console.log(a, res)

const a = [1, 2, 3, 4, 5, 6, 7] const res = a.myFilter(x => x > 2) console.log(a, res)

<a name="PKOC0"></a>
### reduce
`arr.reduce((acc, cur, index, arr) => {}, initValue)`

- acc 累加值
- cur 当前值
- index 当前索引
- arr 原数组

返回值:累加值 acc
```javascript
/**
 * 
 * this --- 调用myMap方法的对象
 * @param {*} cb reduce方法接收的第一个参数
 * @param {*} initValue reduce方法接收的第二个参数初始值
 */
Array.prototype.myReduce = function (cb, initValue) {
    // 如果调用的是null或undefined
    if (this === null) {
        throw new TypeError('Array.prototype.reduce called on null or undefined');
    }

    // 如果回调函数不是函数
    if (typeof cb !== 'function') {
        throw new TypeError(cb + ' is not a function');
    }

    // 如果调用的不是数组
    if (!Array.isArray(this)) {
        throw new TypeError("not a array");
    }

    // 数组为空,并且没有初始值
    if (this.length === 0 && arguments.length < 2) {
        throw new TypeError('Reduce of empty array with no initial value');
    }

    const arr = this;
    let res = null; // 要累加的值
    // 判断有没有初始值
    if (arguments.length > 1) {
        res = initValue;
    } else {
        res = arr.splice(0, 1)[0]; //没有就取第一个值
    }
    arr.forEach((item, index) => {
        res = cb(res, item, index, arr); // cb 每次执行完都会返回一个新的 res值,覆盖之前的 res
    })

    return res;
}

// const a = [1, 2, 3, 4, 5, 6, 7]
// const res = a.reduce((acc, cur) => acc + cur, 10000)
// console.log(a, res)

const a = [1, 2, 3, 4, 5, 6, 7]
const res = a.myReduce((acc, cur) => acc + cur, 10000)
console.log(a, res)