1,eg:var obj = new XX()。obj 由 XX.prototype.constructor 构造,而非 XX 构造。所以 obj.constructor = XX.prototype.constructor 而非 obj.constructor = XX
2,所有函数的参数都是按值传递。
eg:
function setName(obj){
obj.name = "N";
obj = new Object();
obj.name = "G";
}
var person = new Object();
setName(person);
alert(person.name);//"Nicholas"
person 的值 赋给 obj ---------值传递
obj 就为 person 没有进行拷贝------------引用传递
思考:按照这种思考,java中也只有值传递!
3,js 没有块级域
eg:
function aaa(){
for(var i = 0; i < 10; i++) {
}
alert(i);// 10, 依然能够在aaa这个函数里访问到,块级域在js里不存在,会将它的外层域作为变量的存在域。
}
4,闭包中的this对象
var name = "window";
var obj = {
name : "inner obj",
getNameFunc: function(){
return function(){
return this.name;
};
}
};
alert(obj.getFun()()); // "window"
闭包是一种匿名函数,匿名函数的执行环境具有全局性,因此其this对象通常执行window。
obj.getNameFunc()调用返回一个函数。这是个返回的函数,它不在是obj的属性或者方法,此时调用者是window。因此输出是 The Window
5,true false
alert(NaN);//NaN
alert(!NaN);//true
alert(!"");true;
6,正则表达式
(1)test
var text = "abcd";
var pattern = /a/gi;
pattern.test(text);
(2)exec
var text = "abcd";
var pattern = /a/gi;
var matches = pattern.exec(text);
alert(matches[0]);
ECMAScript 定义类或对象
1,原始方式var oCar = new Object;
oCar.color = "blue";
oCar.doors = 4;
oCar.mpg = 25;
oCar.showColor = function() {
alert(this.color);
};
缺点:创建多个对象不给力。要一个一个赋值。
2,工厂方式
function createCar() {
var oTempCar = new Object;
oTempCar.color = "blue";
oTempCar.doors = 4;
oTempCar.mpg = 25;
oTempCar.showColor = function() {
alert(this.color);
};
return oTempCar;
}
var oCar1 = createCar();
var oCar2 = createCar();
缺点:每创建一个实例都包含一个相同的属性方法。
3,构造函数方式
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.showColor = function() {
alert(this.color);
};
}
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
缺点:同工厂方式相同,每创建一个实例都包含一个重复的方法。
4,原型方式
function Car() {
}
Car.prototype.color = "blue";
Car.prototype.doors = 4;
Car.prototype.mpg = 25;
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car();
var oCar2 = new Car();
缺点:1,使用原型方式,不能通过给构造函数传递参数来初始化属性的值。
2,属性指向的是对象,而不是函数时。函数共享不会造成问题,但对象却很少被多个实例共享。
5,混合的构造函数/原型方式
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
}
Car.prototype.showColor = function() {
alert(this.color);
};
var oCar1 = new Car("red",4,23);
var oCar2 = new Car("blue",3,25);
oCar1.drivers.push("Bill");
alert(oCar1.drivers); //输出 "Mike,John,Bill"
alert(oCar2.drivers); //输出 "Mike,John"
缺点:本来已经趋近完美了(可以传参,属性不会被共享,方法不重复创建)。唯一缺点,方法不在构造函数内。
6,动态原型方法
function Car(sColor,iDoors,iMpg) {
this.color = sColor;
this.doors = iDoors;
this.mpg = iMpg;
this.drivers = new Array("Mike","John");
if (typeof Car._initialized == "undefined") {
Car.prototype.showColor = function() {
alert(this.color);
};
Car._initialized = true;
}
}
缺点:与混合的构造函数/原型方式 相比,唯一区别是,方法位置被移动过到了构造函数内。
7,混合工厂方式
function Car() {
var oTempCar = new Object;
oTempCar.color = "blue";
oTempCar.doors = 4;
oTempCar.mpg = 25;
oTempCar.showColor = function() {
alert(this.color);
};
return oTempCar;
}
缺点:由于在 Car() 构造函数内部调用了 new 运算符,所以将忽略第二个 new 运算符(位于构造函数之外),在构造函数内部创建的对象被传递回变量 car。
这种方式在对象方法的内部管理方面与经典方式有着相同的问题。强烈建议:除非万不得已,还是避免使用这种方式。
推荐使用:
如前所述,目前使用最广泛的是混合的构造函数/原型方式。此外,动态原始方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。
8.StringBuffer 实现
function StringBuffer(){
this.arr = new Array();
if (typeof StringBuffer.init == "undefined") {
StringBuffer.prototype.append = function(text){
this.arr.push(text);
};
StringBuffer.prototype.toString = function(){
return this.arr.join("");
};
StringBuffer.init = true;
};
}
ECMAScript 继承机制实现
对象冒充
function ClassA(sColor) {
this.color = sColor;
this.sayColor = function () {
alert(this.color);
};
}
function ClassB(sColor) {
}
function ClassB(sColor, sName) {
this.newMethod = ClassA;
this.newMethod(sColor);
delete this.newMethod;
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
原理很简单,就是this被冒充为ClassB的实例了,还可以实现多继承哦。
这种还可以用call ,apply实现。
function ClassB(sColor, sName) {
//this.newMethod = ClassA;
//this.newMethod(color);
//delete this.newMethod;
ClassA.call(this, sColor);
this.name = sName;
this.sayName = function () {
alert(this.name);
};
}
原型链(prototype chaining)
function ClassA() {
}
ClassA.prototype.color = "blue";
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB() {
}
ClassB.prototype = new ClassA();
ClassB.prototype.custructor = ClassB;
注意:调用 ClassA 的构造函数,没有给它传递参数。这在原型链中是标准做法。要确保构造函数没有任何参数。
与对象冒充相似,子类的所有属性和方法都必须出现在 prototype 属性被赋值后,因为在它之前赋值的所有方法都会被删除。为什么?因为 prototype 属性被替换成了新对象,添加了新方法的原始对象将被销毁。所以,为 ClassB 类添加 name 属性和 sayName() 方法的代码如下:
function ClassB() {
}
ClassB.prototype = new ClassA();
ClassB.prototype.name = "";
ClassB.prototype.sayName = function () {
alert(this.name);
};
ClassB.prototype.custructor = ClassB;
混合方式(冒充+原型链)
这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。
在前一章,我们曾经讲解过创建类的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承 prototype 对象的方法。用这两种方式重写前面的例子,代码如下:
function ClassA(sColor) {
this.color = sColor;
}
ClassA.prototype.sayColor = function () {
alert(this.color);
};
function ClassB(sColor, sName) {
ClassA.call(this, sColor);
this.name = sName;
}
ClassB.prototype = new ClassA();
ClassB.prototype.sayName = function () {
alert(this.name);
};
ClassB.prototype.custructor = ClassB;
增加getElementsByClassName方法
function getByClass(oParent,cls){
if (document.getElementsByClassName){
return (oParent || document).getElementsByClassName(cls);
}else{
var oParent = oParent || document;
var reg= new RegExp("^|\\s"+cls+"$|\\s","i"),
res = [],
child = null;
for (var i = 0; i < oParent.all.length; i ++){
child = oParent.all[i];
if (reg.test(child.className)){
res.push(child);
}
};
return res;
}
}
易错:函数中声明的变量在整个函数中都有定义。
首先观察这段代码:
- <script type="text/javascript">
- function rain(){
- var x = 1;
- function man(){
- x = 100;
- }
- man(); //调用man
- alert( x ); //这里会弹出 100
- }
- rain(); //调用rain
- </script>
上面得代码说明了,变量x在整个rain函数体内都可以使用,并可以重新赋值。由于这条规则,会产生“匪夷所思”的结果,观察下面的代码。
- <script type="text/javascript">
- var x = 1;
- function rain(){
- alert( x ); //弹出 'undefined',而不是1
- var x = 'rain-man';
- alert( x ); //弹出 'rain-man'
- }
- rain();
- </script>
是由于在函数rain内局部变量x在整个函数体内都有定义( var x= 'rain-man',进行了声明),所以在整个rain函数体内隐藏了同名的全局变量x。这里之所以会弹出'undefined'是因为,第一个执行alert(x)时,局部变量x仍未被初始化。
所以上面的rain函数等同于下面的函数:
- function rain(){
- var x;
- alert( x );
- x = 'rain-man';
- alert( x );
- }
in , hasOwnProperty()
js 逻辑运算
1,把 a && b 运算 当成 if(a){ b },返回值为执行到的语句。
如:undefined && 1 // undefined
NaN && ""//NaN
[] && ""
0 && "" // 0
"" && 2//
null && 2//
总结 undefined NaN 0 “” null 在if()里都为 false
[] && ""
[] && "" // ""
true && "" // ""
{} && 1 // 报错 , 应该是这样 ({})&& 1
总结[] {}在if()里为true
2,把 a || b 当成 if(a) { } else {b}看,所以,返回值优先考虑 a ,a == true 返回 a, a == false 返回 b
3, ! ==
然而null却不是对象,所以没有constructor这个属性
function clone1(obj1)
{
function F() {} ;
F.prototype = obj1 ;
var f = new F() ;
for(var key in obj1)
{
if(typeof obj1[key] =="object")
{
f[key] = clone1(obj1[key])
}
}
return f ;
}
http://bbs.9ria.com/thread-188370-1-1.html
类型转换
Number(null) 0
Number(new Object()) NaN
var s1 = String(null); //"null"
var oNull = null;
var s2 = oNull.toString(); //won’t work, causes an error
3. 利用js变量弱类型转换
举个小例子,一看,就会明白了。
<script>
var str= '012.345 ';
var x = str-0;
x = x*1;
</script>
上例利用了js的弱类型的特点,只进行了算术运算,实现了字符串到数字的类型转换,不过这个方法还是不推荐的
dom操作,节点个数问题
[] == false