JavaScript关于创建对象你可能不了解的一些内部原理

创建对象的几种方式

在js中,经常看到如下四种创建对象的方法:

var obj = {}; // 对象字面量,跟new Object()一致
var obj1 = new Object(); // new方式创建对象
var obj2 = Object.create(); // 通过Object.create创建

但我们在开发项目过程中,还有另一种常用的创建对象的方式,即通过function方式:

function PObject(name) {
    this.name = name;
}
var obj3 = new PObject('weis');
var obj4 = new PObject('smas');

跟强类型语言,比如C#,C++,java一样,通过new function方式实现继承达到方法复用目的,但是这里篇幅主要是讲解对象创建方式,继承方式可以放在后面专门讲解。

new创建对象

通过new创建对象,这个过程做了什么事情?

可以看出,obj3的[[Prototype]]即__proto__==PObject.prototype,况且object对象新增了一个name属性,依此,new主要做了以下步骤:

  1. 创建对象var o = {};
  2. 将新对象的隐形原型([[Prototype]])指向构造函数的原型prototype;
  3. 通过call、apply执行构造函数并将this指向新对象o;
  4. 返回这个新对象o;

创建一个newFun方法模拟一下new创建的过程:

function PObject(name) {
    this.name = name;
}
PObject.prototype.getName = function() {
    return this.name;
}
function newFun(func, name) {
    var o = {};
    o.__proto__ = func.prototype;
    func.call(o, name); // 改变this指向
    return o;
}
var obj3 = new PObject('weis');
var obj4 = new PObject('smas');

// 通过newFun创建
var obj5 = newFun(PObject, 'new ok');

运行了一下,可以看到obj3和obj5的指向一样,并且都有了name属性,__proto__里有getName了:

 new创建对象注意事项

new创建一个对象的时候,请注意了!!!构造函数默认返回this,即return this;我们不用显示的手动写出来,但是当显示写return的时候,可能会改变new的初衷,情况如下:

function PObject(name) {
    this.name = name;
    return this;   // 如果不手动写,js规范默认自己加上去
}

var obj6 = new PObject('weis');
console.log(obj6); // PObject{name:'weis'};

还是返回new创建出来的对象。

function PObject(name) {
    this.name = name;
    return 1;  
}
var obj6 = new PObject('weis');
console.log(obj6); // PObject {name: 'weis'}

return 1竟然返回的还是new创建出来的对象,为什么?因为显示return返回一个number、boolean、string、null、undefined等简单的基本数据类型时,那么返回值仍然为新创建的对象。

function PObject(name) {
    this.name = name;
    return {
        ui: 90
    };  
    // return function() {};
    // return [4,5,6];
}
var obj6 = new PObject('weis');
console.log(obj6); // PObject {ui: 90}

如果return一个引用类型或者function时,那么this就会被抛弃,返回值被替换成新的引用或者function。

Object.create创建对象

MDN定义的原话:

Object.create方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__

按照我个人理解,就是通过Object.create创建的对象,是通过__proto__原型链查找属性。实例如下:

o对象的属性挂载在__proto__里了。也可以通过模拟Object.create创建对象的过程:

function PObject(name) {
    this.name1 = name || 'weis';
}
PObject.prototype.getName = function() {
    return this.name1;
}
function ObjCreate(func) {
    var f = function() {}; // 新的构造函数
    f.prototype = func; // 函数原型为fun参数
    return new f();
}
var obj3 = ObjCreate(PObject);
console.log(obj3.name1); // undefined 说明并没有执行PObject构造函数


var obj4 = ObjCreate(new PObject('smas')); // 传入new创建出来的匿名对象;
console.log(obj4);

 执行结果

ObjCreate模拟创建的跟Object.create原理一致,ObjCreate(PObject)执行结果可以看的出来,Object.create并没有执行和改变this指向,因此PObject对象上的属性不会继承到Object.create创建的实例中。

总结

  • 我们想继承原型方法,不想继承构造函数内部属性时,可以使用Object.create;
  • 了解对象创建,有助于我们在实际项目开发中,做功能复用时避免出现不必要的bug;
  • 看似简单的知识,也需要很多时间去吃透和理解,我不是一个天赋凌然的人,只能一点一滴去学习和积累。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值