var strict = (function(){ return !this}());
// 定义并调用一个函数来确定当前脚本运行时是否为严格模式
方法是保存在对象的属性中的js函数。 方法调用和函数调用最大区别是上下文。
var o = {
m: function() {
var self = this;
console.log(this == o); // true
f();
function f(){
console.log(this == o); // false, this为global或者undefined。
console.log(self == o); // true, 指外层的this对象。
}
}
如果嵌套函数作为函数调用,其this值不是全局对象就是undefined.
如果函数调用之前带有关键字 new,它就构成构造函数调用,构造函数调用和普通函数和方法调用在实参处理、调用上下文和返回值方面不同。
凡是没有形参的构造函数都可以省去圆括号。
构造函数调用创建一个新的对象,这个对象继承构造函数的prototype属性,构造函数试图初始化这个新建的对象,并且将新建的对象作为
调用上下文,因此构造函数可以使用this关键字来引用新建的对象。
构造函数不使用return关键字,当构造函数的函数体执行完毕,它会显式返回,如果使用return语句,则返回的是return后的对象,如果return没有指定返回对象或返回一个原始值,则将忽略返回值,同时使用这个新对象作为调用结果。
函数也是对象,函数对象也包含方法, call(), apply();
函数的形参:
可选形参:当调用函数的实参个数比函数声明的时候少,则缺少的形参都将设置为undefined,给形参赋一个默认值:
function getPropertyName(o, /* optinal */ a){
if ( a == undefined) a = []; // 等于 a = a || [];
for(var property in o) a.push(property);
return a;
}
注意:可选形参放置在函数声明的末尾;
当传入的参数个数多余函数声明中所定义的形参的个数,没有办法直接获取多余的实参的值,参数对象刚好解决这个问题。
在函数体内,标识符arguments是指向参数对象的引用,参数对象是一个类数组对象,通过数字下标访问传入函数的实参值。
使用案例:
function max(/* ... */){
int max = Number.NEGATIVE_INFINITY;
for(var i = 0; i < arguments.length; i++)
if (arguments[i] > max) max = arguments[i];
return max;
}
除了数组元素,实参对象还有callee和caller属性,在ES5严格模式下,对这两个属性的读写都会产生类型错误。
var factorial = function(x) {
if ( x <= 1 ) return 1;
return x * arguments.callee(x-1);
将对象属性用作实参:
function easycopy(args) {
arraycopy(args.from,
args.from_start || 0, // 注意这里设置了默认值
args.to,
args.to_start || 0, args.length);
}
var a = [1, 2, 3, 4], b = [];
easycopy({from: a, to: b, length: 4});
宁愿参数报错,也不愿逻辑错误
作为值的函数:
函数可以定义,也可以调用。函数不仅是中语法,也是值。
function square(x) { return x * x }
var f = square;
square(4); // 上下两个表达式是等价的
f(4);
var o = {square: function(x){ return x*x }}
o.square(4);
var a = [function(x) {return x*x}, 20] //数组直接量;
函数并不是原始值,而是一种特殊对象,函数可以拥有属性。当函数需要一个“静态”变量在调用时保持某个值不变,最方便的方法是给函数
定义属性。
uniqueInteger.counter = 0; // 由于函数声明被提前,所以可以在函数声明之前给成员赋值
function uniqueInteger(){
return uniqueInteger.counter++;
}
function factorial(n){
if (isFinte(n) && n>0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n-1);
return factorial[n];
}else return NaN;
}
factorial[1] = 1; // 函数将自己作为一个数组容器;
作为命名空间的函数:
不在任何函数内定义的变量称为全局变量;常常定义一个函数用作临时的命名空间,在命名空间中
定义的变量不会污染到全局命名空间。
解决办法:定义一个函数,将变量定义在函数内,然后调用这个函数,这样全局变量就变成一个局部变量。
function module(){
// 模块代码
// 模块所使用的所有变量都是局部变量。
// 而不是污染全局命名空间
}
module();
使用匿名函数
(function(){ //模块代码 }()); // function前面的左圆括号是必须的,如果不写,Javascript解释器
会将关键字function解析为函数声明语句,使用圆括号,Javascript才会正确解释为函数定义表达式,
var extend = (function(){
for(var p in {toString: null}) {
return function extend(o) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for(var prop in source) o[prop] = source[prop];
}
return o;
};
var protoprops = ["toString", "valueOf", "constructor", "hasOwnProperty",
"isPrototypeOf", "propertyIsEnumerable", "toLocaleString"];
}
}());
闭包:
Javascript采用语法作用域,函数的执行依赖于变量的作用域,而作用域是函数定义时决定的,而不是函数调用时决定的。
为了实现这种词法作用域,Javascript函数对象的内部状态不仅包含函数的代码逻辑,也必须包含当前的作用域链
定义大多数函数是的作用域链在调用函数是依然有效,这不影响闭包,当调用函数是的作用域链和定义函数时作用域链
不是同一个作用域链时,事情就变的微妙。
理解闭包首先理解嵌套函数的词法作用域规则:
var scope = "global scope"; // 全局变量
function checkscope(){
var scope = "local scope"; // 局部变量
function f() {return scope;}//在作用域中返回这个值
return f();
}
checkscope(); // => "local scope"
var scope = "global scope"; // 全局变量
function checkscope(){
var scope = "local scope"; // 局部变量
function f() {return scope;}//在作用域中返回这个值
return f;
}
checkscope()(); // => "依然是local scope"
var uniqueInteger = (function{
var counter = 0;
return function(){ return counter++; };
}();
方法是保存在对象的属性中的js函数。 方法调用和函数调用最大区别是上下文。
var o = {
m: function() {
var self = this;
console.log(this == o); // true
f();
function f(){
console.log(this == o); // false, this为global或者undefined。
console.log(self == o); // true, 指外层的this对象。
}
}
如果嵌套函数作为函数调用,其this值不是全局对象就是undefined.
如果函数调用之前带有关键字 new,它就构成构造函数调用,构造函数调用和普通函数和方法调用在实参处理、调用上下文和返回值方面不同。
凡是没有形参的构造函数都可以省去圆括号。
构造函数调用创建一个新的对象,这个对象继承构造函数的prototype属性,构造函数试图初始化这个新建的对象,并且将新建的对象作为
调用上下文,因此构造函数可以使用this关键字来引用新建的对象。
构造函数不使用return关键字,当构造函数的函数体执行完毕,它会显式返回,如果使用return语句,则返回的是return后的对象,如果return没有指定返回对象或返回一个原始值,则将忽略返回值,同时使用这个新对象作为调用结果。
函数也是对象,函数对象也包含方法, call(), apply();
函数的形参:
可选形参:当调用函数的实参个数比函数声明的时候少,则缺少的形参都将设置为undefined,给形参赋一个默认值:
function getPropertyName(o, /* optinal */ a){
if ( a == undefined) a = []; // 等于 a = a || [];
for(var property in o) a.push(property);
return a;
}
注意:可选形参放置在函数声明的末尾;
当传入的参数个数多余函数声明中所定义的形参的个数,没有办法直接获取多余的实参的值,参数对象刚好解决这个问题。
在函数体内,标识符arguments是指向参数对象的引用,参数对象是一个类数组对象,通过数字下标访问传入函数的实参值。
使用案例:
function max(/* ... */){
int max = Number.NEGATIVE_INFINITY;
for(var i = 0; i < arguments.length; i++)
if (arguments[i] > max) max = arguments[i];
return max;
}
除了数组元素,实参对象还有callee和caller属性,在ES5严格模式下,对这两个属性的读写都会产生类型错误。
var factorial = function(x) {
if ( x <= 1 ) return 1;
return x * arguments.callee(x-1);
将对象属性用作实参:
function easycopy(args) {
arraycopy(args.from,
args.from_start || 0, // 注意这里设置了默认值
args.to,
args.to_start || 0, args.length);
}
var a = [1, 2, 3, 4], b = [];
easycopy({from: a, to: b, length: 4});
宁愿参数报错,也不愿逻辑错误
作为值的函数:
函数可以定义,也可以调用。函数不仅是中语法,也是值。
function square(x) { return x * x }
var f = square;
square(4); // 上下两个表达式是等价的
f(4);
var o = {square: function(x){ return x*x }}
o.square(4);
var a = [function(x) {return x*x}, 20] //数组直接量;
函数并不是原始值,而是一种特殊对象,函数可以拥有属性。当函数需要一个“静态”变量在调用时保持某个值不变,最方便的方法是给函数
定义属性。
uniqueInteger.counter = 0; // 由于函数声明被提前,所以可以在函数声明之前给成员赋值
function uniqueInteger(){
return uniqueInteger.counter++;
}
function factorial(n){
if (isFinte(n) && n>0 && n == Math.round(n)) {
if (!(n in factorial))
factorial[n] = n * factorial(n-1);
return factorial[n];
}else return NaN;
}
factorial[1] = 1; // 函数将自己作为一个数组容器;
作为命名空间的函数:
不在任何函数内定义的变量称为全局变量;常常定义一个函数用作临时的命名空间,在命名空间中
定义的变量不会污染到全局命名空间。
解决办法:定义一个函数,将变量定义在函数内,然后调用这个函数,这样全局变量就变成一个局部变量。
function module(){
// 模块代码
// 模块所使用的所有变量都是局部变量。
// 而不是污染全局命名空间
}
module();
使用匿名函数
(function(){ //模块代码 }()); // function前面的左圆括号是必须的,如果不写,Javascript解释器
会将关键字function解析为函数声明语句,使用圆括号,Javascript才会正确解释为函数定义表达式,
var extend = (function(){
for(var p in {toString: null}) {
return function extend(o) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for(var prop in source) o[prop] = source[prop];
}
return o;
};
var protoprops = ["toString", "valueOf", "constructor", "hasOwnProperty",
"isPrototypeOf", "propertyIsEnumerable", "toLocaleString"];
}
}());
闭包:
Javascript采用语法作用域,函数的执行依赖于变量的作用域,而作用域是函数定义时决定的,而不是函数调用时决定的。
为了实现这种词法作用域,Javascript函数对象的内部状态不仅包含函数的代码逻辑,也必须包含当前的作用域链
定义大多数函数是的作用域链在调用函数是依然有效,这不影响闭包,当调用函数是的作用域链和定义函数时作用域链
不是同一个作用域链时,事情就变的微妙。
理解闭包首先理解嵌套函数的词法作用域规则:
var scope = "global scope"; // 全局变量
function checkscope(){
var scope = "local scope"; // 局部变量
function f() {return scope;}//在作用域中返回这个值
return f();
}
checkscope(); // => "local scope"
var scope = "global scope"; // 全局变量
function checkscope(){
var scope = "local scope"; // 局部变量
function f() {return scope;}//在作用域中返回这个值
return f;
}
checkscope()(); // => "依然是local scope"
var uniqueInteger = (function{
var counter = 0;
return function(){ return counter++; };
}();