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