JS中的new操作符与Object.create()

new操作符用于实例化一个对象: var obj = new Base();,具体过程可解释如下:
(1) 创建一个新对象,__proto__属性指向构造函数的prototype,其中constructor指向原构造函数;
(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
用代码简单解释就是:

    var obj  = {};//创建一个空对象
    obj.__proto__ = Base.prototype;//将对象的__proto__对象指向Base的prototype
    Base.call(obj);//将Base中的this指向obj并执行函数,将属性添加到obj中

接下来再通过例子来看看new操作符在实际使用中的问题:

    var Base = function(){
        this.name = 'in';
    }
    Base.name = 'out';
    var obj1 = new Base();
    var obj2 = new Base;

以上两个obj其实返回的是一样的,调用name属性都会是’in’,但是下面的呢:

    var obj3 = new Base.name;//报错
    var obj4 = Base().name;//报错
    var obj5 = new Base().name;//'in'

分别运行上面三个语句:
obj3那行会报错,原因是Base.name不是一个构造函数,这说明了new操作符的运算优先级小于.的优先级,而且new确实是需要调用构造函数,这里的这个构造函数(constructor)就是Base函数。
obj4那行也会报错原因是Base()函数运行后未返回任何值,被默认成undefined,在调用name属性自然报错。
obj5那行不会报错,对照obj4来看,new Base().name不报错应该是先运算new Base()在访问name属性,此时new Base()的形式运算优先级就要高于.运算。
再来看看下面代码:

    var Base = function(name){
        this.name = name;
        console.log(name);
        return {name:''}
    }
    var base = new Base('myName')//myName
    console.log(base.name);//''

上面的构造函数会打印传入时的name值,最后返回一个name为空的对象,可以看到,在执行var base = new Base('myName')这条语句时Base函数被执行,打印了‘myName’,但是最后访问base的name属性时成了空,这说明base最终指向了{name:’’}对象,可以看它的constructor,指向的是Object,并非Base,这与直接执行Base('myName')得到的结果相同,不同的是,直接调用Base('myName'),this指向window(浏览器中,严格模式下会报错),可以访问到,window.name为’myName’,而new Base(‘myName’)函数执行后里面的name等属性就访问不到了,最终被销毁。


Object对象提供了一个创建对象实例的方法Object.create(p1,p2),接受两个参数,p1必选,为要继承的原型,p2为可选,为包含一个或多个属性描述符的JavaScript对象。具体过程简化一下,p2实现为创建实例后可枚举的对象,于是可用以下代码简单展现:

Object._create =  function (p1, p2) {
    var F = function () {
        for(var prop in p2){
            this[prop] = p2[prop]; 
        }
    };
    F.prototype = p1;
    return new F();
};

其中p1可为null,终断原型链。

你可能感兴趣的:(前端日常)