深入理解JavaScript之3

深入理解JavaScript之3

文章目录

  • 深入理解JavaScript之3
    • 1.JavaScript对象的复制和赋值
    • 2.JavaScript的对象属性及属性特性
    • 3.JavaScript的原型链
    • 4.使用`Object.create()`和new创建对象的区别
    • 5.JavaScript的函数及对象委托机制
    • 6.深入JavaScript的类型及转换
    • 7.重要的s/String、Array、n/Number
    • 8.九大复杂类型其实也可以视作为原生的函数
    • 9.JavaScript的类型转换机制(按照值类型为基准而非变量)和解析机制

1.JavaScript对象的复制和赋值

注:由于JavaScript的对象名称都是其引用而非其值,所以对对象名称做赋值操作只是进行一个引用赋值而非赋值,那么如何进行对象的复制?

JavaScript对象复制的方法:

​ **浅复制:**浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

  • 使用Object.assign({},myObject)方法
  • 直接使用赋值语句

​ **深复制:**但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

  • 使用可转化为JSON的newObj=JSON.parse(JSON.stringify(oldObj))方法,适用于 Number, String, Boolean, Array,不适用于Function 、RegExp对象

2.JavaScript的对象属性及属性特性

/*
	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,

3.JavaScript的原型链

//在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__

1542523615457

4.使用Object.create()和new创建对象的区别

//使用Object.create()创建对象将新旧对象进行关联,但是不会像new一样生成.prototype和.constructor
//属性的引用!!

5.JavaScript的函数及对象委托机制

//
var anotherObj={
    cool:function(){...}
}
var myObj=Object.create(anotherObj)
myObj.docool=function(){
	this.cool()//实现内部函数委托机制
}
myObj.docool()

6.深入JavaScript的类型及转换

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

*/

7.重要的s/String、Array、n/Number

  • 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)
  • 数字number
/*
	千万记住,浮点数变量不能直接比较大小,必须考虑计算机实际的存储数字的机制,而非仅仅只是数学上的
		可以使用toFixed()指定小数位,使用toPrecision()指定有效位数
*/
NaN//值,是数字类型,只是该数字是一个无效的数字

NaN=NaN//true ,由于NaN为一个非自反值,所以自己与自身不相等!
Number.isNaN(a)//必须通过此函数进行判断

+-infinity//无穷数,在js中一旦计算溢出,就会得到infinity
var a=1/0

//-0和0,在js中没有区别!只是返回结果形式不同

//比较的方式== 及=== 及Object.is(a1,a2)

8.九大复杂类型其实也可以视作为原生的函数

Math() String() Number() Boolean() Array() Object() Function() RegExp() Date() Error()

9.JavaScript的类型转换机制(按照值类型为基准而非变量)和解析机制

  • 隐式转换
/*

*/
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

你可能感兴趣的:(深入理解JavaScript之3)