作用域
我们知道,Javascript的变量采用链式作用域。读取变量的时候,先在当前作用域寻找该变量,如果找不到,就前往上一层的作用域寻找该变量。这样的设计,使得读取局部变量比读取全局变量快得多。
读取全局变量:
var a = 0;
function x(){
a += 1;
}
读取局部变量:
function y(){
var a = 0;
a += 1;
}
第二段代码读取变量a的时候,不用前往上一层作用域,所以要比第一段代码快五六倍。
prototype模式:
var X = function(name){ this.name = name; }
X.prototype.get_name = function() { return this.name; };
closure模式:
var Y = function(name) {
var y = { name: name };
return { 'get_name': function() { return y.name; } };
};
同样是get_name()方法,closure模式更快。
iframe嵌套
"window.location.href"、"location.href"是本页面跳转
"parent.location.href"是上一层页面跳转
"top.location.href"是最外层的页面跳转
举例说明:
如果A,B,C,D页面,引入iframe进行页面嵌套,
D是C的iframe,C是B的iframe,B是A的iframe,
如果D中js这样写
"window.location.href"、"location.href":D页面跳转
"parent.location.href":C页面跳转
"top.location.href":A页面跳转
现在终于明白了连接的时候target的用法了:
_blank:重新打开一个窗口
_parent:父窗口执行重定向
_self:自身页面重定向
_top:第一个父窗口重定向
综上所述可知:parent.window:父窗口对象 top.window:第一个父窗口的对象。
对象
对象属性描述符的类型分为两种:数据属性和访问器属性。
数据属性包含一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个特性。
1、configurable(可配置性)
可配置性决定是否可以使用delete删除属性,以及是否可以修改属性描述符的特性,默认值为true。
2、enumerable(可枚举性)
可枚举性决定属性是否出现在对象的属性枚举中,比如是否可以通过for-in循环返回该属性,默认值为true。
3、writable(可写性)
可写性决定是否可以修改属性的值,默认值为true。
4、value属性值)
属性值包含这个属性的数据值,读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。默认值为undefined。
对象属性是名字、值和一组属性描述符构成的。而属性值可以用一个或两个方法替代,这两个方法就是getter和setter。而这种属性类型叫访问器属性。
1、getter
在读取属性时调用的函数。默认值为undefined。
2、setter
在写入属性时调用的函数。默认值为undefined。
和数据属性不同,访问器属性不具有可写性(writable)。如果属性同时具有getter和setter方法,那么它是一个读/写属性。如果它只有getter方法,那么它是一个只读属性。如果它只有setter方法,那么它是一个只写属性。读取只写属性总是返回undefined。
可枚举性(enumerable)
可枚举性决定属性是否出现在对象的属性枚举中,具体来说,for-in循环、Object.keys()、JSON.stringify()是否会取到该属性。
用户定义的普通属性默认是可枚举的,而原生继承的属性默认是不可枚举的。
对象拷贝
对象拷贝分为浅拷贝(shallow)和深拷贝(deep)两种。浅拷贝只复制一层对象的属性,并不会进行递归复制。深拷贝不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深拷贝的方法递归复制到新对象上,拷贝了所有层级。
浅拷贝
【方法一】简单拷贝
新建一个空对象,使用for-in循环,将对象的所有属性复制到新建的空对象中。
function simpleClone1(obj){
if(typeof obj != 'object'){
return false;
}
var cloneObj = {};
for(var i in obj){
cloneObj[i] = obj[i];
}
return cloneObj;
}
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=simpleClone1(obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3,4]
【方法二】Object.assign()
Object.assign()方法实行的是浅拷贝,而不是深拷贝。Object.assign()方法可以接受任意数量的源对象,并按指定的顺序将属性复制到接收对象中。在对象合并的过程中,Object.assign()拷贝的属性是有限制的,只拷贝源对象的自身属性(不拷贝继承属性),也不拷贝不可枚举的属性(enumerable: false。
var obj1 = {a: {b: 1}};
var obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
【方法三】使用属性描述符
通过对象的原型,建立一个空的实例对象。通过forEach语句,获取到对象的所有属性的属性描述符,将其作为参数,设置到新建的空实例对象中。本质上跟方法一是一回事,这种方法更为灵活,可以为对象属性设置需要的描述符。
function simpleClone2(orig){
var copy = Object.create(Object.getPrototypeOf(orig));
Object.getOwnPropertyNames(orig).forEach(function(propKey){
var desc = Object.getOwnPropertyDescriptor(orig,propKey);
Object.defineProperty(copy,propKey,desc);
});
return copy;
}
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=simpleClone1(obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3,4]
【方法四】使用jquery的extend()方法,还可以用lodash等js库。
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=$.extend({},obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3,4]
深拷贝
【方法一】遍历复制
复制对象的属性时,对其进行判断,如果是数组或对象,则再次调用拷贝函数;否则,直接复制对象属性。
function deepClone1(obj,cloneObj){
if(typeof obj != 'object'){
return false;
}
var cloneObj = cloneObj || {};
for(var i in obj){
if(typeof obj[i] === 'object'){
cloneObj[i] = (obj[i] instanceof Array) ? [] : {};
arguments.callee(obj[i],cloneObj[i]); // 递归
}else{
cloneObj[i] = obj[i];
}
}
return cloneObj;
}
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=deepClone1(obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3]
【方法二】json
用JSON全局对象的parse和stringify方法来实现深复制算是一个简单讨巧的方法,它能正确处理的对象只有Number、String、Boolean、Array、扁平对象,即那些能够被json直接表示的数据结构。
function jsonClone(obj){
return JSON.parse(JSON.stringify(obj));
}
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=jsonClone(obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3]
【方法三】使用jquery的extend()方法
var obj1={a:1,b:2,c:[1,2,3]};
var obj2=$.extend(true,{},obj1);
console.log(obj1.c); //[1,2,3]
console.log(obj2.c); //[1,2,3]
obj2.c.push(4);
console.log(obj2.c); //[1,2,3,4]
console.log(obj1.c); //[1,2,3]