Wie andere Hochsprachen hat auch JavaScript das neue Schlüsselwort, das wir zum Erstellen von Instanzobjekten einer Klasse verwenden, aber in js ist alles ein Objekt Tatsache ist, dass das neue Schlüsselwort js nicht zum Erstellen eines Instanzobjekts einer Klasse, sondern zur Vererbung verwendet wird. Als nächstes führt Sie dieser Artikel dazu, das Geheimnis des Neuen in JS zu erkunden...
function Animal(name){ this.name = name; } Animal.color = "black"; Animal.prototype.say = function(){ console.log("I'm " + this.name); }; var cat = new Animal("cat"); console.log( cat.name, //cat cat.height //undefined ); cat.say(); //I'm cat console.log( Animal.name, //Animal Animal.color //back ); Animal.say(); //Animal.say is not a function
Wenn Sie die obige Ausgabe verstehen können, bedeutet dies, dass Sie bereits ein gutes Verständnis für den Funktionsmechanismus von new und dies in js haben. Bitte ignorieren Sie diesen Artikel!
Wir werden Ihr Verständnis von Neu und Vererbung in js vertiefen, indem wir dieses Beispiel analysieren [Wenn Sie dies von js nicht verstehen, lesen Sie bitte zuerst: JS-Bereich und dieses Schlüsselwort]
1. Codeinterpretation
Die Zeilen 1–3 erstellen eine Funktion „Animal“ und definieren das Attribut „name“ darauf. Der Wert von „name“ ist der formale Parameter, wenn die Funktion ausgeführt wird.
Zeile 4 definiert ein statisches Attribut: Farbe für das Animal-Objekt (Animal selbst ist ein Funktionsobjekt) und weist den Wert „schwarz“ zu
Die Zeilen 5–7 definieren eine say()-Methode für den Prototyp-Objektprototyp der Animal-Funktion. Die say-Methode gibt den Namenswert dieser Funktion aus.
Zeile 8 erstellt über das Schlüsselwort new ein neues Objekt cat
In den Zeilen 10–14 versucht das Katzenobjekt, auf die Namens- und Farbattribute zuzugreifen und ruft die Say-Methode auf.
Die Zeilen 16–20 des Animal-Objekts versuchen, auf die Namens- und Farbeigenschaften zuzugreifen und die Say-Methode aufzurufen.
2. Schlüsselanalyse
Zeile 8 des Codes ist der Schlüssel:
var cat = new Animal("cat");
Die JS-Engine hat bei der Ausführung dieses Codes viel Arbeit geleistet. Der Pseudocode wird verwendet, um den Workflow wie folgt zu simulieren:
var obj = {}; obj.__proto__ = Animal.prototype; var result = Animal.call(obj,"cat"); return typeof result === 'obj'? result : obj;
(1)创建一个空对象obj;
(2)把obj的__proto__ 指向Animal的原型对象prototype,此时便建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null
【如果你不了解JS原型链,请先阅读:JS原型和原型链】
(3)在obj对象的执行空间调用Animal函数并传递参数“cat”。 相当于var result = obj.Animal("cat")。
当这句执行完之后,obj便产生了属性name并赋值为"cat"。【关于JS中call的用法请阅读:JS的call和apply】
(4)考察第3步返回的返回值,如果无返回值或者返回一个非对象值,则将obj返回作为新对象;否则会将返回值作为新对象返回。
了解了new的运行机制后,我们知道cat其实就是过程(4)的返回值,因此我们对cat对象的认知就多了一些:
cat的原型链是:obj->Animal.prototype->Object.prototype->null
cat上新增了一个属性:name
分析完了cat的产生过程,我们再看看输出结果:
cat.name -> 在过程(3)中,obj对象就产生了name属性。因此cat.name就是这里的obj.name
cat.color -> cat会先查找自身的color,没有找到便会沿着原型链查找,在上述例子中,我们仅在Animal对象上定义了color,并没有在其原型链上定义,因此找不到。
cat.say -> cat会先查找自身的say方法,没有找到便会沿着原型链查找,在上述例子中,我们在Animal的prototype上定义了say,因此在原型链上找到了say方法。
另外,在say方法中还访问this.name,这里的this指的是其调用者obj,因此输出的是obj.name的值。
对于Animal来说,它本身也是一个对象,因此,它在访问属性和方法时也遵守上述查找规则,所以:
Animal.color -> "black"
Animal.name -> "Animal" , Animal先查找自身的name,找到了name,注意:但这个name不是我们定义的name,而是函数对象内置的属性。
一般情况下,函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象)。
Animal.say -> Animal在自身没有找到say方法,也会沿着其原型链查找,话说Animal的原型链是什么呢?
从调试结果看:Animal的原型链是这样的:
Animal->Function.prototype->Object.prototype->null
因此Animal的原型链上没有定义say方法!
总结一下,javascript的new关键字主要的作用是继承,上面例子中,cat对象在产生时便继承了Animal中定义的方法和属性,因此cat不是Animal的实例而是其子类(不严谨的说法)。可能有人还会想:cat既然是new出来的,那cat和Animal应该是同类型的。我认为既然是父类和子类的关系,那就不可能是同类型,不信,你看:
javascript 使用new关键字的区别
第一种方式使用new关键字以原型的方式将user对象暴露到window对象中
//one var user = function(){ this.name=""; this.id=""; }; user.add = function(){ console.log("add"); }; user.delete = function(){ console.log("delete"); }; user.prototype = user; window.user = new user();
第二种方式不使用new关键字直接将user对象暴露到window对象中
//two var user = { name:"", id:"" }; user.add = function(){ console.log("add"); }; user.delete = function(){ console.log("delete"); }; window.user = user;
使用
<button onclick="user.add()">增加</button> <button onclick="user.delete()">删除</button>