Ursprünglich wollte ich den letzten Artikel in der Reihe der Ausdrücke von einfach bis tiefgehend fortsetzen, aber in letzter Zeit ist das Team plötzlich beschäftigt, beschäftigter als je zuvor! Aber Freunde, die Ausdrücke mögen, keine Sorge, ich schreibe es bereits :) Bei der Arbeit habe ich festgestellt, dass jeder hier oder da ein wenig Verständnis für einige Grundprinzipien von Javascript hat, also habe ich beschlossen, etwas Zeit damit zu verbringen, diese zu klären Grundkenntnisse erwerben und diese mit allen teilen. Ein PPT für die Schulung wird später beigefügt. Zuerst hatte ich vor, einen Artikel zu schreiben, aber als ich weiter schrieb, fand ich immer mehr, also beschloss ich, eine Serie zu schreiben. Der gesamte Inhalt dieser Serie beinhaltet die Grundlagen von Javascript, es gibt keine ausgefallenen Dinge, aber ich glaube, dass diese grundlegenden Dinge Ihnen helfen werden, die interessanten Dinge zu verstehen.
Dieser Artikel ist der dritte Artikel in der Javascript-Reihe, den Sie kennen müssen. Wir befassen uns hauptsächlich damit, wie Javascript objektorientierte Programmierung ist. Beinhaltet hauptsächlich den folgenden Inhalt:
Objekte in Javascript
Was ist ein Objekt?
Eigenschaften durchqueren
Objekte erstellen
Fabrikmuster
Konstruktormuster
Detaillierte Erklärung dazu
In der Funktion
In der Objektmethode
Im Konstruktor
Im Aufruf und anwenden
In bind
In der Dom-Element-Event-Handler-Funktion
Detaillierte Erklärung des Prototyps
Was ist ein Prototyp?
Was ist die Prototypenkette
Verwendung der Prototypenkette zur Implementierung der Vererbung
Probleme in der Prototypenkette
Objekte in Javascript
Was ist ein Objekt
Wir können Objekte in Javascript als eine Menge ungeordneter Schlüssel-Wert-Paare verstehen, genau wie Dictionary
Grundwert (Zeichenfolge, Zahl, Boolescher Wert, Null, undefiniert)
Objekt
Funktion
var o = new Object(); o["name"] = "jesse"; //基本值作为对象属性 o["location"] = { //对象作为对象属性 "city": "Shanghai", "district":"minhang" }; // 函数 作为对象属性 o["sayHello"] = function () { alert("Hello, I am "+ this.name + " from " + this.location.city); } o.sayHello();
Eigenschaften durchqueren
In C# können wir foreach verwenden, um Dictionary
for (var p in o) { alert('name:'+ p + ' type:' + typeof o[p] ); } // name:name type:string // name:location type:object // name:sayHello type:function
Die obige Traversierungsmethode umfasst auch die Attribute im Prototyp. Wir werden darüber sprechen, was ein Prototyp ist und wie die Attribute im Prototyp und in der folgenden Instanz unterschieden werden können. .
Objekt erstellen
Tatsächlich haben wir oben ein Objekt erstellt und die folgenden zwei Methoden zum Erstellen von Objekten verwendet.
Verwenden Sie new, um eine Instanz von Object zu erstellen.
Literal
Unser o oben wurde auf die erste Weise erstellt, und das Standortattribut in o wurde auf wörtliche Weise erstellt. Die erste Methode hat tatsächlich einen Namen namens Konstruktormuster, da Object eigentlich ein Konstruktor ist, der eine Instanz von Object für uns generiert. Wenn Ihnen der Konstruktor immer noch unklar ist, beeilen Sie sich und lesen Sie meinen ersten Artikel Typgrundlagen Objekt und Objekt.
Zusätzlich zu den beiden oben genannten Methoden werfen wir einen Blick auf einige unserer Möglichkeiten zum Erstellen von Objekten:
Fabrikmuster
function createPerson(name, age, job){ var o = new Object(); o.name = name; o.age = age; o.job = job; o.sayName = function(){ alert(this.name); }; return o; } var person1 = createPerson('Jesse', 29, 'Software Engineer'); var person2 = createPerson('Carol', 27, 'Designer');
Es gibt ein Problem mit den von diesem Modus erstellten Objekten, das heißt, es wird für mich eine Instanz von Object innerhalb der Funktion erstellt. Diese Instanz hat nichts mit unserem Konstruktor createPerson zu tun.
Da ich dieses Objekt intern mit new Object() erstellt habe, ist es eine Instanz von Object. Wenn wir also wissen wollen, von welcher Funktion es eine Instanz ist, ist das unmöglich.
Konstruktormuster
Das Fabrikmuster löst das Problem der Objekterkennung nicht, aber wir können darüber nachdenken, ob Object() tatsächlich eine Funktion ist, aber wenn ich ein neues hinzufüge it wird es zu einem Konstruktor, der eine Instanz von Object für uns generiert. Dann kann ich auch new vor anderen Funktionen hinzufügen, um eine Instanz dieser Funktion zu generieren. Dies ist das sogenannte Konstruktormuster.
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ alert(this.name); }; } var p1 = new Person('Jesse', 18, 'coder'); alert(p1 instanceof Person); // true
Detaillierte Erklärung dazu
Dies kann auch als ein sehr magisches Objekt in Javascript angesehen werden. Ja, das ist ein Objekt. Wir haben im vorherigen Artikel über Variablenobjekte gesprochen. Das Variablenobjekt bestimmt, auf welche Eigenschaften und Funktionen in der aktuellen Ausführungsumgebung zugegriffen werden kann. Stellen Sie sich das als dieses Variablenobjekt vor. Wir haben bereits erwähnt, dass die größte Ausführungsumgebung die globale Ausführungsumgebung ist und das Fenster das variable Objekt in der globalen Ausführungsumgebung ist. Wenn wir also this===window in der globalen Umgebung verwenden, wird true zurückgegeben.
Zusätzlich zur globalen Ausführungsumgebung haben wir auch eine weitere Ausführungsumgebung erwähnt, bei der es sich um eine Funktion handelt. Jede Funktion verfügt über ein This-Objekt, aber manchmal sind die Werte, die sie darstellen, unterschiedlich und werden hauptsächlich vom Aufrufer dieser Funktion bestimmt. Schauen wir uns die folgenden Szenarien an:
Funktion
function f1(){ return this; } f1() === window; // global object
因为当前的函数在全局函数中运行,所以函数中的this对象指向了全局变量对象,也就是window。这种方式在严格模式下会返回undefined。
对象方法
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // logs 37
在对象方法中,this对象指向了当前这个实例对象。注意: 不管这个函数在哪里什么时候或者怎么样定义,只要它是一个对象实例的方法,那么它的this都是指向这个对象实例的。
var o = { prop: 37 }; var prop = 15; function independent() { return this.prop; } o.f = independent; console.log(independent()); // logs 15 console.log(o.f()); // logs 37
区别:上面的函数independent如果直接执行,this是指向全局执行环境,那么this.prop是指向我们的全局变量prop的。但是如果将independent设为对象o的一个属性,那么independent中的this就指向了这个实例,同理this.prop就变成了对象o的prop属性。
构造函数
我们上面讲到了用构造函数创建对象,其实是利用了this的这种特性。在构造函数中,this对象是指向这个构造函数实例化出来的对象。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name); }; } var p1 = new Person('Jesse', 18, 'coder'); var p2 = new Person('Carol',16,'designer');
当我们实例化Person得到p1的时候,this指向p1。而当我们实例化Person得到p2的时候,this是指向p2的。
利用call和apply
当我们用call和apply去调用某一个函数的时候,这个函数中的this对象会被绑定到我们指定的对象上。而call和apply的主要区别就是apply要求传入一个数组作为参数列表。
function add(c, d) { return this.a + this.b + c + d; } var o = { a: 1, b: 3 }; // 第一个参数会被绑定成函数add的this对象 add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 // 第二个参数是数组作为arguments传入方法add add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34
在bind方法中
bind方法是 存在于function的原型中的 Function.prototype.bind,也就是说所有的function都会有这个方法。但我们调用某一个方法的bind的时候,会产生一个和原来那个方法一样的新方法,只不过this是指向我们传得bind的第一个参数。
function f() { return this.a; } var g = f.bind({ a: "azerty" }); console.log(g()); // azerty var o = { a: 37, f: f, g: g }; console.log(o.f(), o.g()); // 37, azerty
在dom元素事件处理器中
在事件处理函数中,我们的this是指向触发这个事件的dom元素的。
HTML代码
<html> <body> <div id="mydiv" style="width:400px; height:400px; border:1px solid red;"></div> <script type="text/javascript" src="essence.js"></script> </body> </html>
JavaScript代码
function click(e) { alert(this.nodeName); } var myDiv = document.getElementById("mydiv"); myDiv.addEventListener('click', click, false);
当我们点击页面那个div的时候,毫无疑问,它是会显示DIV的。
详解prototype
prototype即原型,也是Javascrip中一个比较重要的概念。在说原型之前呢,我们需要回顾一下之前的构造函数模式。在我们用构造函数去创建对象的时候主要是利用了this的特性。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; this.sayName = function () { alert(this.name); }; } var p1 = new Person('Jesse', 18, 'coder'); var p2 = new Person('Carol', 17, 'designer');
我们上面还讲到了当用Person实例化p1的时候Person中的this是指向p1的,当实例化p2的时候呢,this是指向p2的。那也就是说,p1和p2中的sayName虽然起到了同样的作用,但是实际上他们并非是一个函数。
也就是说他们内存堆中是存在多份拷贝的,而不是在栈中引用地址的拷贝。先不说这符不符合面向对象的思想,至少这对于内存来说也是一种浪费。而解决办法就是我们要讨论的原型。
什么是原型
在Javascript中的每一个函数,都会有一个原型对象,这个原型对象和我们普通的对象没有区别。只不过默认会有一个constructor属性指向这个函数。 同时,所有这个函数的实例都会有一个引用指向这个原型对象。如果不太清楚,那就看看下面这张图吧:
以上就是构造函数,构造函数原型,以及实例之间的关系。以我们的Person构造函数为例,所有Person的实例(p1,p2)都舒服一个prototype属性指向了Person构造函数prototype对象。如此一来,我们就可以把方法写在原型上,那么我们所有的实例就会访问同一个方法了。
function Person(name, age, job) { this.name = name; this.age = age; this.job = job; Person.prototype.sayName = function () { alert(this.name); } } var p1 = new Person('Jesse', 18, 'coder'); var p2 = new Person('Carol', 17, 'designer'); alert(p1.sayName == p2.sayName); // true
什么是原型链
大家还记得作用域链么?如果不记得,请自觉到第二篇中去复习(作用域和作用域链)。简单的来说,我们在一个执行环境中访问某个变量的时候如果当前这个执行环境中不存在这个变量,那么会到这个执行环境的包含环境也就是它的外层去找这个变量,外层还找不到那就再外一层,一直找到全局执行环境为止,这就是作用域链。而原型链有点类型,只不过场景换到了我们的对象实例中,如果我在一个实例中找某一个属性,这个实例中没有,那就会到它的原型中去找。记住,我们上面说了,原型也是一个对象,它也有自己的原型对象,所以就行成了一个链,实例自己的原型中找不到,那就到原型的原型对象中去找,一直向上延伸到Object的原型对象,默认我们创建的函数的原型对象它自己的原型对象是指向Object的原型对象的,所以这就是为什么我们可以在我们的自定义构造函数的实例上调用Object的方法(toString, valueOf)。
利用原型实现继承
其实我们上面已经讲了继承在Javascript中的实现,主要就是依靠原型链来实现的。所有的实例是继承自object就是因为在默认情况下,我们所有创建函数的原型对象的原型都指向了object对象。同理,我们可以定义自己的继承关系。
function Person(name, age, job) { this.name = name; this.age = age; } Person.prototype.sayName = function () { alert(this.name); } function Coder(language){ this.language = language; } Coder.prototype = new Person(); //将 Coder 的原型指向一个Person实例实现继Person Coder.prototype.code = function () { alert('I am a '+ this.language +' developer, Hello World!'); } function Designer() { } Designer.prototype = new Person(); //将 Desiger 的原型指向一个Person实例实现继Person Designer.prototype.design = function () { alert('其实我只是一个抠图工而已。。。。'); } var coder = new Coder('C#'); coder.name = 'Jesse'; coder.sayName(); //Jesse coder.code(); // I am a C# developer, Hello World! var designer = new Designer(); designer.name = 'Carol'; designer.sayName(); // Carol designer.design(); // 其实我只是一个抠图工而已。。。。
原型链中的问题
由于原型对象是以引用的方式保存的,所以我们在赋值的时候要特别注意,一不小心就有可能把之前赋的值给赋盖了。比如上面的代码中,我们先写原型方法,再实现继承,那我们的原型方法就没有了。
function Coder(language){ this.language = language; } Coder.prototype.code = function () { alert('I am a '+ this.language +' developer, Hello World!'); } Coder.prototype = new Person(); //这里会覆盖上面所有的原型属性和方法 var coder = new Coder('C#'); coder.name = 'Jesse'; coder.sayName(); coder.code(); // 这里会报错,找不到code方法。
这样三篇文章都完成了
更多Javascript基础回顾之(三) js面向对象相关文章请关注PHP中文网!