Effective JavaScript :第三章
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 :第三章的更多相关文章
- [Effective Java]第三章 对所有对象都通用的方法
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- Effective JavaScript :第二章
1.熟练掌握闭包 理解闭包要学会三个基本的事实: ①JavaScript允许你引用在当前函数以外定义的变量: 例如: function makeSandwich(){ var magicIngredi ...
- Effective JavaScript :第一章
第一章 一.严格模式与非严格模式 1.在程序中启用严格模式的方式是在程序的最开始增加一个特定的字符串字面量: ‘use strict’ 同样可以在函数体的开始处加入这句指令以启用该函数的严格模式. f ...
- JavaScript 第三章总结
Getting functional function的特点 function can be reused over and over much more readable function is p ...
- 对于所有对象都通用方法的解读(Effective Java 第三章)
这篇博文主要介绍覆盖Object中的方法要注意的事项以及Comparable.compareTo()方法. 一.谨慎覆盖equals()方法 其实平时很少要用到覆盖equals方法的情况,没有什么特殊 ...
- javascript第三章--引用类型
① Object类型 ② Array类型 ③ Date类型 ④ RegExp类型 ⑤ Function类型 ⑥ 基本包装类型 ⑦ 单体内置对象
- Javascript权威指南——第二章词法结构,第三章类型、值和变量,第四章表达式和运算符,第五章语句
第二章 词法结构 一.HTML并不区分大小写(尽管XHTML区分大小写),而javascript区分大小写:在HTML中,这些标签和属性名可以使用大写也可以使用小写,而在javascript中必须小写 ...
- [Effective JavaScript 笔记]第3章:使用函数--个人总结
前言 这一章把平时会用到,但不会深究的知识点,分开细化地讲解了.里面很多内容在高3等基础内容里,也有很多讲到.但由于本身书籍的篇幅较大,很容易忽视对应的小知识点.这章里的许多小提示都很有帮助,特别是在 ...
- 列表的实现-----数据结构与算法JavaScript描述 第三章
实现一个列表 script var booklist = new List(); booklist.append('jsbook'); booklist.append('cssbook'); book ...
- 《JAVASCRIPT高级程序设计》第三章
<JAVASCRIPT高级程序设计>第三章主要讲述了这门语言的基础概念,内容多而浅,通过思维导图可以帮助我们很好的理清脉络. js函数使用function关键字来声明,以下是一个简单的例子 ...
随机推荐
- eclipse集成配置JDK和Tomcat
在eclipse中集成JDK和tomcat服务器方法很简单,我们可以在服务器上运行想要的东西.比如我们学习javaweb时就要用到. 工具/原料 eclipse,JDK,tomcat 方法/步骤 ...
- winform自动更新并实现文件的批量异步下载
public partial class update : Form { private WebClient client; int downfilenum = 0; ...
- SQL总结之对比和备份
-----用户解锁select * from wfuser for update ----------------------修改金额select * from bp_account where ac ...
- swift3 UIColor扩展
//返回一个RGB颜色 class func getColor(r:CGFloat,g:CGFloat,b:CGFloat,l:CGFloat = 1) ->UIColor{ let color ...
- python绝技 — 用Scapy解析TTL字段的值
#!/usr/bin/env python #--*--coding=utf-8--*-- #打印收到的数据包的源IP和TTL值 from scapy.all import * def testTTL ...
- JavaScript忍者秘籍——闭包
概要:本篇博客主要介绍了JavaScript的闭包 1.闭包的工作原理 简单地说,闭包就是一个函数在创建时允许该自身函数访问并操作该自身函数之外的变量时所创建的作用域. 例如: var outerVa ...
- Hive 执行计划
执行语句 hive> explain select s.id, s.name from student s left outer join student_tmp st on s.name = ...
- extjs 6.2 helloworld
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- ASP.NET中ListBox控件的使用
文章来源:http://www.cnblogs.com/fengzheng126/archive/2012/04/10/2441551.html ListBox控件属性介绍: SelectIndex: ...
- Openjudge-NOI题库-字符串移位包含问题
题目描述 Description 对于一个字符串来说,定义一次循环移位操作为:将字符串的第一个字符移动到末尾形成新的字符串. 给定两个字符串s1和s2,要求判定其中一个字符串是否是另一字符串通过若干次 ...