注:由于JavaScript的对象名称都是其引用而非其值,所以对对象名称做赋值操作只是进行一个引用赋值而非赋值,那么如何进行对象的复制?
JavaScript对象复制的方法:
**浅复制:**浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。
Object.assign({},myObject)
方法 **深复制:**但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
newObj=JSON.parse(JSON.stringify(oldObj))
方法,适用于 Number, String, Boolean, Array
,不适用于Function 、RegExp
对象/*
1、JavaScript中的对象有两种不同类型的属性:数据属性和访问器属性。
name和_job是数据属性,job是访问器。数据属性和访问器属性的最大的不同就在于:
当访问一个访问器属性时,得到get后面函数的返回值;给一个访问器属性赋值时,
执行的是set后面的函数,这个函数以赋的值为参数
2、JavaScript自动为它们创建了属性特性。在ES3中属性特性不可访问,
但是ES5中属性的特性可以通过Object.getOwnPropertyDescriptors或 Object.getOwnPropertyDescriptor得到:
*/
var person = {
age:29,
name: "Nicholas",
_job: "Software Engineer",
sayName: function(){
console.log(this.name);
},
getjob(){
return this._job;
},
setjob(newJob){
this._job=newJob;
}
}
person.setjob("qianduan")
console.log(person.getjob())
var descriptors= Object.getOwnPropertyDescriptors(person)
//descriptors的内容如下;
{
age:{value: 29, writable: true, enumerable: true, configurable: true}
name:{value: "Nicholas", writable: true, enumerable: true, configurable: true}
sayName:{writable: true, enumerable: true, configurable: true, value: ƒ}
_job:{value: "Coder", writable: true, enumerable: true, configurable: true}
}
/*
数据属性的描述符有四个属性:value,writable ,enumerable ,configurable ;
访问器属性的描述符也有四个属性:enumerable ,configurable,get,set
enumerable:属性是否可枚举,即能否通过for-in循环返回属性
configrable:属性是否可配置。即属性能否通过delete删除,能否修改属性的特性,
或者能否把属性修改为访问器属性
get:在读取属性时调用的函数。默认值为 undefined
set:在写入属性时调用的函数。默认值为 undefined
要修改属性默认的特性,
必须使用 ECMAScript 5 的 Object.defineProperty或 Object.defineProperties
*/
var person ={}
Object.defineProperty(person, "name", {
writable: false,
enumerable:true,
configurable:true,
value: "Nicholas"
});
console.info(person.name); //"Nicholas"
person.name = "Greg";
//writable为false,属性不可修改
console.info(person.name); //"Nicholas"
delete person.name
//访问器属性
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
set:function(newName){
console.info("set 被调用")
this._name=newName
},
enumerable:true,
configurable:true,
});
person.name;//get 被调用
person.name="John";//set 被调用
console.info("----------------------不设set 开始--------------------------------");
var person ={_name:"Nicholas"};
Object.defineProperty(person, "name", {
get: function(){
console.info("get 被调用")
return this._name
},
enumerable:true,
configurable:true,
});
person.name;//get 被调用
person.name="John";//没有设置set,什么也没发生
console.info(person.name)//Nicholas,
//在JavaScript中Object为顶级公民,所以字面量和内置对象其实都可以追溯到顶级公民Object,
//函数function则为以及公民
/*
其实a = 1就相当于a = new Number(1)。可以看到所有的内建对象以及Object的__proto__指向的都是
一个匿名函数,也就可以认为它们其实也是function的一个实例,所以之前会说function是一等公民
那么原型链到底是什么呢?我们展开a.__proto__也就是Number.prototype对象,它是没有
toString()的方法的,但是对于a来说它其实是可以调用toString的方法的,这就是原型链的作用。
沿着a的__proto__一直访问会到达Object的prototype,也就是说a调用toString方法最终其实是访
问Object.prototype的toString方法。那么a的原型链就是由Number.prototype和
Object.prototype组成,当a访问一个方法或属性时,它会先在自身查找,然后再沿原型链找,找到则调
用,没找到报错。
prototype是一个对象的属性集合,同时它本身也是一个对象,该prototype对象可以为当前对象提供内置
属性方法,也可以添加和修改属性及放方法!!
__proto__是一个指针,它指的是构造它对象的prototype
*/
Object.__proto__ //ƒ () { [native code] }指向一个函数
/*
js中只有对象,没有真正意义上的类,由于js无法创建类的多个实例,只能创建多个对象;;而且多个对象
只是相互引用,并没有进行复制多份的属性和方法,只是将新对象与prototype进行关联,
此类对象继承称为原型继承!!!
千万别被C++的类继承,多态,实例,构造误解,在C++中继承意味着含有复制操作,但是在js中,原型
继承只是将对象关联,并没有进行复制属性和方法的操作,可以说js理解为对象委托更为合理,也就是说
将新对象的属性和方法的使用委托于旧对象上,只有一份属性和方法的拷贝!!!
*/
function Foo(){...}
var a=new Foo()
//使用new将普通函数的调用变为创建新对象的构造函数!!
//事实上,新创建的对象并没有进行复制操作,只是将新对象a与Foo进行关联
var a=Foo//只是复制函数名字的一个引用,没有创建一个新对象!
//也就是说,在js中所有带new的函数调用都是构造函数,但普通函数却不是构造函数!
//通过 Obj instanceof Func判断对象obj原型链中是否含有指向Func.prototype
//使用Func.prototype.isPrototypeOf(obj)
//使用obj2.isPrototypeOf(obj1)判断两个对象是否关联
//使用obj.__proto__
Object.create()
和new创建对象的区别//使用Object.create()创建对象将新旧对象进行关联,但是不会像new一样生成.prototype和.constructor
//属性的引用!!
//
var anotherObj={
cool:function(){...}
}
var myObj=Object.create(anotherObj)
myObj.docool=function(){
this.cool()//实现内部函数委托机制
}
myObj.docool()
6.1、注:对于JavaScript而言,只有值具有类型,而变量随时持有任何类型的值,也就是说,js引擎并不要求
变量总是持有与初始值同类型的值,可以动态变换,总之记住一点js中只有值有类型,变量没有类型
变量在未持有值的时候,typeof返回undefined
6.2、使用typeof检查变量,防止出现reference error,即使用typeof进行安全防范检查机制
if(a){
console.log('a')
}//直接使用此检查,如果不存在真值a,就会报出reference error的错误,从而使程序无法继续执行
if(typeof a!==undefined){
console.log('a')
}//使用typeof进行安全检查机制,保证程序的顺利执行!
//特别注意,对于typeof p任意未声明的变量,其返回undefined而不是报出is not defined
//typeof对undefined和undeclared都会返回undefined,通过这个安全机制来检查undeclared
6.3、类型转换
/*其他类型转换为boolean类型
数据类型 转换为true的值 转换为false的值
Boolean true false
String 任何非空的字符串 ''空字符串
Number 任何非零数字值(包括无穷大) -0 0和NaN
Object 任何对象 null
Undefined 无 undefined
*/
Array数组对象,可容纳任意类型的值,可不需要预先设置大小,随时添加,修改数据,可以存在空白单元
可以通过字符面键值添加数据,但是不会计算在数组长度之类,使用delete删除数据,其数组长度也不会改变
最好数字索引使用数组,键值索引则使用对象
var r=[]
r["13"]=2
r.length//14
console.log(r[13])//2
//如果字符键值能够转换为数字,则会当做数字索引处理,并改变length的长度,如上创建14个长度的数组
//索引出存放值,其他都是undefined!!
//都可以使用length indexOf concat方法,但是由于字符串不可更改,字符数组还可使用
//toUpperCase push join map reverse
//如直接判断0.1+0.2===0.3 false因为
var a="foo"
.split("")
.reverse()
.join()
console.log(a)
/*
千万记住,浮点数变量不能直接比较大小,必须考虑计算机实际的存储数字的机制,而非仅仅只是数学上的
可以使用toFixed()指定小数位,使用toPrecision()指定有效位数
*/
NaN//值,是数字类型,只是该数字是一个无效的数字
NaN!=NaN//true ,由于NaN为一个非自反值,所以自己与自身不相等!
Number.isNaN(a)//必须通过此函数进行判断
+-infinity//无穷数,在js中一旦计算溢出,就会得到infinity
var a=1/0
//-0和0,在js中没有区别!只是返回结果形式不同
//比较的方式== 及=== 及Object.is(a1,a2)
Math() String() Number() Boolean() Array() Object() Function() RegExp() Date() Error()
/*
*/
var a=42
var b=a+""//隐式转换为字符串
/*
*/
var a=42
var b=String(a)//显示转换为字符串
obj.toString()
obj.toNumber()//true 1;;false 0;;undefined NaN;;null 0;;
obj.toBoolean()//null undefined 0 -0 NaN "" false均会转换为false
//注意:对于封装了假值的对象都是真值
var a=new Boolean(false)
var b=new Number(NaN)
var c=new String("")
a,b,c//均为真!
//记住空数组,空对象,空函数都是真值
var a=[]
var b={}
var c=function(){}
//区别于JSON.stringify()和JSON.parse()方法,不是强制转换,使用时注意只适用于JSON安全
//(符合JSON格式)的对象数据
~ | //位运算符的强制转换的使用变为-(x+1)
var x=-1
~x//0
~~ !!//位截除运算符为32的整数
var x=-35.1
~~x//-35
//解析机制允许出现非法字符,解析到非法字符即停止,但是转换不允许出现,否则返回失败值
var a="42"
var b="42px"
Number(a)//42
parseInt(a)//42
Number(b)//NaN
parseInt(b)//42