JS高级知识总结 
执行上下文,作用域,this指向,闭包,箭头函数相关内容查看文章[深入理解js - AzirKxs的博客 | 分享与记录](http://8.130.40.222/cn/base05-  深入理解js/)
严格模式 
简介 
开启严格模式会以更加严格的方式对代码进行检测和执行,使代码脱离“懒散(sloppy)“模式
严格模式有如下限制
严格模式的限制 
1.无法意外的创建全局变量
2.引起静默(不报错也没有任何效果)错误抛出异常 ,例如更改只读属性,删除不可删除的属性时报错
3.不允许函数参数有相同的名称
4.不允许0的八进制语法
5.不允许使用with
6.eval不能创建外层变量
7.this不会默认转成对象类型(非严格模式下undefined和null都会转化为window)
属性描述符 
可以通过Object.defineProperty对一个对象的属性的描述符进行配置
数据属性描述符 
value该属性对应的值,默认undefined 
configurable该属性描述符是否可被改变、是否可被删除,默认为false 
enumerable该属性是否可被枚举,默认为false 
writable该属性是否可以被写入新的值,默认为false 
 
存取属性描述符 
存储属性描述符(Accessor Properties)
get当访问该属性时,会调用此函数,默认为undefined。 
set当属性值被修改时,会调用此函数,默认为undefined。 
 
 
 
注意,get、set描述符与vaule、writable描述符不共存。
获取对象属性描述符 
getOwnPropertyDescriptor
getOwnPropertyDescriptors
阻止对象扩展属性 
Object.preventExtensions
密封对象 
Object.seal() 不允许配置和删除属性
实际上就是调用preventExtensions并且修改configurable:false
冻结对象 
Object.freeze()不能进行写入
实际上是调用seal并且修改writable:false
原型、原型链 
对象的原型 
每个对象都有自己的原型
获取原型对象 
obj.__ prototype __(隐式原型,由浏览器提供,有个别浏览器访问不到)
Object.getPrototypeOf()
原型的作用 
当我们通过[[get]]方式获取一个属性对应的value时,它会优先在自己的对象中查找,如果找到直接返回,如果没有找到则会去原型对象中查找
函数的原型 
函数也可以看做是一个对象,因此也有proto属性
获取函数的原型对象 
 
new操作中的原型 
new操作的步骤如下:
1.创建一个空对象
2.将对象赋值给this
3.对象内部的[[prototype]]属性会被赋值为该构造函数的[[prototype]]属性(将函数的显式原型赋值给对象的隐式原型)
4.执行函数中的代码体
5.将这个对象默认返回
当多个对象拥有共同的值的时候,我们可以将它放到构造函数的原型上, 这样做的好处是节省空间
1 2 3 4 5 6 7 8 9 10 11 function  student (name,age ) {    this .name = name     this .age = age } student.prototype.eat = function ( ) {     console .log(`${this .name} 正在吃饭` ) } let  kxs = new  student('kxs' ,22 )kxs.eat()  
 
constructor 
每个原型上都会添加一个属性叫constructor,这个属性指向当前函数对象
原型链 
原型链是由原型所构成的,当我们从一个对象上获取属性的时候,如果当前对象中没有就会在它的原型链上获取
1 2 3 4 let  a = new  foo();console .log(a.__proto__) console .log(a.__proto__.__proto__) console .log(a.__proto__.__proto__.__proto__) 
 
原型链继承 
Object是所有类的父类,所有类都是Object类的子类
原型链继承的实现 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function  Person (name,age ) {    this .name = name;     this .age = age;     this .info ={         msg:'该信息会被子类共享'      } } let  p = new  Person('azir' ,22 )function  Student (name,age,height,address ) {    this .name = name     this .age = age     this .height = height     this .address = address } Student.prototype = p let  me = new  Student('azir' ,22 ,175 ,'china' )let  you = new  Student('kxs' ,22 ,185 ,'china' )me.info.msg = '更改信息'  console .log(me)console .log(you)console .log(me.info.msg) console .log(you.info.msg) 
 
优点:
父类方法可以复用
缺点:
在原型上创建了属性,此时,多个子类的实例将共享同一个父类的属性 
子类型实例不能给父类型构造函数传参 
父类引用属性将被子类共享 
 
改进 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function  Person (name,age ) {    this .name = name;     this .age = age;     this .info ={         msg:'该信息会被子类共享'      } } function  Student (name,age,height,address ) {    this .height = height     this .address = address     const  prototype = new  Person(name,age)     this .__proto__ = prototype } let  me = new  Student('azir' ,22 ,175 ,'china' )let  you = new  Student('kxs' ,22 ,185 ,'china' )
 
问题:
在原型链上创建了属性(一般来说,这不是一种好的实践) 
私自篡改__proto__ 
 
1 2 console .log(me instanceof  Student) console .log(me.__proto__ === Student.prototype) 
 
盗用构造函数 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function  Person (name,age ) {    this .name = name;     this .age = age; } function  Student (name,age,height,address ) {    Person.call(this ,name,age)     this .height = height     this .address = address } let  me = new  Student('azir' ,22 ,175 ,'china' )console .log(me)
 
优点:
可以在子类构造函数中向父类传递参数
 
父类的引用属性不会被共享
 
 
缺点:
子类不能访问父类原型上定义的方法(即不能访问Parent.prototype上定义的方法),因此所有方法属性都写在构造函数中,每次创建实例都会初始化 
 
组合继承 
组合继承结合了原型链继承和盗用构造函数继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 function  Person (name,age ) {    this .name = name;     this .age = age; } function  Student (name,age,height,address ) {    Person.call(this ,name,age)     this .height = height     this .address = address } Student.prototype = new  Person() let  me = new  Student('azir' ,22 ,175 ,'china' )console .log(me)
 
优点:
父类的方法可以复用 
可以在Child构造函数中向Parent构造函数中传参 
父类构造函数中的引用属性不会被共享 
 
缺点:
父类构造函数调用了两次
借用的构造函数中的name和age属性没有存在的必要
寄生组合式继承 
寄生组合式继承不在依赖父类的实例对象来实现继承,而依赖一个新的构造函数,使该构造函数的原型指向父类的原型
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 function  creatObject (o ) {    function  f ( )  {};     f.prototype = o     return  new  f() } function  inherit (subType,superType ) {    subType.prototype = creatObject(superType.prototype)     Object .defineProperty(subType.prototype,'constructior' ,{         enurmable:false ,         configurable:true ,         writable:true ,         value:subType     }) } function  Person (name,age ) {    this .name = name;     this .age = age; } function  Student (name,age,height,address ) {    Person.call(this ,name,age)     this .height = height     this .address = address } inherit(Student,Person); let  me = new  Student('azir' ,22 ,175 ,'china' )console .log(me)
 
图示
优点:
只调用一次父类构造函数 
Child可以向Parent传参 
父类方法可以复用 
父类的引用属性不会被共享 
 
Function和Object的关系 
Object是Function的父类 
Function是Object的构造函数 
 
用一张图描述:
最后的null是为了避免死循环而设计的
类方法 
添加到原型上的方法不能够通过类名直接调用
1 2 3 4 5 6 7 8 9 10 function  foo (name,age ) {    this .name = name     this .age = age } foo.prototype.running = function ( ) {     console .log('running~' ) } foo.running()  
 
那是因为foo本身没有running属性,因此会去隐式原型上找,而foo的隐式原型式Function的显式原型,因此找不到,在原型上添加的方法也可以被称之为实例方法
正确添加类方法的方式是作为构造函数对象本身的属性添加
1 2 3 4 5 6 7 8 9 10 function  foo (name,age ) {    this .name = name     this .age = age } foo.running = function ( ) {     console .log('running~' ) } foo.running()  
 
对象的方法补充 
hasOwnProperty() 判断对象自己是否有某个属性
in() 判断原型上是否有某个属性/for in 遍历原型上的属性(不包括不可枚举的属性)
instanceof () 检测某个对象是否是某个构造函数的实例(检测构造函数的prototype,是否出现在了实例对象的原型链上)
isPrototypeOf() 用于检测某个对象,是否出现在了某个实例对象的原型链上
ES6中的类 
使用class定义类 
ES6中可以直接使用class关键字来定义一个类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class  Person   {         constructor (name,age ) {         this .name = name         this .age = age     }               running ( ) {         console .log('running~' )     } } let  p = new  Person('azir' ,22 )
 
使用class定义的类与用构造函数定义的类没有什么异同,唯一的区别是使用class定义的类不能作为一个函数去调用
访问器get与set 
当读取对象的属性时回调用get方法,更改属性时会调用set方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class  Person   {         constructor (name,age ) {         this ._name = name         this ._age = age     }               running ( ) {         console .log('running~' )     }          get  name (){         return  this ._name     }          set  name (value ){         this ._name = value     } } let  p = new  Person('azir' ,22 )console .log(p.name) p.name = 'kxs'  console .log(p.name) 
 
静态方法 
类方法也叫做静态方法,可以通过类直接调用(不能通过实例对象调用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class  Person   {         constructor (name,age ) {         this ._name = name         this ._age = age     }               running ( ) {         console .log('running~' )     }          get  name (){         return  this ._name     }          set  name (value ){         this ._name = value     }          static  test ( ) {         console .log('这是一个静态方法' )     } } let  p = new  Person('azir' ,22 )console .log(p.name) p.name = 'kxs'  console .log(p.name) Person.test() 
 
继承 
ES6引入了extends和super关键字来实现继承
extends和super实现继承  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class  Person   {    constructor (name,age ) {         this ._name = name     	this ._age = age     }          running ( ) {         console .log('running~' )     }      } class  Student  extends  Person  {    constructor (name,age,height,id ) {         super (name,age)         this ._height = height         this ._id = id     }     get  info (){         return  `姓名:${this ._name}            年龄:${this ._age}           身高:${this ._height}           学号:${this ._id} `     } } let  p = new  Student('azirkxs' ,18 ,175 ,'2019006152' )console .log(p.info)p.running() 
 
super关键字 
super可以用于继承,super必须放在构造函数的第一行使用
super也可以用来调用父类的方法
mixin混入实现多继承 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 function  mixinAnimal (baseClass ) {    return  class  extends  baseClass  {         running ( ) {             console .log('running~' )         }     } } function  mixinFlying (baseClass ) {    return  class  extends  baseClass  {         flying ( ) {             console .log('flying~' )         }     } } class  Bird  {    eating ( ) {         console .log('eating~' )     } } class  NewBird  extends  mixinFlying (mixinAnimal (Bird )) {     } console .log(new  NewBird())
 
         
        
        
        
        
        
  
    
      如果这篇文章对你有帮助,可以bilibili关注一波 ~ !此外,如果你觉得本人的文章侵犯了你的著作权,请联系我删除~谢谢!