javaScript:基本概念
面向对象
- JavaScript是面向对象的语言,只有五种基本类型:数值类型、字符串类型、布尔类型、空类型、未定义类型。前三种有对应的封装形式的对象。
- JavaScript是一种解释性语言,一旦定义好了变量,同时也就已经正在处理对象。首先,该变量会自动称为内置对象的一个属性,称为激活对象(可以是AO,或GO)。第二,该变量也是伪类,它具有自身的属性, 决定该变量是否可以被修改,被删除,和在一个for-in循环种进行枚举。
- 对象是一个容器,由命名的属性、键-值对的列表。属性也可以是函数(函数对象),我们称为方法。对象的属性和方法,可以随时修改。
- 对象由两种类型:
- 原生的(Native)
- 内置对象(例如数组,日期对象等)
- 用户自定义对象(例如var o={};)等。
- 主机的(Host)
- 包含windows对象和所有的DOM对象。
在主机环境中定义的(如浏览器)。
- 包含windows对象和所有的DOM对象。
尽量多使用对象的组合,而不是使用类的继承。
原型(Prototypes)
- 定义:原型是一个对象,并且创建的每一个都会自动获取一个Prototypes属性,该属性指向一个新的空对象。该对象几乎等同于采用对象字面量或Obect()创建的对象,区别在于它的constructor属性指向了所创建的函数,而不是指向内置的Object()函数。可以为该空对象增加成员变量,以后其他对象也可以从该对象继承并像使用自己的属性一样使用该对象的属性。
//Person.prototype ---> 原型
//Person.prototype = {} 是祖先
Person.prototype.name = "lisi";
Person.prototype.say = function(){
console.log("haha");
}
function Person () {
this.name = "wangwu";
}
环境
浏览器 + JavaScript(ECMAScript)
ECMAScript 5
- 背景ES在第3版时被接受,4版时被放弃,5版时通过。
- 第5版为ES增加了一些内置对象、方法和属性。最重要的时增加了strict模式。
注:strict模式是通过一个普通的字符串来触发的(“use strict”)。在较早的实现方法中将会简单的忽略该代码。使用strict模式,实现向后兼容性,在不能理解该代码的浏览器中,它不会引起错误。 - 新标准:
- 确保不会再strict模式中引起错误。
- 避免使用类似arguments.callee之类的构造函数。
- 调用再ES5中由等价替换的ES3模式,例如Object.create().
JSLint
- 代码质量检查工具
基本技巧
尽量少用全局变量
全局变量的问题
多个变量名称相同,容易覆盖。
- JavaScript出人意料的创建全局变量,两个特性:
- JavaScript可以直接使用变量,无需声明(x,y)。
function sun (x , y){ result = x + y; return result; }
- JavaScript有暗示全局变量的概念(b)。
function foo () {
var a = b = 0;
}
变量释放时的副作用
隐含全局变量与明确定义的全局变量不同:
- 使用var创建的全局变量(函数外创建)不能删除。
- 不适用var创建的隐含全局变量(可以再函数内)可以删除。
这表明隐含全局变量严格讲不是真正的变量,而是全局对象的属性。属性可以通过delete操作删除,但变量不可以。
访问全局变量
- 浏览器下,使用window属性
- 内嵌函数作用域访问:
var global = (function () {
return this;
});
单一var模式
function func () {
var a = 1,
b = 2,
sum = a + b,
i,
j;
//函数体
}
提升:
变量无论在哪里声明,效果等同于再函数顶部进行声明。
代码处理上分为两个阶段:
- 第一,创建变量,函数声明即形式参数,进而解析上下文。
- 第二,代码运行时执行过程,创建函数表达式和不符合标识符(未定义变量)。
myname = "global";
function func () {
alert(myname); //----->相当于将var myname = undefined;放在第一句执行后,没有赋值
var myname = "local";
alert(myname);
}
for循环
for循环经常用在遍历数组或类数组对象,如引数(arguments)和HTML容器(HTMLColltion)对象。
- 一般使用的for循环:
for(var i = 0; i < myarray.length; i++){
//对myarray的处理
}
- 对应问题:每次遍历都要访问数据的长度。这样代码速度变慢。针对修改为:
for(var i = 0, max = myarray.length; i < max; i++){
//对myarray[i]进行处理
}
- 将变量放在循环以外。
- 好处:一致性,因为它贯穿了单一变量的模型。
- 缺点:创建代码时粘贴和复制整个循环比较麻烦。
function looper(){
var i = 0,
max,
myarray = [];
// ....
for(i = 0, max = myarray.length; i < max; i++){
//处理 myarray[i]
}
}
- 对于循环,最后一个改进,用i++替换以下两种表达式:
i = i + 1;
i += 1; - 使用最少的变量。逐步减至0,这样更快,因为同0比较比同数组长度比较,或同非0数组比较更有效率。
//第一个:
var i, myarray = [];
for (i = myarray.length; i--;){
//处理myarray[i]
}
//第二个使用while循环:
var myarray = [],
i = myarray.length;
while (i--) {
//处理myarray[i]
}
for-in循环
for-in循环用来遍历非数组对象。使用for-in循环,也叫枚举(enumeration)。
- 用法:过滤遇到原型链的属性------->使用hasOwnProperty()方法。
var man = {
hands : 2,
legs : 2,
heads : 1
};
if(typeof Object.prototype.clone === "undefined"){
Object.prototype.clone = function () {};
}
for (var i in man){
if (man.hasOwnProperty(i)) {
console.log(i,":",man[i]);
}
}
控制台打印:
hands : 2
legs : 2
heads : 1
for (var i in man) {
console.log(i,":",man[i]);
}
控制台打印:
hands : 2
legs : 2
heads : 1
clone : ƒ () {}
- 另一种使用hasOwnProperty()模型是在Object.prototype中调用该函数
for (var i in man){
if(Object.prototype.hasOwnProperty.call(man,i)){
console.log(i,":",man[i]);
}
}
使用hasOwnProperty对man对象进行精炼后,可以有效的避免命名冲突,也可以使用一个本地变脸来缓存比较长的属性名:
var i,
hasOwn = Object.prototype.hasOwnProperty;
for(i in man) {
if(hasOwn.call(man,i)){
console.log(i,":",man[i]);
}
}
不要增加内置的原型
最好不要给内置原型增加属性。再将来ES可能支持的属性,自定义的属性和方法再未来存在,准确记录下来,和团队交流清除。增加自定义的方法:
if(typeof Object.prototype.myMethod !== "function"){
Object.prototype.myMethod = function(){
//implementation ...
};
}
switch模式
var inspect_me = 0,
result = '';
switch (inspect_me){
case 0:
result = "zero";
break;
case 1:
result = "one";
break;
default:
result = "unknown";
}
每个case语句结尾有一个明确的break语句。
避免使用隐式类型转换
使用 ===和 ! ===来避免隐式类型转换。
避免使用eval()
- eval(),该函数可以将任意字符串当作一个JavaScript代码来执行。
- 避免使用:setInterval()、setTimeout()和function()等。
- new Function()和eval(),new Function()影响到仅仅能看到全局作用域。eval()会影响到作用域链。
使用parseInt()的数值约定
- 可以从一个字符串中获取值。该函数的第二个参数是一个进制参数,可以忽略,最好不要忽略。在ES3中,当转换"09234",如果忽略,会将字符串按找8进制转换,8进制没有9,报错。
- 使用:
+“08”
Number(“08”)
转换比parseInt()快很多。parseInt()是解析,不是简单的转换,“08 hello”,除了parseInt()之外,其他的方法都会失败并返回NaN.