Allgemein geschrieben:
function add(a,b) { return a + b; } alert(add(1,2)); // 结果 3
Wenn wir eine Funktion wie diese definieren, wird der Funktionsinhalt kompiliert (aber nicht sofort ausgeführt, es sei denn, wir geh und ruf es an). Darüber hinaus wissen Sie vielleicht nicht, dass beim Erstellen dieser Funktion auch ein Objekt mit demselben Namen erstellt wird. Für unser Beispiel haben wir jetzt ein Objekt namens „add“ (weitere Informationen finden Sie im Abschnitt „Funktionen: Objekte“ weiter unten).
Anonyme Funktionen:
Wir können auch A zuweisen Der Variablenname wird der anonymen Funktion gegeben, um sie zu definieren.
var add = function(a,b) { return a + b; } alert(add(1,2)); // 结果 3
Dieser Code macht dasselbe wie das vorherige Beispiel. Vielleicht sieht die Syntax seltsam aus, aber sie sollte Ihnen ein besseres Gefühl dafür vermitteln, dass es sich bei der Funktion um ein Objekt handelt, und wir haben diesem Objekt gerade einen Namen zugewiesen. Sie können es sich als dieselbe Anweisung wie var myVar=[1,2,3] vorstellen. Auf diese Weise deklarierte Funktionsinhalte werden ebenfalls kompiliert.
Wenn wir eine solche Funktion zuweisen, ist nicht unbedingt eine anonyme Funktion erforderlich. Hier mache ich dasselbe wie oben, füge jedoch den Funktionsnamen „theAdd“ hinzu und kann auf die Funktion verweisen, indem ich den Funktionsnamen oder diese Variable aufrufe.
var add = function theAdd(a,b) { return a + b; } alert(add(1,2)); // 结果 3 alert(theAdd(1,2)); // 结果也是 3
Die Verwendung dieser Methode zum Definieren von Funktionen ist in der objektorientierten Programmierung sehr nützlich, da wir eine Funktion in ein Objekt wie die folgenden Eigenschaften umwandeln können.
var myObject = new Object(); myObject.add = function(a,b){return a+b}; // myObject 现在有一个叫做“add”的属性(或方法)” // 而且我能够象下面这样使用它 myObject.add(1, 2);
Funktion: Objekt
Funktion ist eine spezielle Form eines Objekts in Javascript. Es ist der erste [b]-Klassendatentyp. Das bedeutet, dass wir ihm Eigenschaften hinzufügen können. Hier sind einige interessante Punkte, die Sie beachten sollten
Objekterstellung
Wie gerade erwähnt, erstellt JavaScript hinter den Kulissen tatsächlich ein Objekt für Sie, wenn wir eine Funktion definieren. Der Name dieses Objekts ist der Funktionsname selbst. Der Typ dieses Objekts ist Funktion. Im folgenden Beispiel ist es uns vielleicht nicht bewusst, aber wir haben tatsächlich ein Objekt erstellt: Es heißt Ball.
function ball() // 也许看起来有点奇怪,但是这个声明 { // 创建了一个叫做Ball的对象 i = 1; } alert(typeof ball); // 结果 "function"
Wir können sogar den Inhalt dieses Objekts drucken und es gibt den tatsächlichen Code der Funktion aus
alert(ball); //结果为: //function ball() //{ // i = 1; //}
Attribute hinzufügen
Wir können Attribute zu Objekten hinzufügen, einschließlich Objektfunktionen. Denn der Kern der Definition einer Funktion besteht darin, ein Objekt zu erstellen. Wir können Funktionen „heimlich“ Eigenschaften hinzufügen. Beispielsweise definieren wir hier die Funktion Ball und fügen das Attribut callsign hinzu.
function Ball() // 也许看起来有点奇怪,但是这个声明创建了一个叫做Ball的对象,而且你能够引用它或者象下面那样给它增加属性 { } ball.callsign="The ball"; // 给Ball增加属性 alert(ball.callsign); // 输出 "The ball"
Zeiger
Da eine Funktion ein Objekt ist, können wir einer Funktion einen Zeiger zuweisen. Wie im folgenden Beispiel zeigt die Variable ptr auf das Objekt myFunction.
function myFunction(message) { alert(message); } var ptr=myFunction; // ptr指向了myFunction ptr("hello"); // 这句会执行myFunction:输出"hello"
Wir können diese Funktion so ausführen, als ob der Funktionsname durch einen Zeigernamen ersetzt worden wäre. Im obigen Beispiel ist die Bedeutung dieser Zeile ptr("hello"); und myFunction("hello");
Zeiger auf Funktionen sind in der objektorientierten Programmierung sehr nützlich. Zum Beispiel: Wenn wir mehrere Objekte haben, die auf dieselbe Funktion zeigen (wie folgt):
function sayName(name) { alert(name); } var object1=new Object(); // 创建三个对象 var object2=new Object(); var object3=new Object(); object1.sayMyName=sayName; // 将这个函数指派给所有对象 object2.sayMyName=sayName; object3.sayMyName=sayName; object1.sayMyName("object1"); // 输出 "object1" object2.sayMyName("object2"); // 输出 "object2" object3.sayMyName("object3"); // 输出 "object3"
Weil nur der Zeiger gespeichert wird (nicht die Funktion selbst). ) Wenn wir das Funktionsobjekt selbst ändern, ändern sich alle Zeiger auf diese Funktion. Wir können unten sehen:
function myFunction() { alert(myFunction.message); } myFunction.message="old"; var ptr1=myFunction; // ptr1 指向 myFunction var ptr2=myFunction; // ptr2 也指向 myFunction ptr1(); // 输出 "old" ptr2(); // 输出 "old" myFunction.message="new"; ptr1(); // 输出 "new" ptr2();
Zeiger zeigt auf
Wir können eine Funktion neu zuweisen, nachdem sie erstellt wurde, aber wir brauchen einen Zeiger auf das Funktionsobjekt selbst, nicht auf einen Zeiger darauf. Im folgenden Beispiel werde ich den Inhalt von myfunction() ändern.
function myFunction() { alert("Old"); } myFunction(); // 输出 "Old" myFunction=function() { alert("New"); }; myFunction(); // 输出 "New"
Wo sind die alten Funktionen? ? Verlassen.
Wenn wir es behalten müssen, können wir ihm einen Zeiger zuweisen, bevor wir es ändern.
function myFunction() { alert("Old"); } var savedFuncion=myFunction; myFunction=function() { alert("New"); }; myFunction(); // 输出 "New" savedFuncion(); // 输出 "Old"
Inline-Funktion
function get(a,b,c) { function cal(n) { return n/2; } var result = “”; result+=cal(a)+” ”; result+=cal(b)+” ”; result+=cal(c); } var resultString = get(10,20,30); alert(resultString); // 输出 "5 10 15"
Sie können es nur intern verwenden Rufen Sie verschachtelte Funktionen auf. Das heißt, Sie können Folgendes nicht aufrufen:
getHalfOf.calculate(10), da „calculate“ nur existiert, wenn die externe Funktion (getHalfOf()) ausgeführt wird. Dies steht im Einklang mit unserer vorherigen Diskussion (die Funktion wird kompiliert, aber nur ausgeführt, wenn Sie sie aufrufen).
Welche Funktion wird aufgerufen?
Möglicherweise denken Sie über Namenskonflikte nach. Welche der folgenden Funktionen namens „Berechnen“ wird beispielsweise aufgerufen?
function calculate(number) { return number/3; } function getHalfOf(num1, num2, num3) { function calculate(number) { return number/2; } var result=""; result+=calculate(num1)+" "; result+=calculate(num2)+" "; result+=calculate(num3); } var resultString=getHalfOf(10,20,30); alert(resultString); // 输出 "5 10 15"
In diesem Beispiel durchsucht der Compiler zunächst die lokale Speicheradresse und verwendet daher die integrierte Berechnungsfunktion. Wenn wir die Inline-Berechnungsfunktion (lokal) löschen, verwendet dieser Code die globale Berechnungsfunktion.
Funktionen: Datentypen und Konstruktoren
Werfen wir einen Blick auf eine weitere Besonderheit von Funktionen – wodurch sie sich stark von anderen Objekttypen unterscheiden. Eine Funktion kann als Blaupause für einen Datentyp verwendet werden. Diese Funktion wird häufig in der objektorientierten Programmierung verwendet, um benutzerdefinierte Datentypen zu simulieren. Objekte, die mit benutzerdefinierten Datentypen erstellt wurden, werden normalerweise als benutzerdefinierte Objekte bezeichnet.
Datentyp
在定义了一个函数之后,我们也同时创建了一个新的数据类型。这个数据类型能够用来创建一个新对象。下例,我创建了一个叫做Ball的新数据类型。
function Ball() { } var ball0=new Ball(); // ball0 现在指向一个新对象 alert(ball0); // 输出 "Object",因为 ball0 现在是一个对象
这样看来,ball0=new Ball()作了什么?new关键字创建了一个类型是Object的新对象(叫做ball0)。然后它会执行Ball(),并将这个引用传给ball0(用于调用对象)。下面,你会看到这条消息:“creating new Ball”,如果Ball()实际上被运行的话。
function Ball(message) { alert(message); } var ball0=new Ball("creating new Ball"); // 创建对象并输出消息 ball0.name="ball-0"; // ball0现在有一个属性:name alert(ball0.name); // 输出 "ball-0"
我们可以把上面这段代码的第6行看做是底下的代码6-8行的一个简写:
function Ball(message) { alert(message); } var ball0=new Object(); ball0.construct=Ball; ball0.construct("creating new ball"); // 执行 ball0.Ball ("creating.."); ball0.name="ball-0"; alert(ball0.name);
这行代码ball0.construct=Ball和以上中的ptr=myFunction语法一致。
添加属性
当我们象上面那样使用关键字new创建一个对象的时候,一个新的Object被创建了。我们可以在创建之后给这个对象添加属性(就好像我在上面那样添加属性name。而接下来的问题就是如果我们创建了这个对象的另外一个实例,我们得象下面那样再次给这个新对象添加这个属性。)
function Ball() { } var ball0=new Ball(); // ball0 现在指向了类型Ball的一个新实例 ball0.name="ball-0"; // ball0 现在有一个属性"name" var ball1=new Ball(); ball1.name="ball-1"; var ball2=new Ball(); alert(ball0.name); // 输出 "ball-0" alert(ball1.name); // 输出 "ball-1" alert(ball2.name); // 哦,我忘记给ball2添加“name”了!
我忘记给ball2添加属性name了,如果在正式的程序中这也许会引发问题。有什么好办法可以自动增加属性呢?嗯,有一个:使用this关键字。this这个词在function中有特别的意义。它指向了调用函数的那个对象。让我们看看下面的另一个示例,这时候我们在构造函数中添加上这些属性:
function Ball(message, specifiedName) { alert(message); this.name=specifiedName; } var ball0=new Ball("creating new Ball", "Soccer Ball"); alert(ball0.name); // prints "Soccer Ball"
请记住:是new关键字最终使得构造函数被执行。在这个例子中,它将会运行Ball("creating new Ball", "Soccer Ball");而关键字this将指向ball0。
因此,这行:this.name=specifiedName变成了ball0.name="Soccer Ball"。它主要是说:给ball0添加属性name,属性值是Soccer Ball。
我们现在只是添加了一个name属性给ball0,看起来和上一个例子中所做的很象,但却是一个更好更具扩展性的方法。现在,我们可以随心所欲的创建许多带有属性的ball而无需我们手动添加它们。而且,人们也希望创建的Ball对象能够清晰的看懂它的构造函数并且能够轻松找出Ball的所有属性。让我们添加更多属性到Ball里。
function Ball(color, specifiedName, owner, weight) { this.name=specifiedName; this.color=color; this.owner=owner; this.weight=weigth; } var ball0=new Ball("black/white", "Soccer Ball", "John", 20); var ball1=new Ball("gray", "Bowling Ball", "John", 30); var ball2=new Ball("yellow", "Golf Ball", "John", 55); var balloon=new Ball("red", "Balloon", "Pete", 10); alert(ball0.name); // 输出 "Soccer Ball" alert(balloon.name); // 输出 "Balloon" alert(ball2.weight); // 输出 "55"
嘿!使用面向对象术语,你能够说Ball是一个拥有如下属性的对象类型:name,color, owner, weight。
将对象赋给属性我们并没被限制只能添加形如字符串或者数字之类的简单数据类型作为属性。我们也能够将对象赋给属性。下面,supervisor是Employee的一个属性.
function Employee(name, salary, mySupervisor) { this.name=name; this.salary=salary; this.supervisor=mySupervisor; } var boss=new Employee("John", 200); var manager=new Employee("Joan", 50, boss); var teamLeader=new Employee("Rose", 50, boss); alert(manager.supervisor.name+" is the supervisor of "+manager.name); alert(manager.name+"\'s supervisor is "+manager.supervisor.name);
函数也是一个对象。所以你可以让一个函数作为一个对象的一个属性。下面,我将添加两个函数getSalary和addSalary。
function Employee(name, salary) { this.name=name; this.salary=salary; this.addSalary=addSalaryFunction; this.getSalary=function() { return this.salary; }; } function addSalaryFunction(addition) { this.salary=this.salary+addition; } var boss=new Employee("John", 200000); boss.addSalary(10000); // boss 长了 10K 工资……为什么老板工资可以长这么多:'( alert(boss.getSalary()); // 输出 210K……为什么默认工资也那么高……:'( addSalary和getSalary演示了几种将函数赋给属性的不同方法。 如前面数次提到的,一个函数声明的结果是一个对象 被创建。 function Employee(name, salary) { this.name=name; this.salary=salary; this.addSalary=addSalaryFunction; this.getSalary=function() { return this.salary; }; } function addSalaryFunction(addition) { this.salary=this.salary+addition; } var boss=new Employee("John", 200000); var boss2=new Employee("Joan", 200000); var boss3=new Employee("Kim", 200000);
当你创建这个对象的更多实例时(boss2和boss3),每一个实例都有一份getSalary代码的单独拷贝;而与此相反,addSalary则指向了同一个地方(即addSalaryFunction)。
看看下面的代码来理解一下上面所描述的内容。
function Employee(name, salary) { this.name=name; this.salary=salary; this.addSalary=addSalaryFunction; this.getSalary=function() { return this.salary; }; } function addSalaryFunction(addition) { this.salary=this.salary+addition; } var boss1=new Employee("John", 200000); var boss2=new Employee("Joan", 200000); // 给getSalary函数对象添加属性 boss1.getSalary.owner="boss1"; boss2.getSalary.owner="boss2"; alert(boss1.getSalary.owner); // 输出 "boss1" alert(boss2.getSalary.owner); // 输出 "boss2" // 如果两个对象指向同一个函数对象,那么 上面两个输出都应该是“boss2”。 // 给addSalary函数对象添加属性 boss1.addSalary.owner="boss1"; boss1.addSalary.owner="boss2"; alert(boss1.addSalary.owner); // 输出 "boss2" alert(boss2.addSalary.owner); // 输出 "boss2" // 因为两个对象都指向同一个函数 // 当修改其中一个的时候,会影响所有的实例(所以两个都输出“boss2”).
也许不是重要的事情,但这里有一些关于运行类似上面的getSalary的内嵌函数的结论:
1) 需要更多的存储空间来存储对象(因为每一个对象实例都会有它自己的getSalary代码拷贝);
2) javascript需要更多时间来构造这个对象。
让我们重新写这个示例来让它更有效率些。
function Employee(name, salary) { this.name=name; this.salary=salary; this.addSalary=addSalaryFunction; this.getSalary=getSalaryFunction; } function getSalaryFunction() { return this.salary; } function addSalaryFunction(addition) { this.salary=this.salary+addition; }
看这儿,两个函数都指向同一个地方,这将会节约空间和缩短构造时间(特别是当你有一大堆内嵌函数在一个构造函数的时候)。这里有另外一个函数的功能能够来提升这个设计,它叫做prototype,而我们将在下一节讨论它。
函数:原型
每一个构造函数都有一个属性叫做原型(prototype,下面都不再翻译,使用其原文)。这个属性非常有用:为一个特定类声明通用的变量或者函数。
prototype的定义
你不需要显式地声明一个prototype属性,因为在每一个构造函数中都有它的存在。你可以看看下面的例子:
function Test() { } alert(Test.prototype); // 输出 "Object"
给prototype添加属性
就如你在上面所看到的,prototype是一个对象,因此,你能够给它添加属性。你添加给prototype的属性将会成为使用这个构造函数创建的对象的通用属性。
例如,我下面有一个数据类型Fish,我想让所有的鱼都有这些属性:
livesIn="water"和price=20;为了实现这个,我可以给构造函数Fish的prototype添加那些属性。
function Fish(name, color) { this.name=name; this.color=color; } Fish.prototype.livesIn="water"; Fish.prototype.price=20;
接下来让我们作几条鱼:
var fish1=new Fish("mackarel", "gray"); var fish2=new Fish("goldfish", "orange"); var fish3=new Fish("salmon", "white");
再来看看鱼都有哪些属性:
for (int i=1; i<=3; i++) { var fish=eval("fish"+i); // 我只是取得指向这条鱼的指针 alert(fish.name+","+fish.color+","+fish.livesIn+","+fish.price); }
输出应该是:
"mackarel, gray, water, 20" "goldfish, orange, water, 20" "salmon, white water, 20"
你看到所有的鱼都有属性livesIn和price,我们甚至都没有为每一条不同的鱼特别声明这些属性。这时因为当一个对象被创建时,这个构造函数将会把它的属性prototype赋给新对象的内部属性__proto__。这个__proto__被这个对象用来查找它的属性。
你也可以通过prototype来给所有对象添加共用的函数。这有一个好处:你不需要每次在构造一个对象的时候创建并初始化这个函数。
用prototype给对象添加函数
function Employee(name, salary) { this.name=name; this.salary=salary; } Employee.prototype.getSalary=function getSalaryFunction() { return this.salary; } Employee.prototype.addSalary=function addSalaryFunction(addition) { this.salary=this.salary+addition; }
我们可以象通常那样创建对象:
var boss1=new Employee("Joan", 200000); var boss2=new Employee("Kim", 100000); var boss3=new Employee("Sam", 150000);
并验证它:
alert(boss1.getSalary()); // 输出 200000 alert(boss2.getSalary()); // 输出 100000 alert(boss3.getSalary()); // 输出 150000
这里有一个图示来说明prototype是如何工作的。这个对象的每一个实例(boss1, boss2, boss3)都有一个内部属性叫做__proto__,这个属性指向了它的构造器 (Employee)的属性prototype。当你执行getSalary或者addSalary的时候,这个对象会在它的__proto__找到并执行这个代码。