1.函数调用、方法调用以及构造函数调用只是单个构造对象的三种不同的使用模式。

第一种函数调用模式:

function hello(username){
return ‘hello,’+ username;
}
hello(‘Keyser Soze’);

第二种模式是方法调用:

var obj = {
hello:function(){
return ‘hello,’+ this.username;
},
username : ‘Hans Gruber’;
};
obj.hello();

通过某个对象调用方法将查找该方法并将该对象作为该方法的接受者。一个非方法的函数调用会将全局对象作为接受者。

第三种模式是构造函数:就像方法和纯函数一样,构造函数也是由function运算符定义的。

function User(name,passwordHash){
this.name = name ;
this.passwordHash = passwordHash;
}

使用new操作符来调用User则视其为构造函数:

var u = new User(‘sfalken’,
‘0ef33ae791068ec64b502d6cb0191387’
);
u.name; //‘sfalken’

构造函数调用将一个全新的对象作为this变量的值,并隐式返回这个新对象作为调用结果。构造函数的主要职责是初始化该对象。

    

2.将函数作为参数或返回值的函数称为高阶函数:

假设有一个简单的转换字符串数组的操作,我们可以使用循环数组实现:

var names = [‘Fred’,‘Wilma’,‘Pebbles’];
var upper = [];
for(var i = 0, n = names.length; i < n ; i++){
upper[i] = names[i].toUpperCase();
}
upper;

使用数组便利的map方法,我们可以完全消除循环,仅仅使用一个局部函数就可以实现对元素的逐个转换。

var names = [‘Fred’,‘Wilma’,‘Pebbles’];
var upper = names.map(function(name){
return name.toUpperCase();
})
upper; //[‘FRED’,‘WILMA’,‘PEBBLES’];

需要引入高阶函数抽象的信号是出现重复或相似的代码。

 

3.使用call方法自定义接受者来调用方法

使用call方法的三种情况:

①通常情况下,函数或方法的接受者是由调用者的语法决定的。有时需要自定义接受者来调用函数,因为该函数可能并不是期望的接受者对象的属性。当然可以将方法作为一个新的属性添加到接受者对象中。但这种方式不仅让人感觉别扭而且相当危险。幸运的是,函数对象具有一个内置的方法call来自定义接收者,可以通过函数对象的call方法来调用其自身:

f.call(obj,arg1,arg2,arg3);

此行为与直接调用函数自身很类似:

f(arg1,arg2,arg3);

②当调用的方法已经被删除、修改或者覆盖时,call方法就派上用场了。使用hasOwnProperty方法的call方法使调用字典对象中的方法成为可能,即使hasOwnProperty方法并没有存储在该对象中。

var hasOwnProperty = { }.hasOwnProperty ;
dict.foo = 1 ;
delete dict.hasOwnProperty ;
hasOwnProperty.call(dict , ‘foo’);
hasOwnProperty.call(dict ,‘hasOwnProperty’);

③定义高阶函数时,call方法也特别实用。高阶函数的一个惯用方法是接收一个可选的参数作为调用该函数的接受者。例如,表示键值对列表的对象可能提供名为forEach的方法。

var table = {
entries : [];
addEntry : function(key , value){
this.entries.push({ key : key , value : value });
},
forEach : function(f, thisArg){
var entries = this.entries;
for(var i = 0 , n = entries.length ; i < n; i ++){
var entry = entries[i];
f.call(thisArg , entry.key , entry.value , i );
}
}
} ;

上述例子允许table对象的使用者将一个方法作为table.forEach的回调函数f,并为该方法提供一个合理的接收者。例如,可以方便的将一个table的内容复制到另一个中。

table1.forEach(table2.addEntry , table2) ;

 

4.使用apply方法通过不懂数量的参数调用函数

Apply方法需要一个参数数组,然后将数组的每一个元素作为调用的单独参数调用该函数。除了参数数组,apply方法指定第一个参数绑定到被调用函数的this变量。由于average函数没有引用this变量,因此,我们可以简单地传递null。

var scores = getAllScores();
average.apply(null,scores);

例如,如果scores有三个元素,那么以上代码的行为与average(scores[0],scores[1],scores[2])一致。

apply方法也可用于可变参数方法。例如,buffer对象包含一个可变参数的append方法,该方法添加元素到函数内部的state数组中。

var buffer = {
state : [ ] ;
append : function(){
for(var i = 0 , n = arguments.length ; i < n ; i ++){
this.state.push(arguments[i]);
}
}
};

5.使用argumen创建可变参数的函数

固定元数版本的averageOfArray函数是很容易实现的:

function averageOfArray(a){
for(var i = 0 , sum = 0, n = a.length ; i < n ; i ++){
sum += a[i] ;
}
return sum / n ;
}
averageOfArray([2,7,1,8,2,8,1,8]);

提供一个可变参数的函数,委托给固定元数版本来实现可变参数的函数:

function average(){
return averageOfArray(arguments) ;
}

这样一来,函数的使用者就无需借助apply方法,因为apply方法会降低可读性而且经常导致性能损失。

 

6.永远不要修改arguments对象

arguments对象可能看起来像一个数组,但它不总是表现的像数组。使用[].slice.call(arguments)将arguments对象复制到一个真正的数组中再进行修改。

 

7.使用变量保存arguments的引用

引用arguments时当心函数嵌套层级。绑定一个明确作用域的引用到arguments变量,从而可以在嵌套的函数中引用它。

function values(){
var i = 0 , n = arguments.length , a = arguments ;
return {
hasNext : function(){
return i < n ;
},
next : function(){
if(i >=n){
throw new Error(“end of iteration”) ;

return a[i++] ;
}
};
}
var it = values(1,4,1,4,2,1,3,5,6);
it.next();
it.next();
it.next();

8.使用闭包而不是字符串来封装代码

函数是一种将代码作为数据结构存储的便利方式,这些代码可以随后被执行,可是应该将代码表示为函数还是字符串?毫无疑问,应该将代码表示为函数,字符串表示代码不够灵活的一个重要原因是:它们不是闭包。

假设有一个简单的多次重复用户提供的动作的函数。

function repeat(n , action){
for(var i = 0 ; i < n ; i ++){
eval(action) ;
}
}

该函数在全局作用域会工作的很好,因为eval函数会将出现在字符串中的所有变量引用作为全局变量来解释。

 

9.避免使用非标准的栈检查属性

调用栈是指当前正在执行的活动函数链。在某些旧的宿主环境中,每个arguments对象都含有两个额外的属性:arguments.callee和arguments.caller。前者指向使用该arguments对象被调用的函数;后者指向调用该函数arguments对象的函数。许多环境仍然支持arguments.callee,但它除了允许匿名函数递归地引用其自身之外,就没有更多的用途了。

避免使用非标准的arguments.callee和arguments.caller属性,因为它们不具备良好的移植性。避免使用非标准的函数对象caller属性,因为在包含全栈信息方面,它是不可靠的。

Effective JavaScript :第三章的更多相关文章

  1. [Effective Java]第三章 对所有对象都通用的方法

    声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...

  2. Effective JavaScript :第二章

    1.熟练掌握闭包 理解闭包要学会三个基本的事实: ①JavaScript允许你引用在当前函数以外定义的变量: 例如: function makeSandwich(){ var magicIngredi ...

  3. Effective JavaScript :第一章

    第一章 一.严格模式与非严格模式 1.在程序中启用严格模式的方式是在程序的最开始增加一个特定的字符串字面量: ‘use strict’ 同样可以在函数体的开始处加入这句指令以启用该函数的严格模式. f ...

  4. JavaScript 第三章总结

    Getting functional function的特点 function can be reused over and over much more readable function is p ...

  5. 对于所有对象都通用方法的解读(Effective Java 第三章)

    这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...

  6. javascript第三章--引用类型

    ① Object类型 ② Array类型 ③ Date类型 ④ RegExp类型 ⑤ Function类型 ⑥ 基本包装类型 ⑦ 单体内置对象

  7. Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句

    第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...

  8. [Effective JavaScript 笔记]第3章:使用函数--个人总结

    前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...

  9. 列表的实现-----数据结构与算法JavaScript描述 第三章

    实现一个列表 script var booklist = new List(); booklist.append('jsbook'); booklist.append('cssbook'); book ...

  10. 《JAVASCRIPT高级程序设计》第三章

    <JAVASCRIPT高级程序设计>第三章主要讲述了这门语言的基础概念,内容多而浅,通过思维导图可以帮助我们很好的理清脉络. js函数使用function关键字来声明,以下是一个简单的例子 ...

随机推荐

  1. IOS GCD图片数据异步下载,下载完成后合成显示

    关于GCD使用详解,请看我的上一篇blog:http://www.cnblogs.com/xin-lang/p/6278606.html 前段时间遇到个需要异步下载,下载完成后再组合显示的东西.这里我 ...

  2. Python学习笔记进阶篇——总览

    Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(Socket编程进阶&多线程.多进程) Python学习笔记——进阶篇[第八周]———进程.线程.协程篇(异常处理) Pyth ...

  3. 正则表达式之 match , findall, sub,subn

    #正则表达式之 match以及分组 import re #无分组 origin = "hello alex bcd alex lge alex avd 19" r = re.mat ...

  4. MATLAB初体验

    好激动 要入MATLAB的大坑了 恩 很遗憾第一个程序并不是hello world 好 插入代码里并没有MATLAB这个选项 这是一种歧视 x=[:pi/:*pi]; y=sin(x); plot(x ...

  5. CodeForces 710C Magic Odd Square

    构造. 先只考虑用$0$和$1$构造矩阵. $n=1$,$\left[ 1 \right]$. $n=3$,(在$n=1$的基础上,最外一圈依次标上$0$,$1$,$0$,$1$......) $\l ...

  6. The Clocks

    The Clocks 题目链接:http://poj.org/problem?id=1166 题意:给出9个时钟的初始状态,问最少通过几次操作,能使每个时钟指向12点(每次操作都会使对应时钟顺时针旋转 ...

  7. php函数搜集

    数组去重: 方法1:php自带此功能的函数array_unique($arr) 方法2:$arr = array_flip(array_flip($arr)); //这样便可以删除重复元素. 比上面的 ...

  8. textview设置不同字体大小

    <style name="style0"> <item name="android:textSize">19dip</item&g ...

  9. github 上传文件

    1.删除项目 2.  包管理器初始化  npm  init name  必填项   后面可一直回车 最后选择yes 3.建立本地仓储 在git bash 中输入命令  git  init 4. 添加 ...

  10. isset()和empty()的区别

    form表单的数据提交过来 如果用isset() if(isset($_GET)){ .....} '' '0' 0 返回 true 不够严谨 empty() '' '0' 0 显示返回false 比 ...