博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript模拟new的实现
阅读量:6920 次
发布时间:2019-06-27

本文共 4350 字,大约阅读时间需要 14 分钟。

在日常使用new时,我们很清楚它的作用。

准备工作

我们先创建一个Person类,他接受两个参数name姓名和age年龄:

function Person(name, age){    this.name = name;    this.age = age;}Person.prototype.sayHello = function(){    console.log('我叫' + this.name + ', 今年' + this.age + '岁了');}复制代码

new 的使用

我们先用new实例化一个person,并打印出来,看看结构。

var person = new Person('小明', 20);console.log(person); // Person {name: "小明", age: 20}person.sayHello(); // 我叫小明, 今年20岁了复制代码

最终person的结果是一个object

模拟过程

结合Person方法,我们容易发现,仿佛有一个object替代了this的位置,执行了赋值操作,输出了最后的结果。

1、替代this赋值

思考替代过程:

// 1、创建了一个对象    var result = {};         // 2、对象代替了this的位置,执行了赋值    {        result.name = "小明";        result.age = 20;       }         // 3、输出 {name: "小明", age: 20}    return result; 复制代码

那么问题来了,我该如何将这个result替代this的位置呢?

这就用到了call或者apply:

var result = {};    Person.call(result, '小明', 20);    result; // {name: "小明", age: 20}复制代码

这样我们就完成了第一步,你可以在console控制台中尝试一下!

接下来就是处理原型部分了。

2、原型移植

这就很简单了,我们有很多办法:

//方案1result.__proto__ = Person.prototype; //有一定副作用(可枚举)//方案2Object.setPrototypeOf(result, Person.prototype);//方案3result = Object.create(Person.prototype);复制代码

3、初步结果

综上我们容易整理出这样的结果:

function likeNew(fn){        //我们先完成原型移植,以免构造函数中调用了原型方法。        var result = Object.create(fn.prototype);        var args = [].slice.call(arguments,1);        fn.apply(result, args);        return result    }    var person = likeNew(Person, '小明', 20);     console.log(person); // Person {name: "小明", age: 20}    person.sayHello(); // 我叫小明, 今年20岁了复制代码

虽然我们按照思路是先创建对象->执行->处理原型。

但是实际上正确的顺序是 创建包含对应原型的对象->执行。

问题

如果被实例化的方法如果本身包含返回值,new的结果会是什么呢?

function Person(name, age){        this.name = name;        this.age = age;        return name    }    var person = new Person('张三', 20);    console.log(person); // ?    var person1 = new Person(['张三'], 20);    console.log(person); // ?复制代码

通过尝试,输出结果分别为Person {name: '张三', age: 20}['张三']

为什么会产生完全不同的结果呢?
猜想:方法返回值的类型决定实例化后的结果

1、基本类型

js中的基本类型有number、string、boolean、undefined、null、symbol(es6)共6种。

function Test(value){        this.value = value;        return value;    }    //number    var number = new Test(123);    console.log(number); // Test {value: 123}        //string    var string = new Test('abc');    console.log(string); // Test {value: 'abc'}        //boolean    var boolean = new Test(true);    console.log(boolean); // Test {value: true}        //undefined    var Undefined = new Test();    console.log(Undefined); // Test {value: undefined}        //null    var Null = new Test(null);    console.log(Null); // Test {value: null}        //symbol    var symbol = new Test(Symbol('key'));    console.log(symbol); // Test {value: Symbol(key)}复制代码

上述例子所有返回值均为实例化后的对象,由此可见,所有基本类型返回的都是正常的。

2、引用类型

js中的引用类型有 object、array、function。我们接着上面的Test类继续创建对象:

//object    var object = new Test({}});    console.log(object); // {}        //array    var array = new Test([]);    console.log(array); // []        //function    var functions = new Test(function(){});    console.log(functions); // function(){}        //特殊的number    var number = new Test(new Number(1));    console.log(number); // Number {1}    console.log(typeof number); // object。复制代码

可见,方法的返回值若为引用类型,new操作符就“失效”了。

那他真的失效了吗?让我们看看方法内部执行的过程:

function Test(value){        this.value = value;        console.log(this);        return [1,2,3];    }    var result = new Test(1); // Test {value: 1}    console.log(result);// [1, 2, 3]复制代码

由此可见,this在Test的实例化过程中,确实被创建了,只不过由于Test本身的返回值为引用类型,所以实例化后的结果被其替换了。

最后的整理

根据以上的推论,再次完善了likeNew:

function likeNew(fn){        var result = Object.create(fn.prototype);        var args = [].slice.call(arguments,1);        var fnResult = fn.apply(result, args);        if(typeof fnResult === 'object' || typeof fnResult === 'function' && fnResult !== null){            return fnResult        }        return result    }        var person = likeNew(Person, '小明', 20);     console.log(person); // Person {name: "小明", age: 20}    person.sayHello(); // 我叫小明, 今年20岁了        //原始类型 number    var number = likeNew(Test, 1);    console.log(number); // Test {value: 1}        var Null = likeNew(Test, null);    console.log(Null); // Test {value: null}        //引用类型    var object = likeNew(Test, {});    console.log(object); // {}        var numberObject = likeNew(Test, new Number(1));    console.log(numberObject); // Number{1}复制代码

总结:

1、new操作符在进行实例化时,首先会创建一个包含指定__proto__的对象,再带入方法中执行,并选择性输出此对象。
2、被操作的方法的返回值若为引用类型,则会替换原本实例化的结果。

以上如有不当请指出。

转载地址:http://bircl.baihongyu.com/

你可能感兴趣的文章
C语音中关键字static的作用及类的static属性
查看>>
Hibernate映射配置:数据类型映射
查看>>
LCD驱动 15 -2
查看>>
机器学习实战之k-近邻算法(3)---如何可视化数据
查看>>
API测试利器——Postman(2. 理解和处理响应)
查看>>
大叔也说Xamarin~Android篇~调用远程API接口,发POST请求
查看>>
April Flags_Schedule
查看>>
搭建git服务器
查看>>
获取客户端电脑名称
查看>>
将系统从.Net Core2.0升级到.Net Core2.1
查看>>
JavaScript学习基础
查看>>
Volatile关键字
查看>>
理解 python 中__name__ = '__main__' 的作用
查看>>
poj 求二叉树的结点
查看>>
总结:canvas与svg的介绍以及其区别
查看>>
iOS学习之Object-C语言属性和点语法(转载收集)
查看>>
mysql20170404代码实现
查看>>
Hibernate Validator
查看>>
再谈git和github-深入理解-3
查看>>
kindeditor4.1.11的使用方法
查看>>