Home >Web Front-end >JS Tutorial >A concise introduction to JavaScript object-oriented_js object-oriented
Several keywords around object-oriented: encapsulation, inheritance, polymorphism, expansion JavaScript object-oriented
Encapsulation: Among the modes of creating objects in JavaScript, I personally think that through closure It can be regarded as encapsulation in the true sense, so first let’s briefly introduce closures. Look at the following example:
<script type="text/javascript"> function myInfo(){ var name ="老鱼",age =27; var myInfo = "my name is" + name + "i am" + age +"years old"; function showInfo(){ alert(myInfo); } return showInfo; } var oldFish = myInfo(); oldFish(); </script>
Doesn’t it look familiar? That's right, this is actually a simple closure application. A brief explanation: the variables defined in the function myInfo above are accessible in its embedded function showInfo (this is easy to understand), but when we assign the return reference of this embedded function to a variable oldFish, this At this time, the function showInfo is called outside the body of the myInfo function, but the variables defined in the function body can also be accessed. oh yeah!
Let’s summarize the principle of closure: functions run in the scope where they are defined rather than the scope where they are called. In fact, returning an inline function is also the most common way to create a closure!
If you feel that the above explanation is too abstract, then let’s reshape the above function together to see if it has a clearer hierarchy:
<script type="text/javascript"> var ioldFish = function(name,age){ var name = name,age = age; var myInfo = "my name is" + name + "i am" + age +"years old"; return{ showInfo:function(){ alert(myInfo); } } } ioldFish("老鱼",27).showInfo(); </script>
The coding style in the above example is ext yui The more common ones are public and private, clear at a glance. Through closures, we can easily hide some things that we do not want to be directly accessed from the outside. If you want to access the variables defined within the function, you can only access them through specific methods. Direct access from the outside is access. I didn’t get it, I was very tired of writing it, so I finally came back to it after a while. Encapsulation, isn’t it just to hide things that you don’t want others to see? Haha...
If the above example is converted into JQ style, it should be written as the following example. This kind of encapsulation mode belongs to the open door mode, and the variables defined in it can be accessed externally (below) For example, if you instantiate an object first, and then access the object's name or age attribute outside the function, it can be read.) Of course, in this mode, we can set some "hidden rules" to let team development members understand which variables are For private use, we usually add an underscore "_" before private variables and methods to indicate a warning signal! Thus achieving "encapsulation"!
<script type="text/javascript"> var ioldFish = function(name,age){ return ioldFish.func.init(name,age); }; ioldFish.func = ioldFish.prototype ={ init:function(name,age){ this.name = name; this.age = age; return this; }, showInfo:function(){ var info = "my name is" + this.name +"i am " +this.age+"years old"; alert(info); } }; ioldFish.func.init.prototype = ioldFish.func; ioldFish(" 老 鱼",27).showInfo(); //var oldFish = new ioldFish("老鱼",27); //alert(oldFish.name); </script>
Some people may ask, which mode is better? How do you say this? Both methods have advantages and disadvantages, so use them together! In short, the principle is that if something cannot be directly accessed by external objects, use a closure to encapsulate it. The four words "Definitely Definitely" are very profound, and only through continuous practice can you realize the true meaning!
Inheritance: When mentioning this, I would like to add one more thing by the way: a shortcoming of closure encapsulation is not conducive to the derivation of subclasses, so closures are risky and encapsulation needs to be cautious ! For the sake of intuition, the way to create objects in the following example adopts the "open door" mode.
In JavaScript Inheritance is generally divided into three methods: "class inheritance", "prototype inheritance", and "meta-class". The following is a brief introduction to the principles of the three types of inheritance methods.
A. Class inheritance: This is the inheritance method commonly used in mainstream frameworks. See the following example:
<script type="text/javascript"> var Name = function(name){ this.name = name; }; Name.prototype.getName = function(){ alert(this.name); }; var Fish = function(name,age){ Name.call(this,name); this.age = age; }; Fish.prototype = new Name(); Fish.prototype.constructor = Fish; Fish.prototype.showInfo = function(){ alert(this.age); } var ioldFish = new Fish("老鱼",27); ioldFish.getName(); </script>
The above subclass Fish is not defined getName method, but the instance object ioldFish of the subclass Fish still calls this method. This is because the subclass Fish inherits the getName method defined in the superclass Name. To explain, the prototype of the subclass Fish here points to an instance of the super class. Although the getName method is not declared in the subclass Fish, according to the principle of the prototype chain, the upper-level object pointed by the prototype will be searched to see if there is such a method. , if the method is not found, the original prototype object will be searched. This is actually the principle of inheritance. Here is a special explanation, Fish.prototype.constructor = Fish;, because the prototype of the default subclass should point to itself, but the prototype was pointed to the instance object of the super class before, so it needs to be set back here. Of course, the relevant code can be organized through a function to disguise extend
B. Prototypal inheritance, which is better than class inheritance in terms of memory performance.
<script type="text/javascript"> function clone(object){ var F = function(){}; F.prototype = object; return new F(); }; var Name = { name:"who's name", showInfo:function(){ alert(this.name); } }; var Fish = clone(Name); //Fish.name = "老鱼"; Fish.showInfo(); </script>
Obviously, the core of prototypal inheritance is the clone function, which is also the principle of the prototype chain. The difference is that it directly clones the super class, so that the subclass inherits all the attributes and methods of the super class. .In particular, this type of inheritance does not require the creation of a constructor. You only need to create an object variable and define the corresponding properties and methods. Then in the subclass, you only need to refer to the properties and methods through the dot "." symbol. That’s it.
C. Doping class: Encapsulate some common and versatile methods into a function, and then assign them to those who need to use these methods through the following function kind. You can also selectively pass the required methods for different classes.
<script type="text/javascript"> function agument(receveClass,giveClass){ if(arguments[2]){ var len = arguments.length; for(i=2;i<len;i++){ receveClass.prototype[arguments[i]] = giveClass.prototype[arguments[i]]; } } else{ for(method in giveClass.prototype){ if(!receveClass.prototype[method]){ receveClass.prototype[method] = giveClass.prototype[method]; } } } }; var Name = function(){}; Name.prototype ={ sayLike:function(){ alert("i like oldfish"); }, sayLove:function(){ alert("i love oldfish"); } } var Fish = function(){}; var ioldFish = new Fish(); agument(Fish,Name,"sayLove"); ioldFish.sayLove(); ioldFish.sayLike(); </script>
多态 :个人觉得这个比较抽象,很难言传,所以下面就从重载和覆盖两个方面来简单阐述一下。
重载 :上面这个例子中agument函数初始带了两个参数,但是在后面的调用中,agument(Fish,Name,”sayLove”)同样可以带入任意多个参数,javascript的重载,是在函数中由用户自己通过操作arguments这个属性来实现的。
覆盖 :这个很简单,就是子类中定义的方法如果与从超类中继承过来的的方法同名,就覆盖这个方法(这里并不是覆盖超类中的方法,注意一下),这里就不累赘了!
最后重点着墨说一下this和执行上下文 ,在前面举的封装例子中,this都是表示this所在的类的实例化对象本身,但是并不是千篇一律的,打个比方,通过HTML属性定义的事件处理代码,见如下代码:
<script type="text/javascript"> var Name = function(name) { this.name = name; this.getName = function () { alert(this.name); } }; var ioldFish = new Name("老鱼"), btn = document.getElementById('btn'); btn.onclick = ioldFish.getName; //btn.onclick = function(){ioldFish.getName.call(ioldFish)}; </script>
上例中点了按钮以后弹出框里并没有显示出实例对象的属性,这是因为this的执行上下文已经改变了,他现在所在的上下文应该是input这个 HTML标签,但是该标签又不存在getName这个属性,所以自然无法输出这个属性的属性值了!从这个例子我们不难看出:执行上下文是在执行时才确定的,它随时可以变。
当然你可以去掉上面我注释掉的那段代码,通过call改变this的执行上下文,从而获取getName方法。apply方法同样可以实现改变执行上下文的功能,不过在prototype框架中发现了一个更为优美的实现方法bind。看一下这个方法的实现吧,不得不感叹先人的伟大……
Function.prototype.bind = function(obj) { var method = this, temp = function() { return method.apply(obj, arguments); }; }
相信如果能看明白的话,您已经可以靠这些知识点,去写一个简单的脚本框架了,多多实践,相信不久的将来就能高手进级了