对象
- javascript中,对象是可变的键控集合(keyed collection)。对象是属性的容器,其中每个属性都拥有名字和值。属性的名字可以是包含字符串在内的任意字符。属性值可以是除undefined值外的任何值。
- javascript 包含一个原型链的特性,允许对象继承另外一个对象的属性。
-
一个对象的字面量就是包围在一对花括号中的零或多个【键值对】。 '||' 会取第一个为true的,'&&'会尝试取到最后一个为true的(遇到false停止) 可以用 '||' 来填充默认值
var person = {'name':'zxf','age':24}; var status = person.status || "unknown"; //尝试从undefined的成员属性中取值会导致 TypeError异常,可以通过&&运算符来避免错误 var gril_name = person.girl && person.girl.name;
- 对象通过引用传递,永远不会被复制
var a = b = c = {};
- 反射机制
typeof person.name
//检测对象是独有该属性,不检查原型链
person.hasOwnProperty('name');
- delete 可以删除对象属性,它不会触及原型链中的对象(可能使原型链中的同名属性暴露出来)
函数
- 函数包含一组语句,他们是javascript的基础模块单元,用于代码复用,信息隐藏和组合调用。函数用于指定对象的行为,所谓编程,就是将一组需求分解成一组函数与数据结构的技能。
- javascript中函数就是对象。对象是【名/值】对的集合并拥有一个连接到原型对象的隐藏连接。对象的字面常量连接到Object.protoype(也是一个object)。
因为函数时对象,所以他们可以像任何其他值一样被使用。 函数可以在保存变量、对象和数组中。函数可以被当做参数传递给其他函数,函数也可以再返回函数。而且,因为函数是对象,所以函数可以拥有方法。
函数的与众不同在于他们可以被调用。
- 调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了申明是定义的形参,每个函数还接受两个附加的参数:this和arguments。
调用运算符 是跟在任何一个函数表达式之后的一对圆括号
var that = this;
- 基本类型扩充
Function.prototype.method = function(name,func){
if(!this.prototype[name]){
this.prototype[name] = func;
}
return this
}
Number.method('integer',function(){
return Math[this < 0 ? 'ceil':'floor'](this);
});
(-10/3).integer();
- 【作用域】 在编程语言中,作用域控制着变量与参数的可见性与生命周期,它减少了命名冲突,提供了自动的内存管理。
javascript 并不支持块级作用域,只有函数作用域。意味着定义在函数内的参数和变量在函数外是不可见的;而在一个函数内部任何位置定义的变量,在该函数内部任何位置都可见。
最好的做法是在函数体的顶部声明函数中可能用到的所有变量。
- 【闭包】 避免在循环中创建函数,可以在循环之外创建一个辅助函数,让这个辅助函数绑定参数,避免引起混淆。
- 【模块】 我们可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象。
柯里化
允许我们把参数与传递给它的参数结合,产生一个新的函数
function add(){var sum = 0; for(i=0;i<arguments.length;i++){sum += arguments[i];} return sum;}
Function.method('curry',function(){
var slice = Array.prototype.slice,
args = slice.apply(arguments),
that = this;
console.log(args);//[1]
console.log(arguments);//[1]
console.log(this);//function add(){}
console.log(that);//function add(){}
return function(){
console.log('666');
console.log(arguments);//[6]
console.log(args);//[1]
console.log(this);//window
console.log(that);//function add(){}
return that.apply(null,args.concat(slice.apply(arguments)));
}
});
//调用
var add1 = add.curry(1);
document.writeln(add1(6));
记忆
函数可以将先前操作的结果记录在某个对象里,从而避免重复的运算。
定义一个函数,然后返回它。
var memoizer = function(memo,formula){
var recur = function(n){
var result = memo[n];
if(typeof result !== 'number'){
result = formula(recur,n);
memo[n] = result;
}
return result;
}
return recur;
}
var fibonacci = memoizer([0,1],function(recur,n){
return recur(n-1) + recur(n-2);
});
继承
继承提供了两个有用的服务。首先是代码重用的一种形式。另外一个好处是引入了一套类型系统的规范,程序员无需编写显示类型转换的代码。
javascript是一门弱类型语言,从不需要类型转换。对象的集成关系变得无关紧要。对于一个对象来说重要的是它能做什么,而不是它从哪里来。
Function.method('inherits',function(Parent){
this.prototype = new Parent();
return this;
});
//定义构造器
var Mammal = function(name){
this.name = name;
}
Mammal.prototype.get_name = function(){
return this.name;
}
Mammal.prototype.says = function(){
return this.saying || '';
}
var Cat = function(name){
this.name = name;
this.saying = 'meow';
}
Cat.prototype = new Mammal('From the Mammal');
Cat.prototype.purr = function(n){
var i,s = '';
for(i=0;i<n;i++){
if(s){
s += '-';
}
s += 'r';
}
return s;
};
Cat.prototype.get_name = function(){
return this.says() + ' '+ this.name +' ' + this.says();
};
var myCat = new Cat('Tom');
myCat.says();
myCat.purr(5);
myCat.get_name();
//会从原型链上找方法
原型
基于原型的继承:一个对象可以继承一个旧对象的属性
var myMammal = {
name:'the Mammal',
get_name : function(){
return this.name;
},
says:function(){
return this.saying || '';
}
}
//差异化继承
var myCat = Object.create(myMammal);
myCat.name = 'Tom';
myCat.saying = 'meow';
myCat.purr = function(n){
var i,s = '';
for(i=0;i<n;i++){
if(s){
s += '-';
}
s += 'r';
}
return s;
};
myCat.get_name = function(){
return this.says() + ' '+ this.name +' ' + this.says();
};
函数化
继承模式的一个弱点就是没法保护隐私,对象的属性都是可以见的。
应用模块模式
//spec对象包含构造器需要构造一个新实例的所有信息
//my对象是一个为继承链中的构造器提供秘密共享的容器。my对象可以选择新的使用,如果没有传入一个my对象,那么会创建一个my对象。
var constructor = function(spec,my){
var that,其他私有实例变量
my = my || {};
//把共享变量和函数添加到my中
that = 一个新对象
添加that的特权方法
return that;
};
var mammal = function(spec){
var that = {};
that.get_name = function(){
return spec.name;
};
that.says = function(){
return spec.saying || '';
};
return that;
}
var myMammal = mammal({name:'mammal'});
var cat = function (spec){
spec.saying = spec.saying || 'meow';
var that= mammal(spec);
that.purr = function(n){
var i,s = '';
for(i=0;i<n;i++){
if(s){
s += '-';
}
s += 'r';
}
return s;
};
that.get_name = function(){
return that.says() + ' '+ spec.name +' ' + that.says();
};
return that;
};
var myCat = cat({name:'Tom'});
//先给function添加method方法
Function.prototype.method = function(name,func){
if(!this.prototype[name]){
this.prototype[name] = func;
}
return this
}
//处理父类方法的方法
Object.method('superior',function(name){
var that = this,method = that[name];
return function(){
return method.apply(that,arguments);
};
});
var coolcat = function(spec){
var that = cat(spec),
super_get_name = that.superior('get_name');
//super_get_name = that.get_name;
that.get_name = function(n){
return 'like ' + super_get_name() + ' baby';
}
return that;
}
var coolCat = coolcat({name:'Bix'});
var name = coolCat.get_name();
如果对象的所有状态都是私有的,那么该对象就成为一个“防伪(temper-proof)对象”。该对象的属性可以被替换或删除,但该对象的完整性不会受到损害。如果我们用韩淑华的样式创建一个个对象,并且该对象的所有方法都不使用this或that,那么该对象就是持久性(durable)的。一个持久性对象就是一个简单功能函数的集合。
部件
我们可以从一套部件中把对象组装出来。例如,可以构造一个给任何对象添加事件与处理特性的函数。它会给对象添加一个on方法、一个fire方法和一个私有的事件注册表对象:
var eventuality = function(that){
var registry = {};
that.on = function(type, method, parameters){
var handler = {
method : method,
parameters : parameters
};
if(registry.hasOwnProperty(type)){
registry[type].push(handler);
}else{
registry[type] = [handler];
}
return this;
};
that.fire = function(event){
var array,
func,
handler,
i,
type = typeof event === "string" ? event : event.type;
if(registry.hasOwnProperty(type)){
array = registry[type];
for(i = 0; i < array.length; i++){
handler = array[i];
func = handler.method;
if(typeof func === "string"){
func = this[func];
}
func.apply(this, handler.parameters || [event]);
}
}
return this;
};
// that.get_registry = function(){
// return registry;
// };s
return that;
};