如何实现一个函数,可以使用new操作符创建对象,也可以直接使用创建对象?

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sinat_36521655/article/details/82433092

一、缘由

今天在牛客网讨论区看到了一个题目:如何实现一个函数,可以使用new操作符创建对象,也可以直接使用创建对象?

当时有点懵,回头翻了翻《JS高程》,发现里面的工厂模式和寄生构造函数模式的代码不就是这个题目的答案。

下面是《JS高程》中的代码,两种模式的代码相同:

function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}

二、new操作符

在解析这个问题前,首先要讲一下new操作符的内部发生了什么。

在JS中,通过new操作符实例化构造函数创建对象,内部总共有四个步骤。

比如var person = new Person('David', '25', 'student');

第一步:创建新对象,即var obj = new Object();

第二步:设置原型链,即obj.__proto__ = Person.prototype;

第三步:使用指定参数调用构造函数,并将this绑定到新对象上,即var result = Person.call(obj, 'David', '25', 'student');

第四部:判断构造函数的返回值,即result的值,如果是基础类型或者没有返回值,则返回obj;如果是引用类型,则返回result。即return typeof result === 'object' ? result : obj;

三、问题解析

《JS高程》中的解释是:构造函数在不返回值的情况下,默认会返回新对象的实例。而通过在构造函数的末尾添加一个return语句,可以重写调用构造函数时返回的值。

扫描二维码关注公众号,回复: 3315018 查看本文章

当时我第一次看这句话的时候,自动跳过去了,没有去深入了解,但实际上结合上面讲的就非常容易理解了。

对比这两种创建的方式

var person1 = new Person('David', '25', 'student');
var person2 = Person('David', '25', 'student');

第一种方式当构造函数使用,按照上面讲的流程,因为Person构造函数返回值是引用类型,所以他的返回值就是上面直接调用构造函数并且绑定this到新对象obj上的值,与第二种工厂模式直接调用函数的方式的返回值一样。 

有一点值得注意的是,实例person1和person2都不是Person的实例,而是Object的实例。

instanceof 检测一个对象A是不是另一个对象B的实例的原理是:检查对象A的原型链[__proto__]上有没有对象B的原型[prototype]。如果有,则返回true,如果没有则返回false。不过有一个特殊的情况,当对象B的prototype为null将会报错(类似于空指针异常)。

为什么呢,因为他们都是基于Object创建的对象,而没有设置Person原型,所以他们的原型链上并没有Person.prototype。如果构造函数返回值没有或者是基本类型时,按照第二节中讲到的第四步,返回的obj设置了原型链,所以他们就能判断是构造函数的实例。

四、总结

有想法就记录一下,不一定说的对,如果有问题请务必指正。

猜你喜欢

转载自blog.csdn.net/sinat_36521655/article/details/82433092
今日推荐