js--如何创建对象?
丶Serendipity丶 人气:1前言
作为前端开发者,谈起如何创建一个对象,你是否是只能想到利用常见的字面量的方式创建对象?你是否想过new Object()创建对象的过程是什么?本文整理了一些常见的创建对象的方法。
正文
创建对象的方法总结大概有以下几种:
(1)对象字面量的方式;
var Person = {}; //相当于var Person = new Object(); var Person = { name: "Nike", age: 29, };
对象字面量是对象定义的一种简单书写形式,目的在于简化创建包含大量属性的对象的过程。
(2)工厂模式;
工厂模式,常见的设计模式之一,创建对象过程不需要像客户暴露创建对象的具体逻辑,而是通过一个共同的接口来指向一个新常见的对象,换句话说就是用函数封装了创建对象的细节,从而通过调用函数达到了函数复用的目的,这种方式的缺点是无法识别对象的类型,无法建立对象和类型之间的联系。实例如下:
function person(name, age) { var o = new Object(); o.name = name; o.age = age; o.sayHello = function () { console.log("hello"); }; return o; } var per = new Person("xiaoming",20) console.log(per.name) // xiaoming console.log(per.sayHello()) // hello
(3)构造函数模式;
JavaScript 中每一个函数都可以作为构造函数,只要是通过new操作符创建的对象,我们就把这个函数称为构造函数,这种模式不需要显示的创建对象,而是直接将属性和方法赋值给 this ,没有 return 语句,注意常用规范需要将构造函数函数名首字母大写。实例如下:
function Person(name, age) { this.name = name; this.age = age; this.sayHello = function () { console.log(this.name); }; } var person = new Person("xiaoming", 18); person.sayHello(); // xiaoming person.constructor == Person; // true person instanceof Object; //true person instanceof Person; //true Peron("xiaohong", 18);//当作普通函数使用 window.sayHello(); //xiaohong
(4)原型模式;
因为每一个函数都有一个 prototype 属性,这个属性值为一个对象,这个对象包含了通过构造函数创建的所有实例能够共享的属性和方法,因此我们可以使用原型对象来添加公共的属性和方法,从而实现代码的复用。这种模式相对于构造函数来说,解决了构造的实例中函数对象复用的问题,但是这种模式也存在一定的问题,首先没有办法通过传入参数来初始化实例的属性,另外如果是一个引用数据类型的值,那么所有实例将共享一个对象,一个实例对引用数据类型的值做改变将会影响到别的实例对该类型的引用。实例如下:
function Person(){} Person.prototype.name='xioming' Person.prototype.sayHello=function(){ console.log(this.name) } var person=new Person() person.sayHello()//xiaoming console.log(Person.prototype.isPrototypeOf(person))//true 因为person对象内部有一个指向Person.prototype的指针,即person的原型指向Person
(5)构造函数和原型组合模式;
组合使用构造函数模式和原型模式是最常见的创建自定义对象的方法,其中构造函数用于创建实例的属性,原型模式用于创建共享的属性和方法。
function Person(name, age) { this.name = name; this.age = age; } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name); }, }; var p = new Person("xiaozhang", 123); console.log(p.sayName()); // xiaozhang
组合使用两种方式,虽然结合了两种模式的优点,但是出现的问题是代码的封装性较差。
(6)动态原型模式;
动态原型模式是将原型方法赋值的创建过程移动到了构造函数内部,通过对属性是否存在的判断,可以实现仅在一次调用函数时对原型对象赋值一次的效果,这种方式很好地对上面的组合模式进行了封装。
function Person(name, age) { this.name = name; this.age = age; if (typeof this.sayHello != "function") { Person.prototype.sayHello = function () { console.log("hello"); }; } }
通过判断实现,在调用函数时对原型对象进行赋值操作,只有sayHello函数不存在时才会把方法放回原型中,初次调用构造函数的试试才会执行。
(7)寄生构造函数模式;
实例方法如下:假设我们呢需要创建一个具有额外方法的特殊数组:
function SpecialArray() { var arr = new Array(); //添加值 arr.push.apply(arr, arguments); //添加方法 arr.toPipedString = function () { return this.join("|"); }; return arr; } var color = new SpecialArray( "red", "blue" ); console.log(color.toPipedString()); //red|blue
在这个函数内部,首先创建了一个数组,然后push()方法(用构造函数接收到的所有参数)初始化了数组的值。随后,又给数组实例添加了一个toPipedString()方法,该方法返回以竖线分割的数组值。最后,将数组以函数值的形式返回。接着,我们调用了SpecialArray构造函数,向其中传入了用于初始化数组的值,此后调用了toPipedString()方法。但似乎返回的对象与构造函数或构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部创建 对象没有什么不同。为此,不能依赖instranceof操作符来确定对象类型。
总结
以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长之路会持续更新一些工作中常见的问题和技术点。
加载全部内容