资讯专栏INFORMATION COLUMN

js对象创建方法汇总及对比

piapia / 2884人阅读

摘要:中创建对象的方式有很多,尤其是基于原型的方式创建对象,是理解基于原型继承的基础。该函数中的属性指向该源性对象当通过该函数的构造函数创建一个具体对象时,在这个对象中,就会有一个属性指向原型。

js中创建对象的方式有很多,尤其是基于原型的方式创建对象,是理解基于原型继承的基础。因此在这里汇总一下,并对各种方法的利弊进行总结和对比,不至于以后对这些概念有模糊。

简单方式创建
var o = new Object();

我们都知道,实际上在javascript中并没有所谓的类的概念。因此在创建对象时不能像面向对象语言那样,通过类A new出来一个a对象。但是javascript有一个特殊的Object。我们可以借助Object来new一个对象。
然后可以通过如下方式给对象增加属性或方法:

    o.name="abc";

但是因为没有类的约束,这种方式创建出来的对象无法实现对象的重复利用,并且没有一种固定的约数,操作起来可能会出现这样或者那样的意想不到的问题。
有这样一个例子:

    var a = new Object;  
    var b = new Object;  
    var c = new Object;  
    c[a]=a;  
    c[b]=b;  
    alert(c[a]===a); //输出什么

关于这个例子的具体解答详见 例子出处

工厂方法创建

直接看一个例子:

    function createPerson(){
        var o = new Object();
        o.name = "abc";
        o.age = 20;
        return o;    
    }

这种创建对象的方法是在一个function中new Object(),并且赋予属性和方法,最后return 带有这些属性和方法的对象。

但是当我们想通过

    var p1 = createPerson();
    alert(typeof(p1));//Object 仅能得到这个结果,实际上没有太大意义
    alert(p1 instanceof(类名???))//会发现其实并不存在一个Person类
构造函数的方式
    function Person(name,age){
        this.name = name;
        this.age = age;
        this.say = function(){
            //
        }
    }
    
    var p1 = new Person("abc",20);

构造函数的方式创建的对象:

函数名即为类名

通过this来定义属性

通过new Person()创建对象

并且有如下属性:

    alert(typeof(p1));// Person
    alert(p1 instanceof(Person));// true

但是同时我们也发现这种方式创建对象的一个弊端。对于类中的say方法,每分配一个对象就会有一个say的内存空间被分配出来。有一个say的拷贝。如果方法特别多的时候,会造成内存空间的极大浪费。可以通过两种方式进行优化和改进:

将say声明为全局的

    function say(){
    
    }

然后在类的定义中通过:

    this.say = say;

采用下面提到的基于原型的方式创建对象

让类中的行为统一指向全局的say方法。但是如果将所有的方法设为全局的时候,就可以被window对象调用,那么就破坏了对象的封装性;如果方法很多,会造成代码中充斥着大量的全局函数。

基于原型创建对象
    function Person(){
        
    }
    Person.prototype.name = "abc";
    Person.prototype.age= 20;
    Person.prototype.say= function(){
        alert(this.name+this.age);
    }
    
    
    var p1 = new Person();
    p1.say();//ok
    say();//no 完成了封装
    

原型是js中的一个特殊对象。当一个函数创建之后,会随之产生一个原型对象。该函数中的prototype属性指向该源性对象;
当通过该函数的构造函数创建一个具体对象时,在这个对象中,就会有一个_prop_属性指向原型。这些是js中的很重要的一种继承方式--基于原型的继承的基础。这里不再赘述。

基于原型创建对象时,如果对象的属性和方法特别多时,可以通过如下方式进行定义:

    Person.prototype = {
        name:"abc",
        age:20,
        say:function(){
        
        }
    }

称为原型重写。原型重写之后当我们再通过 var p1 = new Person()创建一个对象时,p1 的constructor != Person()了。由于原型重写了,而且没有通过prototype指向,从而指向了Object()。
如果constructor比较重要,可以再json格式的定义中手动制定

    constructor:Pserson

关于原型重写,我画了个示意图,比较容易理解:

p1是原型重写前声明的对象,p2是原型重写

    Person.prototype.name = "123";

之后的声明的对象。
可以看出

constructor的指向确实没有自动变换,除非通过上述手动的方式进行修改。

通过p2.name = "456",设置name时,会在自己的存储空间中存储。当然查找name属性时,也是从自己的内存空间中读取name值。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85977.html

相关文章

  • Node.js运行原理、高并发性能测试对比生态圈汇总

    摘要:模式,单实例多进程,常用于多语言混编,比如等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码。就是我们需要一个调度者,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡。 showImg(https://segmentfault.com/img/remote/1460000019425391?w=1440&h=1080); Nod...

    kamushin233 评论0 收藏0
  • Node.js运行原理、高并发性能测试对比生态圈汇总

    摘要:模式,单实例多进程,常用于多语言混编,比如等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码。就是我们需要一个调度者,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡。 showImg(https://segmentfault.com/img/remote/1460000019425391?w=1440&h=1080); Nod...

    BDEEFE 评论0 收藏0
  • Node.js运行原理、高并发性能测试对比生态圈汇总

    摘要:模式,单实例多进程,常用于多语言混编,比如等,不支持端口复用,需要自己做应用的端口分配和负载均衡的子进程业务代码。就是我们需要一个调度者,保证所有后端服务器都将性能充分发挥,从而保持服务器集群的整体性能最优,这就是负载均衡。 showImg(https://segmentfault.com/img/remote/1460000019425391?w=1440&h=1080); Nod...

    TesterHome 评论0 收藏0
  • 前端面试汇总VUE(二)

    摘要:采用了新旧的对比,获取差异的,最后一次性的更新到真实上。对基本属性进行监听对对象进行监听对对象某一个属性监听监听自定义指令全局指令,第一个参数是指令名,第二个参数是一个对象,对象内部有个的函数,函数里有这个参数,表示绑定了这个指令的元素。 11.vue 虚拟DOM的理解 Web界面由DOM树(树的意思是数据结构)来构建,当其中一部分发生变化时,其实就是对应某个DOM节点发生了变化,  ...

    Sanchi 评论0 收藏0

发表评论

0条评论

piapia

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<