对象
1. 对象的属性特征
- writable => 可写
- enumerable => 可枚举
- configurable => 可配置
2. 对象的创建
- 对象的创建有3种方式:对象直接量、关键字new、Object.create()函数
- 对象的原型:每一个非null的js对象都和另一个对象(即原型)相关联,每一个对象都从原型继承属性。
- Object.create(): 是一个静态函数,传入所需对象原型,就可创建一个原型为传入对象的对象。
- {}(空对象)也是有原型的 Object.prototype,而通过Object.create(null)不继承任何属性、方法
3. 继承
- 原型链的检索:
var o = {};
o.x = 1;
var p = Object.create(o);
p.y = 2;
var q = Object.create(p);
q.z = 3;
var s = q.toString(); // => toString继承自Object.prototype
q.x + q.y = 3; // => x继承自o, y继承自p
- 在js中设置属性时与继承无关,可以自己有选择地覆盖继承的属性(在自身而不是原型链上)
- 在删除属性时,delete只能删除自由属性,而不能删除继承属性
- 判断属性是否存在,使用in(包括原型链上)
- hasOwnPreperty()(仅自身属性返回true)
- propertyIsEnumerable()(检测自由属性中可枚举的,返回true)
4. 对象属性的getter与setter
例子:
var o = {
//普通属性
x: 1,
y: 1,
get r(){
return Math.sqrt(this.x*this.x + this.y*this.y);
},
set r(newvalue){
var oldvalue = r;
var ratio = newvalue/oldvalue;
this.x *= ratio;
this.y *= ratio;
},
get theta(){
return Math.atan2(this.y, this.x);
}
};
console.log(o.r) // => 0.414
5. 属性的特性
- 数据属性特性:value、writable、enumerable、configurable
- 存取器特性:get、set、enumerable、configurable
- 获取对象特定属性的属性描述:Object.getOwnPropertyDescriptor(),仅能获得自身的属性描述符
Object.getOwnPropertyDescriptor({x:1}, "x");
return:
{value: 1, writable: true, enumerable: true, configurable: true}
- 设置属性利用Object.definePeoperty()
var o = {};
Object.definePeoperty(o, "x", {
value: 1;
writable: ture;
enumerable: false; //属性存在,但是不可枚举
configurable: true;
});
- 原型属性:
通过new创建的对象,使用构造函数的propertype属性作为他们的原型;通过Object.create()创建的对象使用其第一个参数作为原型,通过对象直接量创建的对象,使用Objec.propertype作为他们的原型。
数组
1. 数组方法:
- join(),可以指定分隔符
- reverse(),将数组中的元素颠倒,原地修改
- sort(),将数组中的元素转换为字符串比较,按照字母表顺序,接收一个函数参数,该函数规定排序规则。
- concat(),创建并返回一个新数组,他的元素包括调用concat()的原始数组和concat()的每个参数。
- slice()左闭右开的参数方式
var a = [1,2,3,4,5]
a.slice(0, 3) // => [1, 2, 3]
a.slice(3) // =>[4, 5]
a.slice(1, -1) // => [2,3,4]
a.slice(-3, -2) // => [3]
- splice(),可接受2个参数,第一个参数为插入或删除的起始位置,第二个参数指定删除个数,若省略第二个参数则删除之后所有。之后的任意个参数为插入的值
- push()与pop()从尾加,从尾去
- unshift()和shift()从头加,从头去
- toString(), toLocaleString()
- map()对数组中的每一个元素,进行相同操作
- filter()过滤器
- every(), some()
- reduce()
- indexOf(), lastIndexOf()
函数
1. 函数定义:
- 函数声明:声明会提前
- 函数表达式,不会提前
- Function构造函数
2. 函数的调用
- 以函数调用:
var pro = factorial(5)/factorial(13)
- 以方法调用:
o.m = function(){
return true
};
o.m();
o["m"]();
- 以构造函数调用:
var o = new Object();
创建一个新的对象,这个对象继承自构造函数的propertype属性。
- 以call,apply间接调用:
Math.max.call(null, 1,2,3,4,5,6); //以参数列表形式传参
Math.max.call(null, [1,2,3,4,5,6]); //以数组形式传参
- callee和caller:指代调用当前正在执行的函数的函数
var factorial = function(x){
if(x <= 1) return 1;
return x*arguments.callee(x-1);
}
3.闭包:
- 函数对象可以通过作用域链相互关联起来,函数体内部的变量可以保存在函数作用域内
var scope = "global scope"; // 全局变量
function checkScope(){
var scope = "local scope"; // 局部变量
function f(){return scope}; //在作用域中返回值
return f()
}
checkScope() // => "local scope"
关联到闭包的作用域链是活动的,嵌套的函数不会将作用域内的私有成员复制一份也不会生成静态快照
function g(){
var func = [];
for (var i = 0; i<5;i++)
func[i] = function(){return i;};
return func
};
上述程序中每个闭包共享i,最后获得的都是4,
正确写法如下:
function g(){
var func = [];
for (var i = 0; i<5;i++)
func[i] = function(x){return x;}(i);
return func
};
同时利用闭包,我们可以包装函数,有点类似于python的装饰器:
//为旧方法添加新功能
function trace(o, m){
var origin = o[m];
o[m] = function(){
console.log(new Date(), "Entering:", m);
var results = origin.apply(this, arguments);
console.log(new Date(), "Exiting:", m);
return results;
};
}
4.柯里化
var curry = function(func){
var args = [].slice.call(arguments,1);
return function(){
var newArgs = args.concat([].slice.call(arguments));
return func.apply(this,newArgs);
}
}
例题:
实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6
add(1, 2, 3)(4) = 10
add(1)(2)(3)(4)(5) = 15
function add(){
var args = [].slice.call(arguments);
var fn = function(){
var newArgs = args.concat([].slice.call(arguments));
return add.apply(null,newArgs);
}
fn.toString = function(){
return args.reduce(function(a, b) {
return a + b;
})
}
return fn ;
}
想一想运行过程