call(),apply(),bind()

call

1调用函数

2改变函数内的this指向

3实现继承: 构造函数+ 原型对象--组合继承

var obj = {
    uname: 'lili'
}
function fn(a, b) {
  console.log(a + b);
  console.log(this);
}
fn.call(); // 1调用函数
fn.call(obj, 1, 2); // 改变this指向



function Father(uname,age) {
    this.uname = uname;
    this.age = age;
}
Father.prototype.money = function() {
    console.log(this);
}

function Son(uname, age, sex) {
    Father.call(this, uname, age); // 3 实现继承
    this.sex = sex;;
}

// Father的实例对象中有__proto_ ,指向Father的原型对象prototype,Father的prototype中就有Father的方法
Son.prototype = new Father(); 
// 如果利用实例对象的形式修改了原型对象,要把constructor 指回构造函数
Son.prototype.constructor = Son;
Son.prototype.exam = function() {
    console.log('孩子的方法');
}

 

apply - 第二个参数要传数组

1调用函数

2改变函数内的this指向

3 利用apply借助于数学内置对象求最大值

var obj = {
    uname: 'lili'
}
function fn(arr) {
  console.log(arr);
  console.log(this);
}
fn.apply(); // 1调用函数
fn.apply(obj, [1, 2]); // 改变this指向



var arr = [3,66,8,77,9];
// var max = Math.max.apply(null, arr);
var max = Math.max.apply(Math, arr);
var min = Math.min.apply(Math, arr);

补充点相关点

Math.max()函数返回一组数中的最大值。

console.log(Math.max(1, 3, 2));  // 3

es6写法

剩余运算符...:把多个独立的合并到一个数组

拓展运算符...:把一个数组分割,传给函数

const arr = [1,3,2];
console.log(Math.max(...arr)); 

 

 

bind

1不会调用原来的函数,只改变函数内部this指向

2返回原函数改变this指向后的新函数

3如果有的函数不需要立即调用,但又需要改变this指向  --定时器里的函数

var obj = {
    uname: 'lili'
}
function fn(a, b) {
  console.log(a + b);
  console.log(this);
}
var f = fn.bind(obj, 1, 2); // 不调用函数,只改变this指向
f(); // 再去调用新函数


// 如果有的函数不需要立即调用,但又需要改变this指向
var btn = document.querySelector('button');
btn.onclick = function() {
    this.disabled = true;
    setTimeout(function() { // 定时器里的函数this指向window
       this.disabled = false;
    }.bind(this), 3000) // 这个this是btn
}

 

 

js call,apply方法实现原理

Function.prototype.myCall = function () {
      let [targetObj, ...arg] = [...arguments]
      /* 重点 用传递过来的对象 添加一个属性赋值为this */
      targetObj.fn = this; // 对象的隐式调用,就是在A.call(B)的时候,在call函数内部的this是指向A的
      let result = targetObj.fn(...arg)
      delete targetObj.fn // 在targetObj中是没有这个属性的所有要删除这个属性
      return result;
    }

    var obj = { name: 'ooo' }
    function sayHi(e) {
      console.log(this);
    }

sayHi.myCall(obj, 1, 2, 3);

apply与call的实现原理相同,就是传参的方式略微不同。传的是一个数组。

Function.prototype.myApply = function () {
      let [targetObj, ...arr] = [...arguments]
      targetObj.fn = this;
      let result = targetObj.fn(...arr);
      delete targetObj.fn;
      return result;
    }

    var obj = { name: 'ooo' }
    function sayHi(e) {
      console.log(this);
    }

sayHi.myApply(obj, [
1, 2, 3]);

 

js bind方法实现原理

Function.prototype.bind_ = function (obj) {
    //第0位是this,所以得从第一位开始裁剪
    var args = Array.prototype.slice.call(arguments, 1);
    var fn = this;
    return function () {
        //二次调用我们也抓取arguments对象
        var params = Array.prototype.slice.call(arguments);
        //注意concat的顺序
        fn.apply(obj, args.concat(params));
    };
};

var obj = {
    z: 1
};

function fn(x, y) {
    console.log(x + y + this.z);
};

var bound = fn.bind_(obj, 1);
bound(2); //4

 

Array.prototype.slice.call()

JavaScript中的Array.prototype.slice.call(arguments)能将有length属性的对象转换为数组

特别注意: 这个对象一定要有length属性

 

let args = [].slice.call(arguments);意思是将 arguments 数组化。
arguments 是一个类数组的结构,它并不是一个真的数组,所以没法使用数组的方法。

 

posted @ 2021-09-22 21:35  litiyi  阅读(25)  评论(0编辑  收藏  举报