Javascript手写系列(1)

实现以下方法,建议配合this指向原型与原型链食用更佳(点击链接了解相关知识)

1实现Instanceof(判断某个构造函数的prototype属性是否出现在了该对象原型链上)

function myInstanceof(obj, constructor) {
    let left = Object.getPrototypeOf(obj);
    let right = constructor.prototype;
    while (true) {
        if (left == null) return false;
        if (left === right) return true;
        left = Object.getPrototypeOf(left);
    }
}
原型链是由对象及它的proto属性一级一级构成的,所以只需判断constructor.prototype是否等于原型链上某个对象的proto。如果最后等于null,说明遍历到了原型链尽头了,就肯定没有出现在原型链上了。

2实现new操作符

new操作符先创建了一个空对象

设置原型,将对象的原型设置为构造函数的prototype属性(让这个对象可以使用原型上的方法)

让函数的this指向这个对象,执行构造函数代码(为这个对象添加属性)

判断返回类型,如果是值类型,返回创建的对象,如果是引用类型,返回这个引用类型的对象

function Mynew() {
    let newObj = null;
    result = null;
    constructor = Array.prototype.shift.call(arguments);
    if (typeof constructor !== 'function') {
        console.error("type error");
        return;
    }
    newObj = Object.create(constructor.prototype);
    //给newObj添加函数上的属性并将return结果赋值给result
    result = constructor.apply(newObj, arguments);
    let flag = result && (typeof result === 'object' || typeof result === 'function');
    return flag ? result : newObj;
}
使用:Mynew(构造函数,初始化参数)
行12 13看如下代码,应该可以理解
//判断返回类型,如果是值类型,返回创建的对象(在行13中属于return newObj情况)
function Person(name) {
    this.name = name; //默认return undefined,值类型
}
const user = new Person('khkkm');
console.log(user.name) //khkkm
——————————————————————————————————————————————————
//判断返回类型,如果是引用类型,返回这个引用类型的对象(在行13中属于return result情况)
function Person(name) {
    this.name = name;
    return {
        age: 20
    }
}
const user = new Person('khkkm');
console.log(user.name) //undefined
console.log(user.age) //20

3 call

call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。

Function.prototype.myCall = function (context) {
    if (typeof this !== "function") {
        console.error("type error");
        return;
    }
    let result = null;
    args = [...arguments].slice(1);
    context = context || window;
    context.fn = this;
    result = context.fn(...args);
    delete context.fn;
    return result;
}
看着上面的解释,应该不难理解

4 apply

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次。

Function.prototype.myApply = function (context) {
    if (typeof this !== 'function') {
        console.error("type error");
        return;
    }
    let result = null;
    context = context || window;
    context.fn = this;
    if (arguments[1]) {
        result = context.fn(...arguments[1]);
    } else {
        result = context.fn();
    }
    delete context.fn;
    return result;
}
看着上面的解释,应该不难理解

5 bind

bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。

Function.prototype.myBind = function (context) {
    if (typeof this !== 'function') {
        console.error("type error");
        return;
    }
    let fn = this;
    args = [...arguments].slice(1);
    return function Fn() {
        return fn.apply(this instanceof Fn ? this : context, args.concat(...arguments));
    }
};
行9 this instanceof Fn ? this : context 就是优先级:new绑定 > 显示绑定,args.concat(...arguments)则是参数可以分多次传

const func=fn.myBind({name:'khkkm'});
new func();
举例: fn就是随便一个函数,以上为对 this instanceof Fn ? this : context 的解释,如果将Fn(行8)作为了构造函数(如行 15),那么构造函数Fn的this得指向它new出来的实例对象,而不能是用户自定义的context。因为优先级 new绑定 > 显示绑定

6 Object.create(创建一个新对象,使用现有的对象来作为新创建对象的原型)

function MyCreate(proto) {
    function Fn() { }
    Fn.prototype = proto;
    Fn.prototype.constructor = Fn;
    return new Fn();
}
修改了构造函数的prototype属性后,记得把它的constructor指回它本身,主要是代码的规范性,别的作用没啥。

最后,希望能对大家有所帮助,祝愿各位都能找到自己满意的工作。

手写系列还会继续更新。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值