JS数据类型
var str = 'abc';
var num = 123;
var bool = true;
var und = undefined;
var n = null;
var arr=['x','y','z'];
var obj = {};
var fun = function() {};
console.log(typeof str); //string
console.log(typeof num); //number
console.log(typeof bool); //boolean
console.log(typeof und); //undefined
console.log(typeof n); //object
console.log(typeof arr); //object
console.log(typeof obj); //object
console.log(typeof fun); //function
对象
对象常用属性和方法
SON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串; JSON.parse() 方法用于将一个 JSON 字符串转换为对象。
hasOwnProperty() 该方法可以判断对象的自有属性是否存在
assign() 该方法主要用于对象的合并,Object.assign(o1,o2)
defineProperties()直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
keys() 返回一个由一个给定对象的自身可枚举属性组成的数组,Object.keys(o);
values();返回一个给定对象自己的所有可枚举属性值的数组
entries();返回一个给定对象自身可枚举属性的键值对数组
属性的设置和获取
1、设置属性
var obj = {};
obj.name='aaaa';
obj['age'] = 20;
2、获取属性
obj.name;
obj['age'];
3、属性的删除
var o2= { name:'abc', age:18 };
delete o2.name;
console.log(o2);
检测属性
检测属性 该方法可以判断对象的自有属性是否存在
in 运算符 检测属性是否存在于某个对象中,自有属性和继承属性都返回true
var obj={ name:'sonia', age:22 };
console.log('name' in obj);//自有属性
引用类型如何深拷贝
//引用类型深拷贝?结果证明是浅拷贝
//如果对象只有一级属性,Object.concat可以实现深拷贝
var arr1 = [1,2,3,[4,5]]
var arr2 = arr1.concat()
arr1.push(11)
arr1[3][0]=100;
console.log(arr1);
console.log(arr2);//Object.assign对于对象1级属性,可以是深拷贝,多级属性是浅拷贝
var o1= {id:10}
var o2 = Object.assign({},o1);
o1.id = 100
console.log(o1.id);
console.log(o2.id);var o1= {id:10,test:'o1',children:{v:'o1'}}
var o2 = Object.assign({},o1);
o1.id = 100
o1.children.v='v2';
console.log(o1);
console.log(o2);
最简单的深拷贝方法是序列化
var obj = {name: "fangfang",age: 18,children: { id: 1 },};var obj2 = JSON.parse(JSON.stringify(obj));obj.name = "alice";obj2.children.id = 99;console.log(obj);console.log(obj2);
但是序列化实现深拷贝有很多坑:
- 如果obj里存在时间对象,JSON.parse(JSON.stringify(obj))之后,时间变成了字符串
- 如果obj里有RegExp、Error对象,则序列化后的结果只得到空对象
- 如果obj里有函数、undefined,则序列化的结果会把函数undefined丢失
- 如果obj里有NaN,Infinity,则序列化的结果会变成null
- JSON.stringify只能序列化对象的可枚举的自有属性。如果obj中的对象是由构造函数生成的,则使用JSON.parse()深拷贝后,会丢弃对象的constructor
- 如果对象中存在循环引用的情况,也无法进行正确的深拷贝
自定义深拷贝方法
function deepCopy(newObj, obj) {var o = newObj;for (var key in obj) {if (typeof obj[key] === "object") {//判断obj[key]的类型,是数组还是对象,使用constructor严格判断对象是由谁构造出来的o[key] = obj[key].constructor === Array ? [] : {};deepCopy(o[key], obj[key]);} else {o[key] = obj[key];}}return o;}
预解析
JavaScript预解析,可以理解为把变量或者函数预先解析到使用的环境中
console.log(a);
var a = 10;
//结果输出undefined
预解析过程
第一步:预先解析var、function等,提升声明变量
第二步:预解析完毕后,逐行正常由上而下解析
f();//error
//函数表达式
var f = function () {};fn();//OK
//函数声明
function fn() {}//函数表达式和函数声明的最大区别是:预解析。函数声明有预解析功能
//也就是function声明的函数会在执行前提前解析
如果变量名和函数名相同了,谁的优先级高?
console.log(f);
function f(){console.log("456");
}
var f = 123;
//结果输出:[Function: f]console.log(f);
var f = 123;
function f(){console.log("456");
}
//结果还是输出:[Function: f]
同名函数和变量,函数的优先级会更高,也就是函数取代变量。
方法内部也存在预解析:
var b = 10;function f3() {console.log(b);var b = 100;}f3(); //undefined/**************解析过程***************/var b;function f3(){}b=10;f3();//f3方法内部预解析var b;console.log(b);//此时是undefinedb=100;
作用域
作用域:它是指对某一变量和方法具有访问权限的代码空间,在JS中, 作用域是在函数中维护的。
表示变量 或函数起作用的区域,指代了它们在什么样的上下文中执行,亦即上下文执行环境
ES5的作用域只有两种:全局作用域和局部作用域(局部作用域又叫函数作用域)
var a = 1;
//if(true)的语句执行完成之后会自动销毁,从而将var a = 10,提升为全局变量
if (true) {
var a = 10;
}
console.log(a); //输出10
全局变量和局部变量同名的坑:
1、在全局变量和局部变量不同名时,其作用域是整个程序
2、在全局变量和局部变量同名时,全局变量的作用域不包含同名局部变量的作用域
var c = 30;
function f2(){var c;console.log(c);
}
f2();//undefined
作用域链
执行函数的时候,先从函数内部寻找变量,如果找不到,会向创建函数的作用域内寻找变量
var a = 1;function f1() {var a = 10;function f2() {var a = 20;console.log(a);//20}function f3() {console.log(a);//10}f2();f3();}f1();console.log(a);//1