JS深入学习知识整理


属性与原型
function foo(){this.add = function(){};}
②foo.prototype.add = function(){};
①中的add是属性;②中的add是原型。
当调用foo.add时,查询顺序:foo属性--->foo原型--->Object原型
foo.prototype.hasOwnProperty(prop);判断prop是否为foo的自身属性。
delete只能删除属性(除了window对象的属性和 configurable=false 的属性),不能删除原型
 

原型链和构造函数
function Foo(name){
  this.name=name;
}
Foo.prototype.run=function(){};
var f = new Foo("Test");

注:IE中不支持__proto__。
f.__proto__===Foo.prototype //true
f.__proto__.run === Foo.prototype.run //true
f.run ===f.__proto__.run //true
f.constructor ===Foo //true
Foo.prototype.constructor === Foo //true 

继承方式中易犯的错误:

Son.prototype = Father.prototype

这时如果修改Son的原型链,Father的原型也会被修改

原因:Son继承的是Father的原型链地址,所以修改的也是该地址的内容。

 


闭包

简单的定义:有权访问另一个函数作用域中的变量的函数。
从理论角度:所有的函数。因为任意函数在创建之初就已将外层上下文保存起来了。 哪怕是简单的全局变量也是如此,因为函数中访问全局变量就相当于是在访问自由变量,这个时候使用最外层的作用域。 从实践角度:以下函数才算是闭包: 即使创建它的上下文已经销毁,它仍然存在(比如,内部函数从父函数中返回)在代码中引用了自由变量

闭包很强大,但是不合理的应用也是会付出代价的,因为创建闭包必须维护额外的作用域,这可能会占用大量内存。

因为IE8以下版本垃圾回收机制的问题,如果闭包的作用域链中保存着DOM元素,则该元素无法被回收。即传说中的内存泄露

可参照IE内存泄露分析 。Demo:

var but = document.getElementById("button1");
var text = document.getElementById("textbox1");
but.onclick = function() {
    /*现在是在闭包中*/
    alert(text.value);
};

对应方法:

var but = document.getElementById("button1");
var text = document.getElementById("textbox1");
var textValue = text.value;
but.onclick = function() {
    /*现在是在闭包中*/
    alert(textValue);
};
即 把闭包中的DOM元素通过其他方式去除。不过这在工作中,显然不太容易。。。

 


执行上下文

JS中仅有函数能创建新的作用域。if,while,for...则不能。如下
for(var i=0;i<2;i++){}
alert(i);
此时不会出现 ReferenceError 。

数组元素的this指向该数组对象,例如
var arr = [function(){return this;},3,"SS"];
则 arr[0]()===arr;

 


typeof 与 instanceof

typeof 只能用来判断变量属于哪一种基本类型,即string,boolen,function等等

instanceof 用于判断对象的从属关系
例如 var foo = new Foo();
则 foo instanceof Foo===true
在ES5中可以用getPrototypeOf或isPrototypeOf来完成相同功能
例如 Object.getPrototypeOf(foo) === Foo
Foo.prototype.isPrototypeOf(foo)

 


arguments:对象当前所执行的函数;不是数组,但访问方式与数组相同;可用于模拟方法重载。

属性:
length 当前方法的传过来的参数个数;
callee  当前正在执行的Function对象,且仅当改函数正在执行时才可用,常用于递归运算(同样适用于匿名函数)
例如 function foo(a,b,c){...}  foo(1,3);
arguments.callee===foo //true
arguments.length ===2 //true
foo.length === 3 //true 且只读(即使赋值foo.length=10,输出的时候foo.length仍然为3)
arguments.length与foo.length的区别在于,前者是实参个数,后者是形参个数

 

组件模式(紧耦合增益):

var Module = (function(obj){
    obj.old_Method = obj.Method;
    obj.Method = function(){...};
    return obj;
}(Module ||  {}));

 


 函数表达式

函数声明与函数表达式的区别:

①通过函数声明定义的函数在进入上下文阶段就已经创建;如

function A(){
    ....
}

②而函数表达式则先定义一个变量,当代码执行时才将匿名函数赋给该变量。如

var B = function(){
    ....
}

二者还有个区别就是二者的name属性不同。函数声明的name是方法名,而函数表达式的name则为空字符串.


 

对构造函数和一般的函数来说,搞清this所指向的对象并不困难。但匿名函数就比较头晕了。就向下面的这段东东

function A(){
    console.log(this);
    eval('console.log(this)');
    (function(){
        console.log(this);
        eval('console.log(this)');
    })()
}
new A()

匿名函数的执行环境具有全局性,因此其中的this对象通常指向window


 

获取对象属性名

Object.keys(obj)//感觉这个方法不错,不仅仅是JS对象,连DOM对象的属性名也可以获取


 使用JavaScript修改DOM树(考虑性能)

浏览器下载完页面中的所有组件之后会解析生成DOM树、渲染树两个数据结构,然后开始绘制页面元素;
当DOM的变化影响了元素的几何属性,会导致浏览器重新构造渲染树,这个过程叫做重排。
重排之后浏览器会重新绘制受影响的部分到屏幕,这个过程叫做重绘。
而重排和重绘都是代价昂贵的操作,会使web应用程序的UI反应迟钝。
所以在需要对DOM元素进行一系列操作时,要将重绘和重排最小化:
(1)使元素脱离文档流;
(2)对其应用多重改变;
(3)将元素带回文档中;
有三种方法可以使DOM脱离文档:

//1:隐藏元素,应用修改,重新显示;如
var div = document.getElementById("xx");
div.style.display = "none";
//TODO
div.style.display = "";

//2:使用文档片段,在当前DOM之外构建一个子树,再把它拷贝回文档;如
var cdf = document.createDocumentFragment();
var child;
for(var i = 0;i<100;i++){
    child = document.createElement("div");
    cdf.appendChild(child);
}
document.body.appendChild(cdf);
//3:将原始元素拷贝到一个脱离文档的节点中,修改副本,完成后再替换原始元素;

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2012-09-12 10:33  TiestoRay  阅读(579)  评论(0编辑  收藏  举报