公然纪录进修JS MVC,不知道能对峙多久= =。以《基于MVC的JavaScript web富运用开辟》为重要进修材料。接上一篇类的进修,发明实在是看晕了,有些例子是能看懂在干吗,然则不知道为何如许做,有的以至看不懂,真是博大精深!
基于原型的类继承
JavaScript 是基于原型的编程言语,原型用来区分类和实例。原型是一个“模板”对象,它上面的属性被用做初始化一个新对象。任何对象都能够作为另一个对象的原型对象,以此来同享属性。现实上,能够将其理解为某种情势的继承。
当读取一个对象的属性时,JavaScript 起首会在当地对象中查找这个属性,假如没有找到,JavaScript 最先在对象的原型中查找,若还未找到还会继承查找原型的原型,直到查找到Object.prototype。假如找到这个属性,则返回这个值,不然返回undefined。比方,给 Array.prototype 增加了属性,那末一切的 JavaScript 数组都具有了这些属性。
让子类继承父类的属性的要领:
先定义一个组织函数,然后将父类的新实例赋值给组织函数的原型:
// 父,动物大类
var Animal = function(){};
Animal.prototype.breath = function(){
console.log('breath');
};
// 子,狗类
var Dog = function(){};
// Dog 继承了Animal
Dog.prototype = new Animal;
Dog.prototype.wag = function(){
console.log('wag tail');
};
搜检继承是不是见效了:
var dog1 = new Dog;
dog1.wag();
dog1.breath(); // 继承的属性
给“类”库增加继承
经由过程传入一个可选的父类来建立新类,这个能够作为建立类的基本模板:
var Class = function(parent){
var klass = function(){
this.init.apply(this, arguments);
};
// 转变klass 的原型
if (parent) {
var subclass = function() { };
subclass.prototype = parent.prototype;
klass.prototype = new subclass;
};
klass.prototype.init = function(){};
// 定义别号
klass.fn = klass.prototype;
klass.fn.parent = klass;
klass._super = klass.__proto__;
/* include/extend 相干的代码…… */
return klass;
};
假如将parent 传入Class 组织函数,那末一切的子类则同享同一个原型。这类建立
暂时匿名函数的小技能避免了在继承类的时刻建立实例,这里暗示了只要实例的属性才会被继承,而非类的属性【我没读懂这句和上面代码的关联,觉得已晕了 = =】。设置对象的proto ;属性并非一切浏览器都支撑,相似Super.js的类库则经由过程属性复制的体式格局来处置惩罚这
个题目,而非经由过程固有的动态继承的体式格局来完成。
经由过程给Class 传入父类来完成简朴的继承:
var Animal = new Class;
Animal.include({
breath: function(){
console.log('breath');
}
});
var Cat = new Class(Animal);
// 用法
var tommy = new Cat;
函数挪用
在JavaScript中,函数和其他东西一样都是对象。和其他对象差别的是,函数可挪用。函数内上下文,如this 的取值,取决挪用它的位置和要领。
除了运用方括号能够挪用函数以外,另有其他两种要领能够挪用函数:apply()
和 call()
。二者的区分在于传入函数的参数的情势。
apply()
函数有两个参数:第1个参数是上下文,第2个参数是参数构成的数组。假如上下文是null,则运用全局对象替代。比方:
function.apply(this, [1, 2, 3])
call()
的第1个参数是上下文,后续是现实传入的参数序列:
function.call(this, 1, 2, 3);
JavaScript 中许可替换上下文是为了同享状况,尤其是在事宜回调中。jQuery 在其API 的完成中就利用了apply() 和call() 来变动上下文,比方在事宜处置惩罚顺序中或许运用each() 来做迭代时。
$('.clicky').click(function(){
// ‘this’指向当前节点
$(this).hide();
});
$('p').each(function(){
// ‘this’指向本次迭代
$(this).remove();
});
为了接见原始上下文,能够将this 的值存入一个局部变量中,这是一种罕见的形式,比方:
var clicky = {
wasClicked: function(){
/* ... */
},
addListeners: function(){
var self = this;
$('.clicky').click(function(){
self.wasClicked()
});
}
};
clicky.addListeners();
能够用apply来将这段代码变得更清洁一些,经由过程将回调包装在别的一个匿名函数中,来坚持原始的上下文:
var proxy = function(func, thisObject){
return(function(){
return func.apply(thisObject, arguments);
});
};
var clicky = {
wasClicked: function(){
/* ... */
},
addListeners: function(){
var self = this;
$('.clicky').click(proxy(this.wasClicked, this));
}
};
上面的例子中在点击事宜的回调中指定了要运用的上下文;jQuery中挪用这个函数所用的上下文就能够疏忽了。现实上jQuery也包含了完成了这个功用的API——jQuery.proxy()
:
$('.clicky').click($.proxy(function(){ /* ... */ }, this));
运用apply()
和call()
另有其他很有效的缘由,比方“托付”。能够将一个挪用托付给另一个挪用,以至能够修正传入的参数:
var App {
log: function(){
if (typeof console == "undefined") return;
// 将参数转换为适宜的数组
var args = jQuery.makeArray(arguments);
// 插进去一个新的参数
args.unshift("(App)");
// 托付给console
console.log.apply(console, args);
}
};
这个例子中起首构建了一个参数数组,然后将参数增加进去,末了将这个挪用托付给了console.log()
。arguments
变量是诠释器内置的当前挪用的作用域内用来保留参数的数组。但它并非真正的数组,比方它是不可变的,因而须要经由过程jQuery.makeArray()
将其转换为可用的数组。