JavaScript,你懂的
- dylan - keakon的涂鸦馆经常有人问我,JavaScript应该怎么学. 先学基本语法,如果曾学过C等语言,应该1小时内就能掌握了. 再去使用内置的函数、方法和DOM API,熟悉它能干什么;而在学习DOM API的过程中,你还不得不与HTML和CSS打交道. 然后弄懂匿名函数和闭包,学会至少一个常用的JavaScript库(例如jQuery).
function 函数名(参数) {
// 函数体
}
当不写函数名的时候,它就是一个匿名函数了,只不过你没法通过函数名来引用它。
new Function('参数名', '/* 函数体 */');
var 函数名 = function(参数) {
// 函数体
}
第1和第3段代码实现的效果是完全相同的,就是定义一个函数,并与“函数名”这个名称进行绑定。
(function(a, b) {
return a + b;
})(1, 2);
第一个括号内是匿名函数的定义,这个括号的作用是提高运算优先级,以便引用这个匿名函数对象;最后那个括号内则是调用它的实际参数,因此这段代码的作用就是将1和2作为参数传递给一个匿名函数,并返回结果3。
(function (n) {
if (n <= 2) {
return 1;
}
return arguments.callee(n - 1) + arguments.callee(n - 2)
})(10);
function 高阶函数(低阶函数, 参数) {
return 低阶函数(参数) * 2;
}
高阶函数(function(x) {
return x + 1;
}, 3);
这段代码中,高阶函数的函数体里调用了低阶函数,就像C中的函数指针一样,所以应该不难理解。
var 匿名函数 = function(x) {
return x + 1;
}
高阶函数(匿名函数, 3);
所不同的是“匿名函数”这个变量名并不存在,而是在调用时直接作为一个函数对象传递给了高阶函数。
function f() {
function g() {
}
}
var a = 1;
var b = 2;
function f() {
var a = 3;
function g(c) {
var d = 4;
/*
g里定义了d,因此d为4
g的参数里有c,因此c为f传递给它的5
g里没有定义a,而外层的f定义了a,因此a为3
g和f里都没定义b,而全局名字空间里有b,因此b为2
顺带一提,如果连全局名字空间里都没有的话,那就是undefined了
*/
return a + b + c + d;
}
return g(5);
}
function f() {
function g(x) {
return x + 1;
}
return g;
}
f()(2);
其中f()的值就是f函数内部的g函数,因此相当于调用的是g(2)。
var a = 1;
function f(b) {
var c = 3;
function g() {
var d = 4;
return a + b + c + d;
}
c = 5;
return g;
}
var h = f(2);
h(); // 12
a = 6;
h(); // 17
f(7)(); // 22
这段代码很奇特,外部的h被赋值为f(2),因此f和g中的b都是2。那么c是多少呢?在定义g之前,它是3,可在定义之后又被重新赋值为5了。
>>> typeof(Object)
"function"
>>> typeof((function(){}))
"function"
>>> (function(){}) instanceof Object
true
>>> (function(){}) instanceof Function
true
>>> typeof(new Object())
"object"
>>> (new Object()) instanceof Object
true
>>> (new Object()) instanceof Function
false
>>> Object instanceof Object
true
>>> Function instanceof Function
true
>>> Function instanceof Object
true
>>> Object instanceof Function
true
由于typeof(Object)的值是"function",并且Object还是Function的实例,因此它必然是个函数。
var a = new Object();
a['x'] = 1;
a.y = 2;
a.x == 1;
a['y'] == 2;
new Object()是一个空对象(实际上就是{}),它是Object的实例。在这个例子中可以看到,当键名是一个合法的属性名时(不能以数字开头等),键值和这个对象的属性值是一回事。
function 动物(名字) {
this.名字 = 名字;
this.叫什么 = function() {
return '我叫' + this.名字;
}
}
var 神马 = new 动物('神马');
神马.叫什么();
这里的new很关键,它表示将“动物”这个函数作为构造函数来初始化一个对象,而不仅仅是执行这个函数。具体来说,它会构造一个空对象{},然后将this指向这个对象,最后执行函数体。(其实还有一些其他的工作,这里先不提。)
function 动物(名字) {
this.名字 = 名字;
this.叫什么 = function() {
return '我叫' + this.名字;
}
}
var 神马 = {};
动物.call(神马, '神马');
神马.叫什么();
function f(a, b, c) {
return this + a + b + c;
}
f.apply(1, [2, 3, 4]); // 10
f.call('1', 2, 3, 4); // "1234"
var a = {};
a[0] = 1;
a[1] = 2;
a[2] = 3;
a.length = 3;
Array.prototype.join.apply(a, ['']); // "123"
Array.prototype.join.call(a, ''); // "123"
在这个例子中,我模拟了一个包含3个数的数组,然后想把数组中所有的数连接成一个字符串。
function A(x) {
this.x = x;
return x;
}
var a = new A(1);
a.x; // 1
a = new A({y: 2});
a.x; // undefined
a.y; // 2
function 动物(名字) {
this.名字 = 名字;
}
动物.prototype.叫什么 = function() {
return '我叫' + this.名字;
}
var 神马 = new 动物('神马');
神马.叫什么();
var 草泥马 = new 动物('草泥马');
草泥马.叫什么();
神马.叫什么 === 草泥马.叫什么; // true
这个例子和之前的很像,所不同的是我并没有定义“this.叫什么”,而是定义了“动物.prototype.叫什么”。而神马和草泥马本身并没有“叫什么”这个方法,于是在调用时,实际上是调用“动物.prototype.叫什么”。
神马.__proto__ === 动物.prototype;
Object.getPrototypeOf(草泥马) === 动物.prototype;
神马.__proto__.constructor === 动物;
神马.constructor === 动物;
动物.prototype.constructor === 动物;
神马.__proto__ = {
'叫什么': function() {
return '我叫' + this.名字 + ',请多指教';
}
};
动物.prototype.吃什么 = function() {
return '我吃河蟹';
};
神马.叫什么(); // "我叫神马,请多指教"
神马.吃什么(); // TypeError: Object #<an Object> has no method '吃什么'
草泥马.叫什么(); // "我叫草泥马"
草泥马.吃什么(); // "我吃河蟹"
function 动物(名字) {
this.名字 = 名字;
}
动物.prototype.叫什么 = function() {
return '我叫' + this.名字;
};
function 马(名字, 食物) {
动物.call(this, 名字); // 调用父类的构造函数
this.食物 = 食物;
}
马.prototype = new 动物(); // 需要复制动物.prototype到马.prototype
马.prototype.吃什么 = function() {
return '我吃' + this.食物;
};
var 神马 = new 马('神马', '草');
神马.叫什么(); // "我叫神马"
神马.吃什么(); // "我吃草"
var 草泥马 = new 马('草泥马', '河蟹');
草泥马.叫什么(); // "我叫草泥马"
草泥马.吃什么(); // "我吃河蟹"
这段代码有2处要说明。
var temp = 马.prototype.__proto__;
草泥马.__proto__.__proto__ = {};
草泥马 instanceof 动物; // false
草泥马 instanceof 马; // true
马.prototype.__proto__ = temp;
草泥马 instanceof 动物; // true
草泥马.__proto__ = {};
草泥马 instanceof 马; // false
草泥马.__proto__ = 动物.prototype;
草泥马 instanceof 动物; // true
草泥马 instanceof 马; // false
var prototype = {'__proto__': 马.prototype};
prototype instanceof 动物; // true
prototype instanceof 马; // true
草泥马.__proto__ = prototype;
草泥马 instanceof 动物; // true
草泥马 instanceof 马; // true
Object.__proto__ === Function.prototype; // Object是Function的实例
Function.__proto__ === Function.prototype; // Function是Function的实例
Object.__proto__.__proto__ === Object.prototype; // Object是Object的实例
Function.__proto__.__proto__ === Object.prototype; // Function是Object的实例
({}).constructor === Object;
Object.constructor === Function;
(function(){}).constructor === Function;
Function.constructor === Function;