一、对象
JavaScript简单类型有数字、字符串、布尔值、null、undefined,其他所有的值都是对象(数组、函数、正则表达式都是对象)。
数字、字符串、布尔值虽然拥有方法(包装对象),但并不是对象。
包装对象:
每当读取一个基本类型值的时候,后台会创建一个对象的基本包装类型的对象,从而能够调用一些方法来操作这些数据。
var s1 = 'abcdefg' ; var s2 = s1.substring(2) ;</div>
后台自动完成下列处理:
- 创建String类型的一个实例
- 在实例上调用指定的方法
- 销毁这个实例
所以上面代码等同于:
对象字面量
var flight = {
airline: "Oceanic",
number: 815,
departure: {
IATAL: "SYD",
time: "2004-09-22 14:55",
city: "Sydney"
},
arrival: {
IATA: "LAX",
time: "2004-09-23 10:42",
city: "Los Angeles"
}
}
</div>
检索
[] : flight['number'] . : flight.number</div>
更新
通过赋值语句更新,如果属性名已经存在于对象中,则被替换;如果对象中没有那个属性名,则添加。
stooge['first-name'] = 'Jerome'
引用
对象赋值通过引用来传递,它们永远不会被拷贝。
var a = {
name: 'a'
}
var b = a
b.name = 'b'
console.log(a.name) // b
</div>
这里牵扯出 JavaScript 深拷贝和浅拷贝的问题
上例是浅拷贝使用Object.create可以进行深拷贝
var a = {
name: 'a'
}
var b = Object.create(a)
b.name = 'b'
console.log(a.name) // a
</div>
自定义方法深拷贝见下:
var deepCopy= function(source) {
var result={};
for (var key in source) {
result[key] = typeof source[key]==='object'? deepCoyp(source[key]): source[key];
}
return result;
}
</div>
此时 var b = deepCopy(a) 得到的 b 就和 a 没有引用关系,即修改 b 不会影响 a了
原型
每个对象都连接到一个原型对象,并且从中继承属性。所有通过对象字面量创建的对象都连接到 Object.prototype 这个JavaScript中标准的对象。
创建一个对象时,可以选择某个对象作为它的原型:
var o = {o1:1,o2:function(){alert(1)}}
function F(){}
F.prototype = o
var f = new F()
</div>
反射
使用 hasOwnProperty 检查属性是否是对象独有的,它并不会检查原型链。
flight.hasOwnProperty('number'); //true
枚举
for in 可以遍历对象中所有的属性名(见深拷贝部分)
删除
delete 可以删除对象属性,不会触及原型链中的任何对象
减少全局变量污染
最小化使用全局变量的一个方法是创建唯一一个全局变量:
var App = {}
App.stooge = {
"first-name": "Joe",
"last-name": "Howard"
}
App.flight = {
airline: "Oceanic",
number: 815
}
</div>
减少全局变量污染另一个办法是使用闭包进行信息隐藏
二、函数
函数包含一组语句,是Javascript的基础模块单元,用于代码复用、信息隐藏和组合调用。
一般来说,所谓编程就是将一组需求分解成一组函数与数据结构的技能。
函数对象
函数就是对象,对象是键值对的集合并且拥有一个连到原型对象的隐藏连接。对象字面量产生的对象连接到 Object.prototype ,函数对象连接到 Function.prototype (该原型对象本身又连接到 Object.prototype)。
var add = function(a,b){
return a + b;
}
</div>
函数表达式包含四部分:
- 保留字 function
- 函数名,可以被省略(匿名函数)
- 参数,逗号分隔
- 花括号中的语句
函数表达式允许出现在任何允许表达式出现的地方,函数也可以被定义在其他函数中。一个内部函数可以访问自己的参数和变量,同时它也能方便地访问它被嵌套在其中的那个函数的参数和变量。通过函数表达式创建的函数对象包含一个连到外部上下文的连接,被称为闭包。
调用
函数在调用的时候有两个附加参数:this、arguments。
this 是调用上下文,值取决于函数调用的模式。
1.方法调用模式
一个函数被保存为对象的一个属性时,即为一个方法。当一个方法被调用时,this 被绑定到该对象。
每个函数在创建时附有两个附加的隐藏属性:
- 函数上下文
- 实现函数行为的代码
每个函数对象在创建时也会带一个 prototype 属性,它的值是一个拥有 constructor 属性且值为该函数的对象。
函数表达式
函数对象可以通过函数表达式来创建:
var dog = {
name : 'xxx' ,
leg:{
sum : 4 ,
move:function(){
console.log(this) ; //Object,是leg对象,而不是dog对象,下面证明了
alert(this.name) ; //underfined
alert(this.sum) ; //4
}
}
}
dog.leg.move();
</div>
2.函数调用模式
函数仅仅当做函数来调用时,this 被绑定到全局对象。
var a = 111 ;
function t1(){
var a = 1
function t2(){
console.log(this.a) //111,这其实很不合理,应该指向t2的。
}
t2()
}
t1()
</div>
这其实是语言设计上的一个错误,倘若语言设计正确,当内部函数被调用时,this 应该仍然绑定到外部函数的 this 变量。
3.构造器调用模式
如果一个函数前面带上 new 调用,那么将创建一个隐藏连接到该函数的 prototype 成员的新对象,同时 this 将被绑定到那个新对象上。
function Dog(name){
this.name = name ;
}
Dog.prototype.cry = function(){
alert(this.name)
}
var dog1 = new Dog('xxx');
dog1.cry(); // 'xxx'
</div>
4.Apply/Call调用模式
apply 接受两个参数,第一个是将被绑定给this的值,第二个就是一个参数数组。
call 与 apply 相同,不过第二个参数不是数组。
var dog = {
leg : 4 ,
color:'yellow'
}
var color = 'red' ;
function t(){
alert(this.color) ;
}
t(); // red , 因为指向this在函数中调用指向window
t.call(dog); //yellow , 把t()的作用域指向了dog
</div>
再来说说 arguments,它是一个类数组对象(拥有length属性,但缺少所有数组方法)。通过它可以访问函数调用时传递给函数的参数列表。
返回
一个函数调用时,将暂停当前函数的执行,传递控制权和参数给新函数。它从第一个语句开始执行,并在遇到关闭函数体的 } 时结束。使得函数把控制权交还给调用该函数的程序部分。
return 语句可用来使函数提前返回,当 return 执行时,函数立即返回而不再执行余下的语句。一个函数总是会返回一个值,如果没有指定返回值,则返回 undefined 。
如果函数前加上 new 来调用,且返回值不是一个对象,则返回this(该新对象)。
异常
抛出异常
function add(a,b){
if(typeof a!=='number' || typeof b!=='number'){
throw {
name: 'TypeError',
message: 'add needs numbers'
}

