javascript大杂烩
花了点时间学习了下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
参考:
- simple class instantiation/
- hidden features of javascript
- Object Oriented Programming in JavaScript
- module pattern
- javascript的作用域原理
--EOF--
若无特别说明,本站文章均为原创,转载请保留链接,谢谢