版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://cloud.tencent.com/developer/article/1347611
本书作者douglas Crockford是JSON的创立者,一位javascript大师。
javascript好的想法包括函数,弱类型,动态对象和一个富有表现力的对象字面量表示法。坏的想法包括基于全局变量的编程模型。
javascript函数是基于词法作用域(lexical scoping)的顶级对象,是第一个成为主流的lamda语言。一个糟糕的选择:javascript依赖于全局变量来进行连接。所有编译单元的所有顶级变量被撮合到一个被称为全局对象的公共命名空间中。
这本书之后的很多例子都与用到一个method方法去定义新方法
Function.prototype.method = function (name,fn) {
this.prototype[name] = fn;
return this
}
1 === 1.0 //true
0.1+0.2 != 0.3 //true
var flight= {};
flight.equipment //undefined
flight.equipment.model //throw"TypeError"
flight.equipment && flight.equipment.model //undefined
var status = flight.status || '';
if(typeof Object.beget != 'function') {
Object.beget = function(o) {
var F = function () {};
F.prototype = 0;
return new F();
}
}
函数对象连接到Function.prototype(该原型对象本身连接到Object.prototype),它的值是一个拥有constructor属性且值为该函数的对象。
每个函数在创建时附有两个附加的隐藏属性:函数的上下文和实现函数行为的代码。调用一个函数将暂停当前执行,传递控制权和参数给新函数。除了声明时定义的形参,每个函数接收两个附加的参数:this和arguments,arguments.callee(ES5严格模式报错)代表函数自身,通常用于递归。可用命名函数表达式来代替(js高程第七章函数表达式-7.1递归)
var factorial = (function f(num) {
if(num <= 1) {
return 1;
} else {
return num * f(num-1);
}
});
函数的实参(arguments)和型参(parameters)的个数不匹配时不会报错,如果实参多了,超出的将被忽略。如果实参过少,缺少的会被传入undefined。 一共四种调用模式:方法调用模式,函数调用模式,构造器调用模式和apply调用模式。
当一个函数被保存为对象的一个属性时,我们称它为一个方法,一个方法被调用时,this绑定到该对象(只要函数被调用的时候用一个.点或者subscript下标表达式),那么它被当做一个方法来调用。
当一个函数并非一个对象的属性时,那么它被当做一个函数来调用,this被绑定到全局对象。解决内部函数的this被指向全局的设计缺陷时,可以在外部var that=this。如在浏览器中,this == window;在node中,this == global。
如果在一个函数前面带上new来调用,那么将创建一个隐藏链接到该函数的prototype成员的新对象,同时this将会被绑定到那个新对象上。
类似有call和bind。apply和call的区别在于第二个参数,apply接收数组对象,call接收任意个参数。
this绑定到第一个参数,即传入对象。
在EcmaScript5中扩展了叫bind的方法(IE6,7,8不支持),使用方法如下
function T(c) {
this.id = "Object";
this.dom = document.getElementById("kenny");
}
T.prototype = {
init: function() {
//①
this.dom.onmouseover = function() {
console.log("Over-->"+this.id);//'kenny'
}
//②
this.dom.onmouseout = function() {
console.log("Out -->"+this.id);//'Object'
} .bind(this)
}
};
(new T()).init();
bind与call很相似,,例如,可接受的参数都分为两部分,且第一个参数都是作为执行时函数上下文中的this的对象。
不同点有两个:
1.bind的返回值是函数,(类似事件绑定,改变this指向,执行需在调用一次)。
bind改变上下文this并返回(return)函数,call是 改变上下文this并执行(excute)函数
2.后面的参数的使用也有区别
function f(a,b,c){
console.log(a,b,c);
}
var f_Extend = f.bind(null,"extend_A");
f("A","B","C") //这里会输出--> A B C
f_Extend("A","B","C") //这里会输出--> extend_A A B
f_Extend("B","C") //这里会输出--> extend_A B C
f.call(null,"extend_A") //这里会输出--> extend_A undefined undefined
bind的兼容处理
if (!Function.prototype.bind) {
Function.prototype.bind = function(obj) {
var _self = this
,args = arguments;
return function() {
_self.apply(obj, Array.prototype.slice.call(args, 1));
}
}
}
return语句可以使函数提前返回。当return被执行(不管ture or false),函数立即返回而不再执行余下代码。
一个函数总会返回一个值,没有指定返回值,则返回undefined。如果函数以new方式调用,且返回值不是一个对象,则返回this(该新对象)。
补充:continue中断本次循环,继续下一次循环。break 语句用于跳出循环。jquery中的$.each()用return ture中断本次循环,return false跳出循环。
利用闭包来返回外部函数变量的方式,可以避免一个函数被加上new来使用
//闭包
var quo = function (status){
return {
get_status : function () {
return status ;
}
};
};
var myQuo = quo ("amazed");
myQuo.get_status();
//构造函数
var Quo = function (status){
this.status =status;
};
var myQuo = new Quo("amazed");
当我们调用myQuo时,它返回包含get_status方法的一个新对象。该对象的一个引用保存在myQuo中。即使quo已经返回了,但get_status方法仍然享有访问quo对象的的status属性的特权。get_status方法并不是访问该参数的一个拷贝,它访问的就是该参数本身。因为该函数可以访问它被创建时所处的上下文环境,这就是闭包。
内部函数能访问外部函数的实际变量而无须复制(闭包是活动对象的一个子对象,包含变量的属性)
模拟异步请求,避免客户端被阻塞
request = prepare_the_request();
send_request_asynchronously(request,function(response){
display(response);
};
通过函数和闭包来构造模块。只暴露可用的public方法,其它私有方法全部隐藏,如果你不需要传参数或者没有一些特殊苛刻的要求的话,我们可以在最后一个}后面加上一个括号,来达到自执行的目的,这样该实例在内存中只会存在一份copy。可通过模块模式来实现单例模式
var theModule = (function(){
var i = 1;
return {
result :function(x) {
i++;
return x*i;
}
};
}());
var fibonacci = function (n) {
return n < 2 ? n : a(n-1) + a(n-2);
}
for(let i=0; i<10; i++) {
console.log(i + ':' + fibonacci(i));
}
// 0:0
// 1:1
// 2:1
// 3:3
// 4:5
// 5:7
// 6:9
// 7:11
// 8:13
// 9:15
这样写fiboacci函数被调用了453次。我们调用了11次。
var fibonacci = (function () {
var memo = [0, 1];
var fib = function (n) {
var result = memo[n];
if(typeof result != 'number') {
result = fib(n-1) + fib(n-2);
memo[n] = result;
}
return result;
};
return fib;
})();
fibonacci(10) //55
抽象的递归记忆函数
var memoizer = function (memo, fundamental) {
var shell = function(n) {
var result = memo[n];
if(typeof result != 'number') {
result = fundamental(shell, n);
memo[n] = result;
}
return result;
}
return shell;
};
var fibonacci = memoizer([0, 1], function (shell, n) {
return shell(n-1) + shell(n-2);
});//传递函数
fibonacci(10) //55
在伪类模式与模块模式中,尽量选择后者,函数化构造器伪代码模板
“`javascript
var constructor = function (spec ,my) {
var that,
//其他的私有实例变量;
my = my || {};
//把共享的变量和函数添加到my中;
that = 一个新对象
//添加给that的特权方法
return that;
}