小哥带来的学习

1、写一个方法:不定参数求和

前言:

1、类数组对象: 在javascript中,数组是一个特殊的对象,其property名为正数组,且其length属性会随着数组成员的增减而发生变化,同时又从arry构造函数中继承一些用于进行数组操作的方法,而对于一个普通的对象来说,如果它的所有property名均为正整数,同事也有相应的length属性,那么虽然该对象并不是由Array构造函数所创建的,它依然呈现出数组的行为,在这种情况下,这些对象被称为"类数组对象"
2、Array.from()对一个类似数组或可迭代对象创建一个新的,浅拷贝的数组实例。

function Sum() {
    // 1、获取参数个数---arguments(类数组对象)
    // 2、类数组对象转化为数组
    //      [...arguments]
    //      Array.from(arguments)
    // 3、数组求和
    //  return eval(Array.from(arguments).join("+"));
        return [...arguments].reduce((pre,cur) => {
            return pre + cur
        })
} 
console.log(Sum(1,2,3,4));//10

//arguments

image.png

2、创建一个长度为100的数组

  • length=100
image.png
  • new Array()
image.png
  • Array.from()

image.png

注:上面两种拿到的数组,都是empty,没有实际的使用效果; 使用Object.keys()可以拿到数组的index去生成数组

3、手写一个 new

function selfNew(param){
    if(typeof param !== 'function') return '要是一个function';
    
    selfNew.target = param;

    let newObj = Object.create(param.prototype);
    console.log(newObj,'newObjnewObjnewObj');


    let arr = [...arguments].slice(1,arguments.length)
    console.log(arr, 'arr');

    let paramResult =  param.apply(newObj, arr);
    console.log(paramResult,'paramResultparamResultparamResultparamResult');

    var isObject = typeof paramResult === 'object' && paramResult !== null;
    var isFunction = typeof paramResult === 'function';
     if(isObject || isFunction){
        return paramResult;
    }
    return newObj;
}
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    newOperator.target = ctor;

    var newObj = Object.create(ctor.prototype);

    console.log(newObj,'newObj-newOperator');



    var argsArr = [].slice.call(arguments, 1);
    console.log(argsArr,'argsArr-newOperator');

    // 重置new.target
    newOperator.target = null;

    var ctorReturnResult = ctor.apply(newObj, argsArr);
    console.log(ctorReturnResult,'ctorReturnResult-newOperator');

    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    return newObj;
}
function Student(name, age) {
    this.name = name;
    this.age = age;
}
Student.prototype.doSth = function() {
    console.log(`我是${this.name}`);
};

newStudent = new Student('new',18);
myStudent = selfNew(Student, 'selfNew',18);
operatorStudent = newOperator(Student, 'newOperator',18);

console.log(newStudent,newStudent.doSth(),'newStudent');

console.log(myStudent,myStudent.doSth(),'myStudent');

console.log(operatorStudent,operatorStudent.doSth(),'operatorStudent');
//newOperator方法来自于 https://juejin.cn/post/6844903704663949325

对target进行拦截处理,以防构造函数中含有构造函数,target的指向会有问题

 const newOperator = (function () {
      const _newStack = [];
      function newOperator(ctor) {
        // 设定new.target
        newOperator.target = ctor;
        // 生成新的对象,其隐式原型指向构造函数的原型对象
        const obj = Object.create(ctor.prototype);
        // 执行构造函数,并返回结果
        const result = ctor.apply(
          obj,
          Array.prototype.slice.call(arguments, 1)
        );

        // 重置new.target
        newOperator.target = null;
        // 判断最终返回对象
        return (typeof result === "object" && result !== null) ||
          typeof result === "function"
          ? result
          : obj;
      }
      // 设定target的get、set方法
      Reflect.defineProperty(newOperator, "target", {
        get() {
          return _newStack[_newStack.length - 1];
        },
        set(target) {
          if (target == null) {
            _newStack.pop();
          } else {
            _newStack.push(target);
          }
        },
      });
      return newOperator;
    })();
    function B() {
      if (newOperator.target === B) {
        console.log("new调用 B");
      } else {
        console.log("非new调用 B");
      }
      return { balabala: 123 };
    }

    function A() {
      const b = newOperator(B);
      if (newOperator.target === A) {
        console.log("new调用 A");
      } else {
        console.log("非new调用 A");
      }
    }
//此优化为 https://juejin.cn/post/6844903704663949325 网友的评论

4.手写call、apply、bind

  • call(参数用逗号隔开,不需要自调用)
Function.prototype.myCall = function(context, ...args) {
    // 此时this指的是当前调用myCall的函数
    if(typeof this !== 'function') return "It's must be a function"

    // 绑定的对象是否存在,不存在 this指向window
    if(!context) context = window;

    // 创建一个唯一的fn作为绑定对象的属性
    const fn = Symbol()

    // 把this指向fn
    context[fn] = this;

    // 用其他的参数,调用fn拿到返回值
    const result = context[fn](...args)
    // 清除对象上的fn属性
    delete context[fn]
    
    return result

}
let ceshi = function(name, age, className) {
    this.name = name,
    this.age = age,
    this.className = className
}
let obj = {
    name: 'xiaohua',
    age: 18
}
let school = {
    className: 2,
    age: 18
}
ceshi.myCall(obj, '小花','2',6);
ceshi.myCall(school, '3', 12,5);
console.log(obj, school);
image.png
  • apply(参数为数组,不需要自调用)
Function.prototype.myApply = function (context, args) {
     // 此时this指的是当前调用myCall的函数
     if(typeof this !== 'function') throw "It's must be a function"

     // 绑定的对象是否存在,不存在 this指向window
     if(!context) context = window;
 
     // 创建一个唯一的fn作为绑定对象的属性
     const fn = Symbol()
 
     // 把this指向fn
     context[fn] = this;
    // 参数: 数组 || 类数组
    if (typeof args !== 'object' || !args.length ) throw console.error('参数类型错误');
     // 用其他的参数,调用fn拿到返回值 ---参数为类数组对象Array.from(args)
     const result = context[fn](...Array.from(args))
     // 清除对象上的fn属性
     delete context[fn]
     
     return result
 
}
let ceshi = function(name, age, className) {
    this.name = name,
    this.age = age,
    this.className = className
}
let obj = {
    name: 'xiaohua',
    age: 18
}
let school = {
    className: 2,
    age: 18
}
ceshi.myApply(obj,['xiaohuaya',1,2])
ceshi.myApply(school,['shiwoa',2,3])
console.log(obj,school);
image.png
  • bind(参数用逗号隔开,需要自调用)

你可能感兴趣的:(小哥带来的学习)