美文网首页前端
JavaScript实现常用API

JavaScript实现常用API

作者: Kevin丶CK | 来源:发表于2019-09-17 15:49 被阅读0次

一、new运算符

语法
new constructor[([arguments])]

constructor
一个指定对象实例的类型的类或函数。
arguments
一个用于被 constructor 调用的参数列表。

描述

当代码 new Foo(...) 执行时,会发生以下事情:

  1. 一个继承自 Foo.prototype 的新对象被创建。
  2. 使用指定的参数调用构造函数 Foo,并将 this 绑定到新创建的对象。new Foo 等同于 new Foo(),也就是没有指定参数列表,Foo*不带任何参数调用的情况。
  3. 由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式返回一个对象,则使用步骤1创建的对象。(一般情况下,构造函数不返回值,但是用户可以选择主动返回对象,来覆盖正常的对象创建步骤)。

根据上面的条件,我们就可以写代码了

 function myNew(constructor, ...args) {
        //以构造器原型创建对象
        let instance = Object.create(constructor.prototype);
        //执行构造器,并把构造器内部的this指向返回的对象
        let res = constructor.apply(instance, args);
        //如果构造器有返回对象,则使用返回的对象,没有则使用以构造器原型创建对象
        return typeof res === "object" ? res : instance;
      }

测试代码

let mFunc = myNew(Foo, "张三");
      mFunc.work();
      console.log(mFunc.name);

二、call/apply方法

call语法
fun.call(thisArg, arg1, arg2, ...)

thisArg
在 fun 函数运行时指定的 this 值。
if(thisArg == undefined|null) this = window,
if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()
arg1, arg2, ...
指定的参数列表。

返回值

使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined

apply语法
func.apply(thisArg, [argsArray])

thisArg
可选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 nullundefined 时会自动替换为指向全局对象,原始值会被包装。
argsArray
可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。
其实call和apply的区别就是第二个参数,apply第二个参数是一个数组或者类数组。其他的和call一样,性能也一样。所以,自定义功能时,唯一的区别就是传递的参数。
根据上面的条件,我们就可以写代码了

      Function.prototype.MyCall = function(context, ...args) {
        //获取当前this(调用MyCall的函数),自定义的call方法在函数的原型对象上,所以typeof this =='function'
        let mFunc = this;
        //创建变量,作为指定this对象(call的第一个参数context)的属性名
        let fnKey = "fnKey";
        //把当前this(调用MyCall的函数)作为属性值保存到指定this对象(call的第一个参数context)上,属性名为上面定义的fnKey
        context[fnKey] = mFunc;
        //调用指定this对象(call的第一个参数context)上的当前this(调用MyCall的函数)
        let result = context[fnKey](...args);
        //执行结束,删除该属性
        delete context[fnKey];
        return result;
      };
     Function.prototype.MyApply = function(context, args) {
        //获取当前this(调用MyCall的函数),自定义的call方法在函数的原型对象上,所以typeof this =='function'
        let mFunc = this;
        //创建变量,作为指定this对象(call的第一个参数context)的属性名
        let fnKey = "fnKey";
        //把当前this(调用MyCall的函数)作为属性值保存到指定this对象(call的第一个参数context)上,属性名为上面定义的fnKey
        context[fnKey] = mFunc;
        //调用指定this对象(call的第一个参数context)上的当前this(调用MyCall的函数)
        let result = context[fnKey](...args);
        //执行结束,删除该属性
        delete context[fnKey];
        return result;
      };

测试代码

 let obj = {
        name: "张三",
        id: 1002
      };
      function TestFunc(name, id) {
        this.name = name;
        this.id = id;
        return {
          name: this.name,
          id: this.id
        };
      }
      let resCall = TestFunc.MyCall(obj, "abc", 11111);
      console.log(obj);
      console.log(resCall);
      let resApply = TestFunc.MyApply(obj, ["efg", 2222]);
      console.log(obj);
      console.log(resApply);

三、Object.create()方法

语法
Object.create(proto[, propertiesObject])

proto
新创建对象的原型对象
propertiesObject
可选。如果没有指定为 undefined,则是要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。
返回新的对象,带着指定的原型对象和属性。
这里偷个懒,给新对象添加属性就采用Object.defineProperties(),不熟悉Object.defineProperties()可以点击上面蓝色部分查看,里面也有兼容版本polyfill的实现。
根据上面的条件,我们就可以写代码了

 Object.prototype.myCreate = function(proto, propertiesObject) {
        //判断传入的原型对象
        if (typeof proto !== "object" && typeof proto !== "function") {
          throw new TypeError("Object prototype may only be an Object");
        } else if (proto === null) {
          throw new Error(" Object.create不支持第一个参数为null");
        }
        if (propertiesObject === null) {
          throw new Error(" Object.create第二个参数不能为null");
        }
        //创建一个构造函数
        function F() {}
        //设置构造函数的原型为新创建对象的原型对象
        F.prototype = proto;
        //构造器的原型对象的constructor指向自身,防止原型链错乱
        F.prototype.constructor = F;
        //创建实例对象
        let newObj = new F();
        //加到新创建对象的可枚举属性
        if (typeof propertiesObject != "undefined") {
          //这里偷懒,这个API暂时就不自定义
          Object.defineProperties(newObj, propertiesObject);
        }
        return newObj;
      };

测试代码

     let obj = {};
      let propertiesObj = {
        property1: {
          value: true,
          writable: true
        },
        property2: {
          value: "Hello",
          writable: false
        }
      };
      console.log(Object.create(obj, propertiesObj));
      let myObj = Object.myCreate(obj, propertiesObj);
      console.log(myObj);

四、数组的map方法

语法
var new_array = arr.map(function callback(currentValue[, index[, array]]) {
 // Return element for new_array 
}[, thisArg])

callback
生成新数组元素的函数,使用三个参数:
currentValue
callback 数组中正在处理的当前元素。
index可选
callback 数组中正在处理的当前元素的索引。
array可选
callback map 方法被调用的数组。
thisArg可选
执行 callback 函数时使用的this 值。
返回一个新数组,每个元素都是回调函数的结果。
根据上面的条件,我们就可以写代码了

       Array.prototype.MyMap = function (callBack, context) {
           // 浅拷贝要遍历的数组
           var copyArr = Array.prototype.slice.call(this);
            //有就使用,null或者undefined,设定为全局对象
            context = context || window;
            //调函数的结果
            var resultArr = [];
            for (let index = 0; index < copyArr.length; index++) {
                //是否是自己的属性
                if (!copyArr.hasOwnProperty(index)) continue;
                //把回调结果放入返回的数组中,回调函数按照上面设置为三个参数
                resultArr.push(callBack.call(context, copyArr[index], index, this));
            }
            return resultArr;
        }

测试代码

        let arr = [1, 2, { name: '123' }];
        arr.MyMap(function(item,index,context){
            console.log('item:'+item,"index:"+index);
            console.log(this);
        },{id:123});
结果
        let arr = [1, 2, { name: '123' }];
       let newArr= arr.MyMap(function(item,index,context){
            console.log('item:'+item,"index:"+index);
            console.log(this);
            return {name:item}
        });
        console.log(newArr);
image.png

另外,map方法中,对于每一项是浅拷贝。

        let arr = [1, 2, { name: '123' }];
        arr.map(function (item,index) {
            if (typeof item === 'object') {
                item.id = 4555;
            } else {
                item = index;
            }
        });
  console.log(arr);
image.png
所以,上面采用浅拷贝就行,浅拷贝和深拷贝有疑惑的,可以阅读一下这篇文章

五、数组的reduce方法

语法
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])

callback
执行数组中每个值的函数,包含四个参数:
accumulator
累计器累计回调的返回值; 它是上一次调用回调时返回的累积值,或initialValue(见于下方)。
currentValue
数组中正在处理的元素。
currentIndex可选
数组中正在处理的当前元素的索引。 如果提供了initialValue,则起始索引号为0,否则为1。
array可选
调用reduce()的数组
initialValue可选
作为第一次调用 callback函数时的第一个参数的值。 如果没有提供初始值,则将使用数组中的第一个元素。 在没有初始值的空数组上调用 reduce 将报错。
返回函数累计处理的结果。
根据上面的条件,我们就可以写代码了

        Array.prototype.myReduce = function (callBack, initialValue) {
            // 浅拷贝要遍历的数组
            let copyArr = Array.prototype.slice.call(this);
            //提供初始值,从第一项开始,没有提供从第二项开始
            let currentIndex = initialValue ? 0 : 1;
            let result = initialValue ? initialValue : copyArr[0];
            for (let index = currentIndex; index < copyArr.length; index++) {
                //调用回调函数,按照上面的设置四个参数
                result = callBack.call(null, result, copyArr[index], index, this);
            }
            return result;
        }

下面是测试代码

      let redarr = [1, 2, 3, 4, 5];
        let result = redarr.reduce(function (accumulator, item) {
            return accumulator + item;
        }, 10);
        console.log(result);
        let mResult = redarr.myReduce(function (accumulator, item) {
            return accumulator + item;
            return
        }, 10);
        console.log(mResult);
结果

bind方法

语法
function.bind(thisArg[, arg1[, arg2[, ...]]])

thisArg
调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用bindsetTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg
arg1, arg2, ...
当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。
返回一个原函数的拷贝,并拥有指定的this值和初始参数。
根据上面的条件,我们就可以写代码了

      Function.prototype.myBind = function(context, ...args) {
        //获取当前方法
        let _that = this;
        //创建返回的函数
        let mNewFunc = function(...argsNew) {
          //把参数拼接,并改变原函数的this对象,返回原函数的返回值
          return _that.apply(context || window, [...args, ...argsNew]);
        };
        //保证原函数的原型对象上的属性不丢失
        mNewFunc.prototype = Object.create(_that.prototype);
        return mNewFunc;
      };

测试代码

      var myName = "999";
      let module = {
        myName: "上海"
      };
      function bindFuc(args) {}
      bindFuc.myName = "ABCDE";
      function textFuc(args) {
        console.log("args:", arguments);
        console.log("myName:" + this.myName);
      }
      var boundTextFuc = textFuc.bind(module, "123");
      boundTextFuc("145");
      var boundTextFuc = textFuc.myBind(module, "123");
      boundGetX("145");

instanceof运算符

语法
object instanceof constructor

object
要检测的对象
constructor
某个构造函数
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。
根据上面的条件,我们就可以写代码了

      Object.prototype.myInstanceof = function(constructor) {
        //获取要检测的对象
        let object = this;
        //判断constructor是否是对象
        if (constructor == null || typeof constructor !== "function") {
          return new Error("第二个参数必须为构造函数");
        }
        //获取验检测对象的原型
        let objProto = Object.getPrototypeOf(object);
        //循环在检测对象的原型链上查找是否存在constructor.prototype
        while (true) {
          //排除检测对象是Object.prototype的原型的情况
          if (objProto == null) return false;
          if (objProto == constructor.prototype) return true;
          objProto = Object.getPrototypeOf(objProto);
        }
      };

测试代码

      function TestFunc() {}
      let mTestFunc = new TestFunc();
      console.log(mTestFunc.myInstanceof(Number),mTestFunc instanceof Number);
      console.log(mTestFunc.myInstanceof(Function),mTestFunc instanceof Function);
      console.log(mTestFunc.myInstanceof(Object),mTestFunc instanceof Object);
      console.log(Function.myInstanceof(Object),Function instanceof Object);
      console.log(Object.myInstanceof(Function),Object instanceof Function);

相关文章

  • JavaScript实现常用API

    一、new运算符 语法 constructor一个指定对象实例的类型的类或函数。arguments一个用于被 co...

  • DOM常用API

    Javascript操作DOM常用API总结 文本整理了javascript操作DOM的一些常用的api,根据其作...

  • JavaScript常用API合集

    JavaScript常用API合集 本文分享了一些JavaScript常用的代码,有DOM操作、CSS操作、对象(...

  • dom

    Javascript操作DOM常用API总结 Posted on 2015-11-30 | In Ja...

  • JavaScript常用的API

    1 什么是DOM 文档对象模型 (DOM) 是HTML和XML文档的编程接口。它提供了对文档的结构化的表述,并定义...

  • javascript常用的API

    JavaScript常用API合集 一、节点 1.1 节点属性 1.2 操作 1.3 Document节点 1.3...

  • JavaScript常用API总结

    目录 1.元素查找2.class操作3.节点操作4.属性操作5.内容操作6.css操作7.位置大小8.事件9.DO...

  • Frida JavaScript 常用 API

    1. Process 1.1 Process.id 当前附加进程的 pid。 1.2 Process.enumer...

  • 5、Selenium -- CSS Selector定位

    一、常用工具 浏览器 Console 查询:$$(' xxxxxx ') javascript 对应 API:fi...

  • 高德地图实现输入提示服务

    高德地图 高德地图的一个可能实现方案。 以JavaScript为例 开发 > JavaScript API > 开...

网友评论

    本文标题:JavaScript实现常用API

    本文链接:https://www.haomeiwen.com/subject/gcbyectx.html