创建对象的几种方式

Posted 茂树24

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了创建对象的几种方式相关的知识,希望对你有一定的参考价值。

javascript中,所有对象的创建都是基于原型的。在js中任意的对象都有一个内部属性[[Prototype]]。这个属性的值只能是object或者是null。对象有这个内部属性的目的就是为了实现继承,或者更明确的说实现属性(方法)的复用。所以说创建一个对象的关键就是确定[[prototype]]的值。一般情况下,如果创建了一个对象什么属性也没有那么这个对象的原型就是Object.prototype。假设创建的对象的原型为null的话,则将不会继承toString等方法,也就不会进行相应的操作了。可以设么说,原型是js的核心。

 

创建一个对象有四种方式,分别是ES3之前的通过对象字面量创建、ES3中通过new创建对象、ES5标准下通过Object.create的方式创建对象、还有就是ES6中通过__proto__、Object.setPrototypeOf创建对象。其实上述这些方式根本是对对象的原型属性的操纵。

 

一、通过对象字面量创建对象

var myObj =

    name: "maotr",

    "ID  code": 21

;

通过对象字面量窗帘对象中,创建对象表达式每执行一次,表达式每部的被赋值的表达式也会执行一次,所以会出现下面这个情况:

function f()

    return myObj =

        name: "maotr",

        eat: function ()

    ;

console.log(f() === f());//false

console.log(f().eat === f().eat);//false

所以说使用这种方式创建对象的话仅仅限于单例模式,对于其他的方式会很消耗内存的。

 

除了我们都知道的对象的属性除了可以是标识符之外,如果不符合标识符条件可以通过字符串的形式引用,比如:一开始那个例子。即使在ES5标准下,通过这种方式定义的对象的属性是不能变的。也就是说只能是标识符或者字符串常量。如果要使用变化的属性怎么办,只能通过如下方式:

function f(name, value)

    var o =

        x: 2,

        y: 4

    ;

    o[name] = value;//使用[]访问运算符进行添加属性。

    return o;

但是在ES6标准下,可以这样了:

function f(name, value)

    return

        x: 2,

        y: 4,

        [name]: value

    ;

console.log(f("z", 10).z);//10

也就是说,在ES6中:左边的属性名不再要求是常量了,而是可以使表达式。工作方式是:当执行到一个对象字面量表达式的时候,除了创建一个对象和计算每一个属性的值之外,还会计算:左边的方括号内的表达式,并且将结果通过调用内部的toString函数转化成字符串,也就是说如下实例:

function f(name, value)

    return

        x: 2,

        y: 4,

        [name+4]: value

    ;

console.log(f("^", 10)["^4"]);//10

 

 

二、通过new关键字创建对象

New更像是为了能够靠近面向对象类式语言而引入的。New关键字实现的功能就是将一个对象的原型属性绑定到构造函数的prototype中去,然后执行构造函数执行初始化。所以这么看来函数中有prototype也是为了类式风格的面向对象设计而引入的。但是对于js本身而言,实现类或者继承使用原型的方式更加纯粹。

对于new关键字是如何工作的呢?看一下规范就明白了。

 

 

我们可以不是同new和函数内部的prototype情况下模拟类的创建。

function defineClass(initializer, proto) 
    if(typeof initializer !== 'function') 
        throw TypeError('the initializer may only an function');
    
    return (function f() 
       var obj, result;
      if(!(proto instanceof Object)) 
        proto = Object.prototype;
      else 
        proto.constructor = initializer;
      
       //obj = Object.create(proto); ES5
       function Temp() ;
       Temp.prototype = proto;
       obj = new Temp();
       f.prototype = proto;
 
       result = initializer.apply(obj, arguments);
       if(result instanceof Object) 
            obj = result;
       
 
       return obj;
    );

 
var Point = defineClass(function (x, y)
    this.x = x;
    this.y = y;
,
    getLength: function()
        let x, y = this;
        return Math.sqrt(x * x + y * y);
    
 
);
 
var p = Point(3,4);
 console.log(p.getLength(),p instanceof Point, p instanceof Object);//5 true true


所以这种通过new创建对象的方式使得创建对象时要创建一个函数作为构造函数,使得原型这个工具使用起来比较局限,不能灵活的去使用。下面介绍的Object.create略有改善。

 

三、通过Object.create创建对象

Object.create函数传入第一个参数是返回的对象的原型,第二个参数是添加到对象中的属性的特性的描述。但是对于IE6到8来说存在兼容性的问题。所以要处理兼容性:

if (typeof Object.create !== 'function') 
    Object.create = (function () 
        //为了省内存,共享一个构造器
        function Temp() ;
 
        //使用Object.propertype.hasOwnProperty更安全的引用
        var hasOwn = Object.prototype.hasOwnProperty;
 
        return function (proto, properties) 
            //1、如果proto不是Object或者null,则抛出异常
            if(typeof proto !== 'object') 
                throw TypeError('Object prototype may only be an Object or null');
            
 
            //2创建一个对象obj,和通过new Object()方式创建的一样
            //3设置obj的prototype值为proto
            Temp.prototype = proto;
            var obj = new Temp();
            Temp.prototype = null;//不要保持一个proto的杂散引用
 
            //4如果存在参数properties 而不是undefined
            //那么就把参数的自身属性添加到obj上,就像是调用
            //携带obj,properties两个参数的标准内置函数
            //Object.properties()一样
            if (properties !== undefined) 
                for (var key in properties) 
                    if(hasOwn.call(properties, key)) 
                        obj[key] = properties[key];
                    
                
            
            //5返回obj
            return obj;
        
    )();


 

ES5这个方法的提出,使得创建对象可以直接明确的赋予原型值,使得原型成为一个可以控制的量,真正的将js原型的功能发挥出来,但是有一个缺点就是一旦创建了这个对象之后,这个对象就和这个传入的原型对象绑定在一起,不够灵活。下面ES6能够直接操作对象的原型属性,所以更加灵活了。

 

四、通过Object.setPrototypeOf创建对象。

 

Object.setPrototypeOf方法,用来设置一个对象的prototype对象,返回参数对象本身。

 

let proto = ;let obj = x: 10 ;

Object.setPrototypeOf(obj, proto);

 

proto.y = 20;

proto.z = 40;

 

obj.x // 10

obj.y // 20

obj.z // 40


注意返回的是设置对象本身,所以:

如果第一个参数不是对象,会自动转为对象。但是由于返回的还是第一个参数,所以这个操作不会产生任何效果。

Object.setPrototypeOf(1, ) === 1 // true

Object.setPrototypeOf('foo', ) === 'foo' // true

Object.setPrototypeOf(true, ) === true // true


由于undefined和null无法转为对象,所以如果第一个参数是undefined或null,就会报错。

Object.setPrototypeOf(undefined, )

// TypeError: Object.setPrototypeOf called on null or undefined

Object.setPrototypeOf(null, )

// TypeError: Object.setPrototypeOf called on null or undefined

 

以上是关于创建对象的几种方式的主要内容,如果未能解决你的问题,请参考以下文章

js创建对象的几种方式

Java 创建对象的几种方式

创建对象的几种方式和对象方法

javascript对象的几种创建方式

IOC创建对象的几种方式

js中面向对象(创建对象的几种方式)