Rumah >hujung hadapan web >tutorial js >Analisis ringkas tentang pelbagai mod mencipta objek dalam kemahiran javascript_javascript
Saya sedang membaca "Pengaturcaraan Lanjutan dengan JavaScript" (Edisi Kedua)
Penciptaan objek dalam javascript
•Mod Kilang
•Corak Pembina
•Mod Prototaip
• Gabungkan corak pembina dan prototaip
•Mod dinamik prototaip
Kebanyakan bahasa berorientasikan objek mempunyai konsep kelas, yang melaluinya berbilang objek dengan kaedah dan sifat yang sama boleh dicipta. Walaupun secara teknikalnya, JavaScript adalah bahasa berorientasikan objek, JavaScript tidak mempunyai konsep kelas, semuanya adalah objek. Mana-mana objek ialah contoh jenis rujukan tertentu, yang dibuat melalui jenis rujukan sedia ada, jenis rujukan boleh asli atau disesuaikan. Jenis rujukan asli termasuk: Objek, Tatasusunan, Data, RegExp dan Fungsi. ! Jenis rujukan ialah struktur data yang menyusun data dan kefungsian, selalunya dipanggil kelas. Dalam JavaScript, yang tidak mempunyai konsep kelas, masalah yang perlu diselesaikan ialah cara mencipta objek dengan cekap.
1.1.0 Kaedah am untuk mencipta objek
var person = {}; //对象字面量表示,等同于var person = new Objcect(); person.name = 'evansdiy'; person.age = '22'; person.friends = ['ajiao','tiantian','pangzi']; person.logName = function() { console.log(this.name); }
Berdasarkan jenis rujukan Objek, objek dicipta, yang mengandungi empat sifat, salah satunya ialah kaedah. Jika anda memerlukan banyak contoh objek seperti orang, akan terdapat banyak kod pendua.
1.1.1. Mod kilang [atas]
Buat objek melalui fungsi yang boleh mengandungi butiran objek, dan kemudian kembalikan objek ini.
function person(name,age,friends) { var o = { name: name, age: age, friends: friends, logName: function() { console.log(this.name); } }; return o; } var person1 = person('Evansdiy','22',['ajiao','tiantian','pangzi']);
Setiap kali fungsi orang dipanggil, objek baharu akan dicipta melalui objek o di dalam fungsi, dan kemudian dikembalikan, selain daripada ini, objek dalaman o yang wujud untuk mencipta objek baharu tidak mempunyai tujuan lain. Di samping itu, adalah mustahil untuk menentukan jenis objek yang dicipta oleh corak kilang.
1.1.2. Corak pembina [atas]
function Person(name,age,job) { this.name = name; this.age = age; this.job = job; this.logName = function() { console.log(this.name); } } //通过new操作符创建Person的实例 var person1 = new Person('boy-a','22','worker'); var person2 = new Person('girl-b','23','teacher'); person1.logName(); //boy-a person2.logName(); //girl-a
Membandingkan corak kilang, anda boleh mendapati bahawa tidak perlu mencipta objek perantaraan di sini dan tiada pulangan. Di samping itu, contoh pembina boleh dikenal pasti sebagai jenis tertentu, yang menyelesaikan masalah pengenalan objek (dengan menyemak sifat pembina contoh, atau menggunakan pengendali instanceof untuk memeriksa sama ada contoh itu dicipta melalui pembina tertentu) .
console.log(person1.constructor == Person);//constructor terletak dalam prototaip pembina dan menunjuk kepada pembina, dan hasilnya benar
console.log(person1 instanceof Person);//Gunakan operator instanceof untuk menentukan sama ada person1 ialah instance of constructor Person Walau bagaimanapun, mod pembina juga mempunyai masalahnya sendiri, kaedah logName akan dimulakan semula pada setiap contoh. Perlu diingatkan bahawa kaedah yang dibuat oleh instantiasi adalah tidak sama
console.log(person1.logName == person2.logName);//falseKami boleh menyelesaikan masalah ini dengan mengalihkan kaedah di luar pembina (menjadi fungsi global):
function logName() { console.log(this.name); } function logAge() { console.log(this.age); }
1.1.3. Mod prototaip [atas]
Setiap fungsi dalam JavaScript mengandungi penunjuk kepada atribut prototaip (kebanyakan penyemak imbas boleh mengaksesnya melalui atribut dalaman __proto__ Atribut prototaip ialah objek yang mengandungi semua kejadian yang dibuat oleh jenis rujukan dan kaedah tertentu.
function Person() {} Person.name = 'evansdiy'; Person.prototype.friends = ['ajiao','jianjian','pangzi']; Person.prototype.logName = function() { console.log(this.name); } var person1 = new Person(); person1.logName();//'evansdiy'
Kod di atas melakukan perkara berikut:
1. Fungsi pembina Orang ditakrifkan, dan fungsi Orang secara automatik memperoleh atribut prototaip, yang secara lalai hanya mengandungi atribut pembina yang menunjuk kepada Orang;2. Tambahkan tiga atribut melalui Person.prototype, salah satunya ialah kaedah
3 Buat contoh Orang dan kemudian panggil kaedah logName() pada contoh itu.
Apa yang perlu diperhatikan di sini ialah proses panggilan kaedah logName():
1. Cari kaedah logName() pada contoh person1 dan mendapati bahawa tiada kaedah sedemikian, jadi kami mengesannya kembali ke prototaip person1
2. Cari kaedah logame() pada prototaip person1, jadi memanggil kaedah ini adalah berdasarkan proses carian sedemikian dalam prototaip pada contoh. Atribut dengan nama yang sama Perlu diingat bahawa berbuat demikian tidak akan memadamkan atribut dengan nama yang sama pada prototaip, tetapi hanya menghalang akses contoh.
var person2 = new Person();
person2.name = 'laocai'; Jika kita tidak lagi memerlukan atribut pada instance, kita boleh memadamkannya melalui operator delete.
padam person2.name; Gunakan gelung untuk masuk untuk menghitung semua sifat yang boleh diakses oleh tika (sama ada sifat itu wujud dalam tika atau prototaip):
同时,也可以利用hasOwnProperty()方法判断某个属性到底存在于实例上,还是存在于原型中,只有当属性存在于实例中,才会返回true:
console.log(person1.hasOwnProperty('name'));//true!hasOwnProperty来自Object的原型,是javascript中唯一一个在处理属性时不查找原型链的方法。[via javascript秘密花园] 另外,也可以通过同时使用in操作符和hasOwnProperty()方法来判断某个属性存在于实例中还是存在于原型中:
console.log(('friends' in person1) && !person1.hasOwnProperty('friends'));先判断person1是否可以访问到friends属性,如果可以,再判断这个属性是否存在于实例当中(注意前面的!),如果不存在于实例中,就说明这个属性存在于原型中。 前面提到,原型也是对象,所以我们可以用对象字面量表示法书写原型,之前为原型添加代码的写法可以修改为:
Person.prototype = { name: 'evansdiy', friends: ['ajiao','jianjian','pangzi'], logName: function() { console.log(this.name); } }
由于对象字面量语法重写了整个prototype原型,原先创建构造函数时默认取得的constructor属性会指向Object构造函数:
//对象字面量重写原型之后
console.log(person1.constructor);//Object不过,instanceof操作符仍会返回希望的结果:
//对象字面量重写原型之后
console.log(person1 instanceof Person);//true当然,可以在原型中手动设置constructor的值来解决这个问题。
Person.prototype = { constructor: Person, ...... }
如果在创建对象实例之后修改原型对象,那么对原型的修改会立即在所有对象实例中反映出来:
function Person() {}; var person1 = new Person(); Person.prototype.name = 'evansdiy'; console.log(person1.name);//'evansdiy'
实例和原型之间的连接仅仅是一个指针,而不是一个原型的拷贝,在原型实际上是一次搜索过程,对原型对象的所做的任何修改都会在所有对象实例中反映出来,就算在创建实例之后修改原型,也是如此。 如果在创建对象实例之后重写原型对象,情况又会如何?
function Person() {}; var person1 = new Person1();//创建的实例引用的是最初的原型 //重写了原型 Person.prototype = { friends: ['ajiao','jianjian','pangzi'] } var person2 = new Person();//这个实例引用新的原型 console.log(person2.friends); console.log(person1.friends);
以上代码在执行到最后一行时会出现未定义错误,如果我们用for-in循环枚举person1中的可访问属性时,会发现,里头空无一物,但是person2却可以访问到原型上的friends属性。 !重写原型切断了现有原型与之前创建的所有对象实例的联系,之前创建的对象实例的原型还在,只不过是旧的。
//创建person1时,原型对象还未被重写,因此,原型对象中的constructor还是默认的Person()
console.log(person1.constructor);//Person()
//但是person2的constructor指向Object()
console.log(person2.constructor);//Object()需要注意的是,原型模式忽略了为构造函数传递参数的过程,所有的实例都取得相同的属性值。同时,原型模式还存在着一个很大的问题,就是原型对象中的引用类型值会被所有实例共享,对引用类型值的修改,也会反映到所有对象实例当中。
function Person() {}; Person.prototype = { friends: ['ajiao','tiantian','pangzi'] } var person1 = new Person(); var person2 = new Person(); person1.friends.push('laocai'); console.log(person2.friends);//['ajiao','tiantian','pangzi','laocai']
修改person1的引用类型值friends,意味着person2中的friends也会发生变化,实际上,原型中保存的friends实际上只是一个指向堆中friends值的指针(这个指针的长度是固定的,保存在栈中),实例通过原型访问引用类型值时,也是按指针访问,而不是访问各自实例上的副本(这样的副本并不存在)。
1.1.4.结合构造函数和原型模式创建对象 [top]
结合构造函数和原型模式的优点,弥补各自的不足,利用构造函数传递初始化参数,在其中定义实例属性,利用原型定义公用方法和公共属性,该模式应用最为广泛。
function Person(name,age) { this.name = name; this.age = age; this.friends = ['ajiao','jianjian','pangzi']; } Person.prototype = { constructor: Person, logName: function() { console.log(this.name); } } var person1 = new Person('evansdiy','22'); var person2 = new Person('amy','21'); person1.logName();//'evansdiy' person1.friends.push('haixao'); console.log(person2.friends.length);//3
1.1.5.原型动态模式 [top]
原型动态模式将需要的所有信息都封装到构造函数中,通过if语句判断原型中的某个属性是否存在,若不存在(在第一次调用这个构造函数的时候),执行if语句内部的原型初始化代码。
function Person(name,age) { this.name = name; this.age = age; if(typeof this.logName != 'function') { Person.prototype.logName = function() { console.log(this.name); }; Person.prototype.logAge = function() { console.log(this.age); }; }; } var person1 = new Person('evansdiy','22');//初次调用构造函数,此时修改了原型 var person2 = new Person('amy','21');//此时logName()方法已经存在,不会再修改原型
需要注意的是,该模式不能使用对象字面量语法书写原型对象(这样会重写原型对象)。若重写原型,那么通过构造函数创建的第一实例可以访问的原型对象不会包含if语句中的原型对象属性。
function Person(name,age) { this.name = name; this.age = age; if(typeof this.logName != 'function') { Person.prototype = { logName: function() { console.log(this.name); }, logAge: function() { console.log(this.Age); } } }; } var person1 = new Person('evansdiy','22'); var person2 = new Person('amy','21'); person2.logName();//'amy' person1.logName();//logName()方法不存在
需要说明的是,各模式都有自己的应用场景,无所谓优劣。
以上这篇浅析在javascript中创建对象的各种模式就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。