花了点时间学习了下 js 基础,跟大家分享一下,有不到之处,欢迎指出 :)
关于对象
对象的创建
var newObj = new Object();
// var newObj = {};
newObj['someValue'] = 'val';
一切皆对象
[1,2] instanceof Object // true
{1:2, 3:4} instanceof Object //true
但也有些特殊的对象,如 3, ‘str’, true 等等,但如果用 instanceof 测试的话,会发现
'foo' instanceof Object; // false
3 instanceof Object; // false
true instanceof Object; // false
但它们真的也是对象
'foo'.constructor == String // true
true.constructor == Boolean // true
3.constructor == Number // true
还有一个理由
Number.prototype.times = function (func) {
for (var index = 1; index <= this; index++) {
func(index);
}
};
(5).times(print);
// 5 .times(print); //also works
// 加上括号是为了避免出现解析错误(js引擎会以为是小数点)
就连函数也是一个对象
var fn = function () {};
fn.foo = 'hello world';
fn.bar = function () {
alert(this.foo);
};
对象的初始化
function User(first, last) {
this.name = first + ' ' + last;
}
var user = new User('John', 'Resig');
// var user = User('John', 'Resig');
一个 function,可以看成是一个 Class,也可以看成是一个正常的函数,这就麻烦了,因为无论加不加上 new 这个关键字,function 都能正常运行,虽然结果会不一样。
如果看成 Class,使用 new 关键字初始化,那么 function 里的 this 指向当前的 function。如果不使用 new 关键字,则 function 里的 this 默认指向 Window
有两种解决方法,一个是将 Class function 的首字母大写,如 User,这样就能清楚地知道哪些 function 是 Class。但这样还是避免不了写程序时粗心,忘了加 new 关键字。
另一种方法就是不是用 new 关键字,在 function 里自动判断,保证返回的一定是当前对象
function User(first, last) {
if (this instanceof User) {
this.name = first + ' ' + last;
} else return new User(first, last);
}
更通用的方法是创建一个 makeClass 方法
// makeClass - By John Resig (MIT Licensed)
function makeClass() {
return function (args) {
if (this instanceof arguments.callee) {
if (typeof this.init == 'function')
this.init.apply(this, args.callee ? args : arguments);
} else return new arguments.callee(arguments);
};
}
因为函数名未知,所以使用了 arguments.callee 来实现。
makeClass 的使用
var User = makeClass();
User.prototype.init = function (first, last) {
this.name = first + ' ' + last;
};
var user = User('John', 'Resig');
user.name;
// => "John Resig"
对象的继承
每个 function 都有一个特殊的变量”prototype”,当实例化对象时,这个变量上的各个属性也会被附加到对象上
function Car(model, year, miles) {
this.model = model;
this.year = year;
this.miles = miles;
}
Car.prototype = {
info: function () {
return this.model + this.year + this.miles;
},
};
var car = new Car('Benz', 3, 1500);
alert(car.info());
如果不使用 new 关键字,prototype 就失效了
prototype 属性也有一个特殊的属性”constructor”,通过它我们就能实现继承了
Object.prototype.inObj = 1;
function A() {
this.inA = 2;
}
A.prototype.inAProto = 3;
B.prototype = new A(); // Hook up A into B's prototype chain
B.prototype.constructor = B;
function B() {
this.inB = 4;
}
B.prototype.inBProto = 5;
x = new B();
闭包与模块化
闭包是一种现象,通常是因为一个 function 返回了一个内部的 function,如
function f1() {
n = 2011;
return function f2() {
alert(n); // 2011
};
}
可以看到内部 function f2 成功地得到了 f1 的 local 变量,又因为 n 被 f2 使用,所以变量 n 就常驻内存了 从这个角度上说,如果把 f1 看成一个 class,n 就变成了私有变量,而 f2 成为了公共方法,所以就有了模块化的概念
var myNamespace = (function () {
var myPrivateVar = 0;
var myPrivateMethod = function (someText) {
console.log(someText);
};
return {
myPublicVar: 'foo',
myPublicFunction: function (bar) {
myPrivateVar++;
myPrivateMethod(bar);
},
};
})();
其他
避免命名污染的方法
// self executing
// if you want some var global accessable, put "window." ahead
(function () {
var myVar = 2;
alert(myVar);
window.globalVar = 3;
})();
强大的 prototype
Array.prototype.contains = function (value) {
for (var i = 0; i < this.length; i++) {
if (this[i] == value) return true;
}
return false;
};
var stringArray = ['foo', 'bar', 'foobar'];
stringArray.contains('foobar');
方便的”+”
// Quick hex to dec conversion:
+'0xFF'; // -> 255
// Get a timestamp for now, the equivalent of `new Date().getTime()`:
+new Date();
// Safer parsing than parseFloat()/parseInt()
parseInt('1,000'); // -> 1, not 1000
+'1,000'; // -> NaN, much better for testing user input
parseInt('010'); // -> 8, because of the octal literal prefix
+'010'; // -> 10, `Number()` doesn't parse octal literals
// A use case for this would be rare, but still useful in cases
// for shortening something like if (someVar === null) someVar = 0;
+null; // -> 0;
// Boolean to integer
+true; // -> 1;
+false; // -> 0;
// Other useful tidbits:
+'1e10'; // -> 10000000000
+'1e-4'; // -> 0.0001
+'-12'; // -> -12
注意:如果是字符串与数字相加的话,结果还是字符串,如”hello” + 3,结果为”hello3”
通过[]来获取/设置 Object 的属性
a = {};
a['class'] = 'hello'; // access reversed property
a['have space'] = 'world'; // has space
a['.class .subclass'] = 'value'; // can have .
String 的 split 和 replace 可以包含正则
'hello world with spaces'.split(/\s+/g);
//returns an array: ["hello", "world", "with", "spaces"]
var i = 1;
'foo bar baz '.replace(/\s+/g, function () {
return i++;
});
//returns "foo1bar2baz3"
函数定义式与函数表达式
alert(typeof eve); //结果:function
alert(typeof walle); //结果:undefined
function eve() {
//函数定义式
alert('I am Laruence');
}
var walle = function () {
//函数表达式
};
alert(typeof walle); //结果:function
对于函数定义式,会将函数定义提前,而对于函数表达式,只有在执行过程中才会计算
作用域
对于下面的 demo
var name = 'laruence';
function echo() {
alert(name);
var name = 'eve';
alert(name);
alert(age);
}
echo();
输出结果为
undefined;
eve[ReferenceError];
原因是 js 在执行函数之前,会有一个预编译的过程,这个过程中会把局部变量提取出来,放到 scope chain 中,value 都为 undefined(不包括传递过来的参数),所以在执行 echo 函数时,name 的值在设置为”eve”前,为 undefined
参考: