Rumah  >  Artikel  >  hujung hadapan web  >  Kajian mendalam prototaip prototaip dalam pengetahuan JavaScript_Basic

Kajian mendalam prototaip prototaip dalam pengetahuan JavaScript_Basic

WBOY
WBOYasal
2016-05-16 15:45:231004semak imbas

Javascript ialah bahasa pengaturcaraan berasaskan prototaip, yang sangat berbeza daripada pengaturcaraan berasaskan kelas biasa saya akan menyenaraikan perkara penting seperti berikut:

1. Fungsi ialah objek kelas pertama, yang bermaksud fungsi dan objek mempunyai status bahasa yang sama
2. Tiada kelas, hanya objek
3. Fungsi juga adalah sejenis objek, yang dipanggil objek fungsi
4. Objek diluluskan melalui rujukan
Jadi bagaimana bahasa pengaturcaraan berasaskan prototaip ini melaksanakan pewarisan (elemen asas OO), yang merupakan asal prototaip.

Lihat coretan kod di bawah:

function foo(a, b, c)
{
return a*b*c;
}
alert(foo.length);
alert(typeof foo.constructor);
alert(typeof foo.call);
alert(typeof foo.apply);
alert(typeof foo.prototype);

Untuk kod di atas, selepas menjalankannya dalam pelayar anda akan dapati:

1.panjang: Menyediakan bilangan parameter fungsi
2.prototaip: ialah objek
3. Tiga lagi adalah fungsi
Untuk pengisytiharan mana-mana fungsi, ia akan mempunyai 5 sifat (kaedah atau atribut) yang dinyatakan di atas.

Mari kita lihat prototaipnya.

// prototype
function Person(name, gender)
{
this.name = name;
this.gender = gender;
this.whoAreYou = function(){//这个也是所谓的closure, 内部函数可以访问外部函数的变量
var res = "I'm " + this.name + " and I'm a " + this.gender +".";
return res;
};
}
// 那么在由Person创建的对象便具有了下面的几个属性
Person.prototype.age = 24;
Person.prototype.getAge = function(){
return this.age;
};
flag = true;
if (flag)
{
var fun = new Person("Tower", "male");
alert(fun.name);
alert(fun.gender);
alert(fun.whoAreYou());
alert(fun.getAge());
}
Person.prototype.salary = 10000;
Person.prototype.getSalary = function(){
return this.name + " can earn about " + this.salary + "RMB each month." ;
};
// 下面就是最神奇的地方, 我们改变了Person的prototype,而这个改变是在创建fun之后
// 而这个改变使得fun也具有了相同的属性和方法
// 继承的意味即此
if (flag)
{
alert(fun.getSalary());
alert(fun.constructor.prototype.age);//而这个相当于你直接调用 Person.prototype.age
alert(Person.prototype.age);
}

Daripada contoh di atas, kita boleh mendapati bahawa kita boleh menambah kaedah atau atribut prototaip secara dinamik, dan objek yang dicipta olehnya akan mewarisi kaedah dan atribut yang berkaitan secara automatik.

Selain itu, setiap objek mempunyai atribut pembina, yang digunakan untuk menunjuk ke objek fungsi yang menciptanya Sebagai contoh, fun.constructor dalam contoh di atas menunjukkan kepada Person.

Kemudian persoalan secara semula jadi timbul, apakah perbezaan antara kaedah dan atribut yang diisytiharkan oleh objek fungsi dan objek yang diisytiharkan oleh prototaip?

Terdapat beberapa perbezaan:

1. Kaedah dan atribut yang diisytiharkan oleh anda sendiri adalah statik, yang bermaksud bahawa jika anda cuba menambah kaedah baharu atau mengubah suai kaedah sedia ada selepas mengisytiharkannya, ia tidak akan menjejaskan objek yang dibuat oleh mereka, dan ia tidak akan menjejaskan objek yang dicipta. oleh mereka. Iaitu, warisan gagal
2. Prototaip boleh menambah kaedah baharu atau mengubah suai kaedah sedia ada secara dinamik, jadi ia adalah dinamik Sebaik sahaja objek fungsi induk mengisytiharkan atribut prototaip yang berkaitan, objek yang dicipta olehnya akan mewarisi atribut prototaip ini secara automatik.
Meneruskan contoh di atas:

flag = true;
// 函数内部声明的方法是静态的,无法传递的
Person.school = "ISCAS";
Person.whoAreYou = function(){
return "zhutao";
};//动态更改声明期的方法,并不会影响由其创建的对象的方法, 即所谓的 静态
if (flag)
{
alert(Person.school);
alert(fun.school);//输出的是 "undefined"
alert(Person.whoAreYou()); //输出 zhutao
alert(fun.whoAreYou()); // I'm Tower and I'm a male.
}
Person.prototype.getSalary = function(){
return "I can earn 1000000 USD";
};
if (flag)
{
alert(fun.getSalary());//已经继承了改变, 即所谓的 动态
}

Memandangkan terdapat atribut objek fungsi itu sendiri dan atribut prototaip, bagaimanakah objek yang dicipta olehnya mencari atribut yang sepadan?

Pada asasnya ikut proses dan urutan di bawah.

1. Mula-mula cari sifat objek fungsi itu sendiri, dan laksanakannya dengan segera jika ditemui
2. Jika 1 tidak dijumpai, ia akan mencari atribut prototaip Terdapat dua hasil Jika ia dijumpai, ia akan dilaksanakan secara langsung, ia akan terus mencari prototaip objek induk sehingga ia ditemui atau mencapai penghujung rantai prototaip (penghujungnya akan menjadi objek Objek )
Di atas juga menjawab penyelesaian jika sifat objek fungsi itu sendiri adalah sama dengan sifat prototaip (nama pendua), objek fungsi itu sendiri diutamakan.

Contoh tipikal prototaip

Rakan yang pernah menggunakan perpustakaan jQuery atau Prototaip mungkin tahu bahawa perpustakaan ini biasanya mempunyai kaedah trim.

Contoh:

String.prototype.trim = function() {
 return this.replace(/^\s+|\s+$/g, '');
};

penggunaan trim:

' foo bar '.trim(); // 'foo bar'

Tetapi terdapat satu lagi kelemahan dalam melakukan ini, kerana enjin JavaScript dalam versi penyemak imbas yang lebih baharu itu sendiri menyediakan kaedah pemangkasan dalam objek String, jadi pemangkasan yang kami tentukan akan menimpa pemangkasannya sendiri. Sebenarnya, sebelum kita menentukan kaedah trim, kita boleh melakukan ujian mudah untuk melihat sama ada kita perlu menambah kaedah ini sendiri:

if(!String.prototype.trim) {
 String.prototype.trim = function() {
 return this.replace(/^\s+|\s+$/g, '');
 };
}

Rantai Prototaip

Apabila mana-mana objek ditakrifkan atau digunakan dalam JavaScript, ia akan ditambah dengan atribut tersembunyi yang dipanggil __proto__ dan rantai prototaip bergantung pada atribut ini untuk membentuk. Tetapi jangan sekali-kali mengakses atribut __proto__ secara langsung, kerana sesetengah penyemak imbas tidak menyokong akses terus kepadanya. Selain itu, __proto__ dan sifat prototaip sesuatu objek bukanlah perkara yang sama. Mereka masing-masing mempunyai tujuan tersendiri.

Bagaimana untuk memahami? Sebenarnya, apabila kita mencipta fungsi myObject, kita sebenarnya mencipta objek jenis Fungsi:

console.log(typeof myObject); // fungsi

Perlu diperhatikan di sini bahawa Function ialah objek yang dipratentukan dalam JavaScript, jadi ia juga mempunyai atribut yang dipratentukan sendiri (seperti panjang dan argumen) dan kaedah (seperti panggil dan gunakan Sudah tentu, ia juga mempunyai __proto__ to). melaksanakan rantaian prototaip. Dalam erti kata lain, mungkin terdapat coretan kod yang serupa dengan yang berikut dalam enjin JavaScript:

Function.prototype = {
 arguments: null,
 length: 0,
 call: function() {
 // secret code
 },
 apply: function(){
 // secret code
 },
 ...
};

Malah, kod enjin JavaScript tidak boleh begitu mudah. ​​Berikut ialah penerangan tentang cara rantai prototaip berfungsi.

Kami mentakrifkan fungsi myObject, yang juga mempunyai nama parameter, tetapi tidak memberikannya apa-apa sifat lain, seperti panjang atau kaedah lain, seperti panggilan. Jadi mengapa kod berikut dilaksanakan secara normal?

console.log(myObject.length); // 结果:1,是参数的个数

这是因为我们定义 myObject 时,同时也给它定义了一个 __proto__ 属性,并赋值为 Function.prototype(参考前面的代码片段),所以我们能够像访问其它属性一样访问 myObject.length,即使我们并没有定义这个属性,因为它会顺着 __proto__ 原型链往上去找 length,最终在 Function 里面找到了。

那为什么找到的 length 属性的值是 1,而不是 0 呢,是什么时候给它赋值的呢?由于 myObject 是 Function 的一个实例:

console.log(myObject instanceof Function); // true
console.log(myObject === Function); // false

当实例化一个对象的时候,对象的 __proto__ 属性会被赋值为其构造者的原型对象,在本示例中就是 Function,此时构造器回去计算参数的个数,改变 length 的值。

console.log(myObject.__proto__ === Function.prototype); // true

而当我们用 new 关键字创建一个新的实例时,新对象的 __proto__ 将会被赋值为 myObject.prototype,因为现在的构造函数为 myObject,而非 Function。

var myInstance = new myObject('foo');
console.log(myInstance.__proto__ === myObject.prototype); // true

新对象除了能访问 Function.prototype 中继承下来的 call 和 apply 外,还能访问从 myObject 中继承下来的 getName 方法:

console.log(myInstance.getName()); // foo
 
var mySecondInstance = new myObject('bar');
 
console.log(mySecondInstance.getName()); // bar
console.log(myInstance.getName()); // foo

其实这相当于把原型对象当做一个蓝本,然后可以根据这个蓝本创建 N 个新的对象。

再看一个多重prototype链的例子:

// 多重prototype链的例子
function Employee(name)
{
this.name = "";
this.dept = "general";
this.gender = "unknown";
}
function WorkerBee()
{
this.projects = [];
this.hasCar = false;
}
WorkerBee.prototype = new Employee; // 第一层prototype链
function Engineer()
{
this.dept = "engineer"; //覆盖了 "父对象"
this.language = "javascript";
}
Engineer.prototype = new WorkerBee; // 第二层prototype链
var jay = new Engineer("Jay");
if (flag)
{
alert(jay.dept); //engineer, 找到的是自己的属性
alert(jay.hasCar); // false, 搜索到的是自己上一层的属性
alert(jay.gender); // unknown, 搜索到的是自己上二层的属性
}

上面这个示例的对象关系如下:

201581395745486.jpg (222×362)

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn