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();
2.函数调用模式
函数仅仅当做函数来调用时,this 被绑定到全局对象。
var a = 111 ; function t1(){ var a = 1 function t2(){ console.log(this.a) //111,这其实很不合理,应该指向t2的。 } t2() } t1()
这其实是语言设计上的一个错误,倘若语言设计正确,当内部函数被调用时,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'
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
再来说说 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' } } return a + b; }
throw 语句中断函数的执行,抛出一个 exception 对象,该对象包含可识别异常类型的 name 属性和一个描述性的 message 属性。
该 exception 对象将被传递到一个 try 语句的 catch 从句
try{ add('seven') }catch(e){ console.log(e.name) console.log(e.message) }
如果在 try 代码块中抛出异常,控制权就跳转到其 catch 从句。
给类型增加方法
Number.prototype.integer = function(){ return Math[this < 0 ? 'ceiling' : 'floor'](this) //this指向实例 } var num = 10/3 console.log(num.integer()) ; // 3
作用域
作用域空间那个值变量和参数的可见性和生命周期,对程序员来说很重要,因为它减少了命名冲突,并且提供了自动内存管理。
JavaScript没有块级作用域,却有函数作用域:定义在函数中的参数和变量在函数外部是不可见的,而且在一个函数中的任何位置定义的变量在该函数中任何地方都可见。
下面这个例子与以对象字面量初始化对象不同,通过调用一个函数形式去初始化对象,返回一个对象字面量。此函数定义了一个 val 变量,该变量对 addVal 和 getVal 总是可用的,但函数的作用域使得其对其他程序来说是不可见的。
// 从设计模式的角度来说这是模块模式 var o = (function(){ var val = 0; return { addVal: function(){ val += 1 }, getVal: function(){ console.log(val) } } })()
联想到之前我做的一个小游戏,是20秒内完成任务,使用 restTime 做倒计时变量。后来同事把restTime修改了,成绩贼高。最后我就是用这种办法把 restTime像 val 一样隐藏了起来。
闭包
作用域的好处是内部函数可以访问定义它们的外部函数的参数和变量(除了this和arguments)。
var o = function(){ var val = 0; return { addVal: function(){ val += 1 }, getVal: function(){ console.log(val) } } } var oo = o() oo.addVal() oo.addVal() oo.getVal() // 2
当调用 o 时,返回一个包含addVal和getVal的新对象,该对象的引用保存在 oo 中。虽然 o 返回了,但是 oo 的addVal和getVal有访问 val 的特权,它们可以访问被创建时所处的上下文,这就是闭包。
模块
可以使用函数和闭包来构造模块。模块是一个提供接口却隐藏状态与实现的函数或对象。
具体见『作用域』部分-模块模式
三、继承
当一个函数对象被创建时,Function 构造器产生的函数对象会运行类似这样的代码:
this.prototype = {constructor: this}
每个函数都会得到一个 prototype 对象,其值是包含一个 constructor 属性且属性值为该新函数对象。该 prototype 对象是存放继承特征的地方。
四、数组
区分数组和对象