函数
函数的定义
函数可以通过关键字 function 来定义。实质上function 对象是 Function函数的实例化对象。
下面是定义的例子
function fn(args){ //关键字定义函数
var vari = args;
console.log(vari)
}
var fn = new Function( //通过构造函数 定义函数
'args',
'var vari = args;console.log(vari)'
)
函数的调用
函数的调用可以分为4种
1. 函数
2. 方法
3. 构造函数
4. call, apply 调用
函数调用
这里只做简单的例子说明,函数调用:
function a(){
console.log(123)
}
a()// ===> 123
var some_var = a()
some_var //===> 123
方法调用
一个方法 ,就是一个对象的属性里的 javascript函数。
var a = {} //JavaScript 对象
a.fn = function(){} // a对象的方法a
a.vari = 123; //a对象的属性vari
方法调用其实和调用函数一样,只不过我们调用的函数是对象里面的一个属性:
var example = function(){
this.fn = function(){
console.log('test')
}
}
var obj = new exmaple();
obj.fn()// ===> test
构造函数的调用
如果函数或者方法前面带有关键字 new,她就构成了构造函数调用。构造函数调用和普通的函数调用在实参处理,调用上下文和返回值方面都有不同;
var o = new Object();
var o = new Object;
构造函数调用会创建一个新的空对象,这个对象继承 继承 构造函数的prototype属性。
var con = function(){
this.asd = 123;
}
con.prototype = {
test:'this is con's prototype'
}
var c_obj = new con();
c_obj.test() // ====> 'this is con's prototype'
构造函数试图初始化这个新创建的对象,并将这个对象做其调用上下文,因此构造函数可以使用this关键字来引用这个新对象。
间接调用
对象名称 | [类型]参数 | 默认 | 必填 | [类型]返回 | 描述 |
---|---|---|---|---|---|
call | object,arg1, arg2, ,argN | window | / | call(object,arg1,…argN) | |
apply | [对象]object,[array][arg1, arg2, ,argN] | window | / | / | apply(object,arg1,…argN) |
function a(){}
a.call();
函数属性,方法,构造函数
这里主要讨论 prototype,call,apply,Function
函数的prototype
每一个函数包涵一个prototype属性,这个属性是指向一个对象的引用,这个对象称为“原型对象”(prototype object)。当函数用作构造函数调用时,新创建的对象会从原型对象(__proto__)上面继承属性。
所以prototype是在描述,当function实例化以后需要继承哪个对象的属性,而且这个被继承的属性将被实例化对象中的属性 __proto__引用。
就是说prototype是描述继承关系,实质上对象继承的继承 靠 __proto__ 属性来实现。
当然 prototype 是函数的属性,而__proto__ 是对象的属性
var animal= function(){
this.eat = function(){
console.lof('i can eat')
}
}
var cat = function(){
this.sleep = function(){
console.log('i can sleep')
}
}
cat.prototype = new animal()
var my_cat = new cat();
my_cat.eat() // ===> i can eat
my_cat.sleep() // ===> i can sleep
我们可以看看 my_cat 对象中的属性:
my_cat.prototype ==== > undefined
my_cat.\__proto__ ==== > animal 对象
my_cat.\__proto__.constructor == function animal ....
注意:不要试图修改实例化对象的 __proto__ 。
1. 并不是所有平台都支持__proto__属性,修改会带来兼容性问题;
2. 大部分平台都会对原型对象的索引进行优化,修改会破坏原有的原型链,这会影响性能;
3. 原型对象是公用对象,修改该对象会影响其他继承该对象的 对象
4. 替换对象这会影响整个继承层次的结构
方法 call、apply
call&apply 这个两个是 function的属性,继承Function.prototype;
这两个属性的效果一个,只是传入参数不一样。
这两个方法常用于方法的复用,和对象继承;
继承:
var animal = function(){
this.eat = function(){
console.log('eat')
}
}
var cat = function(){
animal.call(this) // animal.apply(this)
this.sleep = function(){
console.log('sleep')
}
var cat_case = new cat();
cat_case.eat() // ===> eat
cat_case.sleep() // ===> sleep
复用:
alert(Math.max(5,7,9,3,1,6)); //9
//但是在很多情况下,我们需要找出数组中最大的元素。
var arr=[5,7,9,1];
//alert(Math.max(arr)); // 这样却是不行的。NaN
//要这样写
function getMax(arr){
var arrLen=arr.length;
for(var i=0,ret=arr[0];i<arrLen;i++){
ret=Math.max(ret,arr[i]);
}
return ret;
}
alert(getMax(arr)); //9
//换用apply,可以这样写
function getMax2(arr){
return Math.max.apply(null,arr);
}
alert(getMax2(arr)); //9
//两段代码达到了同样的目的,但是getMax2却优雅,高效,简洁得多。
bind方法
这里的bind 方法讨论ES3 兼容。从名字就能看出,这个方法主要作用就是将函数绑定至某个对象。当函数f()上调用bind()方法并传入一个对象o座位参数,这个方法将返回一个新的函数。调用新的函数将会把原始的函数f( )当做o的方法来调用。传入新函数的任何实参都将传入原始函数,如:
function f(y){
return this.x + y
}
var o = {x:1}
var g = f.bind(o);
g(2) // ==> 3
bind除了绑定一个函数至对象上,他还附带一些其他应用:除了第一个实参以外,传入bind的实参都会绑定至this,这个附带的应用是一种比常见的编程技术,有时也被称为‘柯里化’。下列例子就是柯里化的例子
var sum = function(x,y){return x + y}
var succ = sum.bind(null,1);
succ(2) // ==> 3
function f(y,z){return this.x + y + z }
var g = f.bind({x:1},2)
g(3) // ⇒ 6
Function 构造函数
本文开头说过,function是Function的实例化对象,也就是说,我们可以通过 new 关键字来 实例化一个函数:
var f = new Function('x','y','return x+ y')
这几乎等价于
var f = function(x,y){ return x + y }
不建议使用这种方式 定义函数
参考:
《JavaScript权威指南》 作者:David Flanagan
《Effective JavaScript》 作者: David Herman