Object.create()与new操作符

最近几天在看ES6的东东,看到了对象的扩展运算赋值解构部分,对被扩展操作符应用的赋值解构变量与对象实际属性解构时候的对应关系产生了一点疑惑,所以着手研究了一下,写一写心得,防止之后再忘记或者混淆可以再回头来看看这篇文章 ,看下面例子:

const o = Object.create({ x: 1, y: 2 });
o.z = 3;

let { x, ...newObj } = o;
let { y, z } = newObj;
x // 1
y // undefined
z // 3

首先,我们要知道:扩展运算符的解构赋值,不能复制继承自原型对象的属性
上面代码中,变量x是单纯的解构赋值,所以可以读取对象o继承的属性;变量y和z是扩展运算符的解构赋值,只能读取对象o自身的属性,所以变量z可以赋值成功,变量y取不到值。

根据上面这段代码,我查找了Object.create()new操作符对于原型继承方面的知识。

这两个知识点涉及到__proto__prototype,可以点击下面链接了解一下。
Javascript原型与原型链的理解

Object.create()

我们先来看一下Object.create()在MDN上英文原话:

The Object.create() method creates a new object with the specified prototype object and properties.

  • 语法

Object.create(proto[, propertiesObject])

  • 参数描述

proto

The object which should be the prototype of the newly-created object

propertiesObject

Optional. If specified and not undefined, an object whose enumerable own properties (that is, those properties defined upon itself and not enumerable properties along its prototype chain) specify property descriptors to be added to the newly-created object, with the corresponding property names. These properties correspond to the second argument of Object.defineProperties()

  • 返回值

A new object with the specified prototype object and properties.

看着英文描述我们来模拟一下Object.create()在执行过程中做了哪些操作呢?
①创建一个空对象{}
②指定空对象的原型(__proto__)为Object.create()的参数({}.__proto__ = proto
③返回这个对象
Object.create()的第一个参数可以是对象也可以是函数,返回值的类型实际上都是Object,当第一个参数为null,那结果返回的就是一个完全为空的新对象,没有继承Object.prototype上的任何属性与方法

var Base = function () {}
var o2 = Object.create(Base);

//console info
Base => //ƒ () {}
o2.__proto__ => // ƒ () {}
o2.prototype === Base.prototype => //true

var obj = {s:1,b:2};
var ty = Object.create(obj)

//console info
obj => // {s: 1, b: 2}
ty.__proto__ => // {s: 1, b: 2}
obj 与 ty 都是Object对象 没有prototype属性

new操作符

MDN对于 new操作符是这样解释的:

The new operator creates an instance of a user-defined object type or of one of the built-in object types that has a constructor function.

  • 语法

new constructor[([arguments])]

  • 参数描述

constructor

A class or function that specifies the type of the object instance.

arguments

A list of values that the constructor will be called with.

接下来我们分析一下var o = new f();在执行过程中做了什么:
①创建一个空对象{}
②让空对象的_proto_(IE没有该属性)成员指向了构造函数的prototype成员对象
③使用 apply/call 调用构造器函数,属性和方法被添加到 this 引用的对象中
④如果构造函数中没有返回其它对象,那么返回 this,即创建的这个的新对象,否则,返回构造函数中返回的对象

接下来我们模拟一下 new 的过程:

function _new() {
    let obj= {}; // 创建的新对象
    // 第一个参数是构造函数
    let [constructor, ...args] = [...arguments];

    // 执行 [[原型]] 连接 ;实际上就是生产了一个新的上下文
    obj.__proto__ = constructor.prototype;

    // 使用apply在obj作用域中调用构造器函数,属性和方法被添加到 this 引用的对象即obj中
    let result = constructor.apply(obj, args);
    if (result && (typeof (result) == "object" || typeof (result) == "function")) {
        // 如果构造函数执行的结果返回的是一个对象,那么返回这个对象
        return result;
    }
    // 如果构造函数返回的不是一个对象,返回创建的新对象
    return obj;
}

来实践一下:

var Base = function () {}
var o1 = _new(Base);
//console info
Base.prototype ===  o1.__proto__  => //true

下面我们结合实例来加深一下理解:
代码片段一

    function Person(age){
        this.age= age;
        console.log(this); 
        return {age:age};//返回对象
    }
    Person.prototype.index = 1

    var person1 = new Person(20);  // 此处相当于var person1=_new(Person, 20)
    var person2 = Person(18);
     
    console.log(person1);
    console.log(person2);

    console.log('p1.index=', person1.index)
    console.log('p2.index=', person2.index)
片段一输出结果
  • obj._proto_ = constructor.prototype,即 obj._proto_ = Person.prototype,将obj_proto_(隐式原型)指向Person的原型对象,此时obj的原型链为:
    obj => Person.prototype => Object.prototype => null
    因此 执行到let result = constructor.apply(target, args)这句代码时,在obj作用域中调用Person函数,打印出 Person {age: 20}
    因为Person函数返回的是一个对象,所以console.log(person1)打印出的就是返回的这个对象:{age: 20}person1.index自然就为undefined
    var person2 = Person(18),只是简单的调用了Person函数,在Window全局中执行,所以打印出Window对象,执行console.log(person2)打印出:{age: 18}person2.indexundefined

代码片段二

    function Person(age){
        this.age= age;
        console.log(this);
        // return {age:age};//返回对象
    }
    Person.prototype.index = 1

    var person1 = new Person(20);  // 相当于var person1 = _new (Person, 20);
    var person2 = Person(18);
     
    console.log(person1);
    console.log(person2);

    console.log('p1.index=', person1.index)
    console.log('p2.index=', person2.index)
片段二输出结果
  • 代码片段二和代码片段一的区别在于, 片段二中构造函数Person没有返回值(返回的不是一个对象,还可以通过直接返回age验证下效果),所以person1接收到的实际上是_new新创建的对象obj,即Person {age: 20}, person1.index则相当于obj.index属性时,它会先找自身的index属性,如果找不到,则会顺着原型链向上找,这时会找到People.prototype.indexperson1.index的结果是1
    由于Person没有返回值,所以console.log(person2)结果为undefined,进而,打印person2.index时会报错。

new 操作符只能对构造函数进行创建实例操作
以上new的部分借鉴了JS new 创建对象原理

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容