导航

  • 2021/07/21更新
  • 2021/07/22更新

[[深刻01] 执行上下文](https://juejin.im/post/684490...
[[深刻02] 原型链](https://juejin.im/post/684490...
[[深刻03] 继承](https://juejin.im/post/684490...
[[深刻04] 事件循环](https://juejin.im/post/684490...
[[深刻05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490...
[[深刻06] 隐式转换 和 运算符](https://juejin.im/post/684490...
[[深刻07] 浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...
[[深刻08] 前端平安](https://juejin.im/post/684490...
[[深刻09] 深浅拷贝](https://juejin.im/post/684490...
[[深刻10] Debounce Throttle](https://juejin.im/post/684490...
[[深刻11] 前端路由](https://juejin.im/post/684490...
[[深刻12] 前端模块化](https://juejin.im/post/684490...
[[深刻13] 观察者模式 公布订阅模式 双向数据绑定](https://juejin.im/post/684490...
[[深刻14] canvas](https://juejin.im/post/684490...
[[深刻15] webSocket](https://juejin.im/post/684490...
[[深刻16] webpack](https://juejin.im/post/684490...
[[深刻17] http 和 https](https://juejin.im/post/684490...
[[深刻18] CSS-interview](https://juejin.im/post/684490...
[[深刻19] 手写Promise](https://juejin.im/post/684490...
[[深刻20] 手写函数](https://juejin.im/post/684490...

[[react] Hooks](https://juejin.im/post/684490...

[[部署01] Nginx](https://juejin.im/post/684490...
[[部署02] Docker 部署vue我的项目](https://juejin.im/post/684490...
[[部署03] gitlab-CI](https://juejin.im/post/684490...

[[源码-webpack01-前置常识] AST形象语法树](https://juejin.im/post/684490...
[[源码-webpack02-前置常识] Tapable](https://juejin.im/post/684490...
[[源码-webpack03] 手写webpack - compiler简略编译流程](https://juejin.im/post/684490...
[[源码] Redux React-Redux01](https://juejin.im/post/684490...
[[源码] axios ](https://juejin.im/post/684490...
[[源码] vuex ](https://juejin.im/post/684490...
[[源码-vue01] data响应式 和 初始化渲染 ](https://juejin.im/post/684490...

构造函数的毛病

  • 通过构造函数生成实例对象,属性和办法都生成在实例上,多个实例之间属性和办法不能共享

prototype属性

  • javaScript的继承机制的设计思维:原型对象的所有属性和办法都能被实例对象所共享
  • 所有的函数都有一个prototype属性,指向一个对象
  • 对于构造函数来说:在构造函数生成实例的时候,构造函数的prototype属性会成为实例对象的原型

原型对象

  • 原型对象上的属性不是实例对象本身的属性,只有批改原型对象,变动就会立即反馈到所有实例对象上
  • 如何实例对象和原型对象有同名的属性和办法,则实例对象读取该属性时,会读取本身的属性,而不会读取原型上的属性
  • 原型对象的作用:定义所有实例共享的属性和办法

原型链

  • js规定,所有对象都有原型对象
  • 所有对象都能够成为其余对象的原型,原型对象也是对象,也有本人的原型,造成一个链条
  • 一层层上溯,最终都会上溯到Object.prototype,即Object构造函数的prototype属性
  • 即所有对象都继承了 Object.prototype 对象上的属性和办法,这就是所有对象都具备valueOf和toString的起因
  • Object.prototype的原型是null,null没有任何属性和办法,也没有本人的原型,原型链终止
  • null是为了避免死链

笼罩 overriding

  • 读取对象的属性时,本身和原型上有同名的属性和办法,优先读取本身属性,这叫做笼罩
  • 读取对对象的属性时,本身没有会到原型上找,原型没有会到原型的原型上找,直到Object.prototype,还是没有返回undefined
  • 一级级向上,在整个原型链上寻找某个属性,对性能是有影响的。
  • overriding:笼罩的意思

    function A(){} //---------------------- 定义构造函数AA.prototype = new Array() // ---------- 将A.prototype指向实例数组,那么A的实例就能继承数组原型链上的属性和办法A.prototype.constructor = A // -------- 批改prototype的同时,也要批改constructor避免意外const a = new A()a.push(1)a instanceof Array // true

constructor

  • prototype对象有一个constructor属性,默认指向prototype属性所在的构造函数
  • 因为constructor属性在prototype对象上,所以constructor属性被所有实例继承
  • 作用:

    • (1) constructor的作用是,能够得悉一个实例对象,到底是由哪个构造函数产生的
    • (2) constructor的另一个作用:能够用一个实例新建另一个实例
  • 留神:<font color=red>constructor示意原型对象和构造函数之间的关连关系,如果批改原型对象,个别会同时批改constructor属性,避免援用的时候报错,=> 因为批改了prototype之后,A.prototype.constructor指向的曾经不是A了,而是最新赋值给prototype对象的对象指向的那个constructor</font>
  • 批改原型对象要一起批改构造函数,避免援用报错!!!!!!!
  • name属性

    • constructor.name => 构造函数名
    <script>function A(){}const a = new A()console.log(A.prototype.constructor === A) // trueconsole.log(a.constructor === A.prototype.constructor) // true,constructor属性在prototype对象上,所以能被实例继承并拜访console.log(a.constructor === A) // true,constructor的作用是能够确定实例由哪个构造函数产生console.log(a.constructor === RegExp) // falseconsole.log(a.hasOwnProperty('constructor'), "a.hasOwnProperty('constructor')") // constructor不是实例本身属性,继承的console.log(new a.constructor(), 'constructor的另一个作用: 一个实例能够借助constructor新建另一个实例')const b = new a.constructor()console.log( b instanceof A) // true , 即b是A的其中一个实例</script>
    constructorconstructor示意原型对象和构造函数之间的关联关系,批改prototype,须要同时批改constructor,避免援用出错<script>function A () {  console.log('A构造函数')}console.log(A.prototype, '批改之前的A.prototype')console.log(A.prototype.constructor, '批改之前的A.prototype.constructor') // Aconsole.log(A.prototype.constructor.name, '批改之前的A.prototype.constructor.name => 批改前的constrctor名称')A.prototype = {name: 'woow_wu7'}console.log(A.prototype.constructor, '批改之后的A.prototype.constructor') // Objectconsole.log(A.prototype.constructor.name, '批改之后的A.prototype.constructor.name => 批改后的constrctor名称')A.prototype.constructor = Aconsole.log(A.prototype.constructor, '批改prototype后,要从新指定A.prototype.constructor=A,避免援用出错')</script>

instanceof

  • 返回一个布尔值,示意对象是否为某个构造函数的实例
  • instanceof右边是实例对象,左边是构造函数
  • <font color=red> instanceof会查看左边构造函数的原型对象prototype,是否在右边对象的原型链上</font>
  • <font color=red> 因为instanceof查看整个原型链,因而同一个实例对象,可能对多个构造函数返回true</font>
  • 有一个非凡状况:如果右边对象的原型链上只有null(即右边对象的原型对象是null),这时instanceof判断就会失真
  • instanceof的一个用途就是判断值类型,(然而只能用于判断对象,不能用于判断原始类型的值)
  • 对于undefined和null,instanceOf运算符总是返回false
  • <font color=red>利用instanceof能够奇妙的解决,调用构造函数时遗记加new命令的问题</font>

    instanceoffunction A(){}const a = new A()console.log(a instanceof A, 'instanceof的原理是查看左边构造函数的原型对象是否在右边对象的原型链上')console.log(A.prototype.isPrototypeOf(a), 'instanceof等价于这样')var d = new Date();d instanceof Date// true// d既是Date的实例,也是Object的实例d instanceof Object // true// 因为instanceof查看的是左边构造函数的实例,是否在右边实例对象的原型链上,查看整个原型链// 所以同一个实例,可能对多个构造函数返回turevar obj = Object.create(null); // 以null为原型对象创立实例typeof obj // "object"Object.create(null) instanceof Object // false
    installof能够解决调用构造函数时,遗记加new命令的状况function A() {if(!(this instanceof A)) { // 如果this不是A的实例,阐明不是new命令调用的,那么执行new  return new A()}else {  this.name = 'woow_wu7'}}const a = new A()console.log(a)

    Object.getPrototypeOf

  • 返回参数对象的原型对象
  • Object.getPrototypeOf 是获取原型对象的规范办法
  • 留神:<font color=red>参数是对象,也能够是函数,因为函数也是对象,在es6中能够判断类的继承,Object.getPrototypeOf(ColorPoint) === Point
    // true,ColorPoint是一个类,即是一个函数</font>

  • 获取参数对象的原型对象,是获取原型对象的规范办法

    Object.getPrototypeOf(Object.prototype) === null // true
    Object.getPrototypeOf(Function.prototype) === Object.prototype // true
    Object.getPrototypeOf({}) === Object.prototype // true

  • 将第一个参数对象的原型设置为第二个参数对象 Object.setPrototypeOf(现有对象,原型对象)
  • 返回值:返回第一个参数对象
  • 参数:第一个参数是现有对象,第二个参数是原型对象

    const a = {}const b = {name: 'woow_wu7'}const res = Object.setPrototypeOf(a, b) // 将b设置成a的原型,留神返回值是aObject.getPrototypeOf(a) === b // trueconsole.log(a.name)console.log(res) // a, 返回值是a
  • new命令能够用Object.setPrototypeOf来模仿

    var F = function () {this.foo = 'bar';};var f = new F();// 等同于var f = Object.setPrototypeOf({}, F.prototype);// 返回值f是第一个参数 {}// Object.setPrototypeOf({}, F.prototype) => 相当于 {}.__proto__ = F.prototypeF.call(f);

    Object.create

  • 生成实例对象

    • 通过new命令执行构造函数的形式生成(构造函数其实就是一般的函数,只是用new命令调用时,this指向了实例,并且首字母大写来辨别,不大写也行,但约定俗成)
    • 通过一个对象生成,有时候只能拿到一个对象,要生成实例对象。Object.create,该实例齐全继承原型对象的属性和办法
  • <font color=red>Object.create() 以参数对象为原型返回实例对象,该实例齐全继承原型对象的属性和办法</font>

    手动实现一个 Object.createObject._create = function(obj) {function F(){}F.prototype = obj // 新建一个构造函数,将构造函数的prototype指向传入的对象,执行构造函数,即实例的原型指向了传入的对象return new F()}
  • 如果想要生成一个不继承任何属性和办法的对象,能够应用 Object.create(null)
  • <font color=red>如果Object.create()的参数为空,或者不是对象就会报错</font>

Object.prototype.isPrototypeOf

  • 实例对象的 isPrototypeOf 属性用于判断该对象是否是参数对象的原型

    Object.prototype.__proto__

  • 实例对象的原型对象
  • 依据语言规范,只有浏览器须要部署__proto__,其余环境中没有__proto__属性
  • 不倡议应用__proto__
  • 而是用规范的Object.getPrototypeOf读取原型Object.setPrototypeOf(现有对象,原型对象)来设置原型

获取原型对象的办法比拟

- `obj.__proto__` // 只有浏览器才有,不倡议应用- obj.constructor.prototype // 手动批改原型时,可能会失真- Object.getPrototypeOf() // 举荐的获取办法
间接批改原型对象时,须要同时批改constructor避免失真function A(){}const a = new A()function B() {}B.prototype = aconst b = new B()b.constructor.prototype === a // false// 因为:b.constructor === a.constructor === A.prototype.constructor === A// 所以:b.constructor.prototype === A.prototype// 论断:当间接批改prototype属性时,肯定要批改constructor属性 !!!!!!!!!!!!!!!!!!(重要)// 如果是上面这样则:function A(){}const a = new A()function B() {}B.prototype = aB.prototype.constructor = B // 批改了prototype,同时批改constructor则援用不会出错const b = new B()b.constructor.prototype === a // true

Object.prototype.hasOwnProperty

  • 返回一个布尔值,示意是否是对象本身的属性,不蕴含原型链上的属性

    Date.hasOwnProperty('length') // trueDate.hasOwnProperty('toString') // false

in运算符

  • in运算符返回一个布尔值,示意属性在对象中是否存在,不辨别本身属性还是继承的属性
  • 留神:<font color=red>in 运算符不辨别本身属性和继承属性</font>

    例子:function X(){}X.prototype.name = 'woow_wu7';let x = new X()'name' in X // true// 因为:in 运算符返回一个布尔值,示意属性是否在对象中存在,不辨别本身还是继承// 所以:'name' in X => 返回 true

    for in 和 for of

  • for in 能够遍历对象和数组
  • for of 只能遍历数组

  • 用于数组,i示意:key
  • 用于对象,i示意:key
  • 用于对象时,for...in会遍历本身属性和继承的属性,
    for of
  • 用于数组:i示意 value

    const objP = {sex: 'man'}
    const obj = {name: 'woow_wu7', age: 20, address: 'hangzhou'};
    Object.setPrototypeOf(obj, objP)
    for(let i in obj) {
    console.log(i, 'for in 循环 => 用于对象,会遍历本身和继承的属性') // name,age,address,sex
    if (obj.hasOwnProperty(i)) {
    console.log(i, '如果只心愿遍历本身属性,能够用Object.prototype.hanOwnProperty(属性名)来过滤')// name,age,address
    }
    }

  • 我的简书:https://www.jianshu.com/p/1a2...

  • constructor

    • constructor示意构造函数和原型对象之间的关联关系,如果批改了原型对象,须要一起批改构造函数,避免援用出错。
      -(每一个构造函数都有一个prototype属性,prototype的constructor指向prototype所在的构造函数)
  • instanceof

    • 原理:instanceof是查看(左边构造函数的prototype属性)是否在(右边对象)的原型链上
    • instanceof生效的状况:

      • 如果一个对象的__proto__属性指向null,则instanceof就会生效
      • 因为左边是构造函数的prototype => 起点是Object.prototype,是否在右边对象的原型链上
      • Object.prototype.__prototo__ === null
      • Object.prototype instanceof Ojbect // false
        // Object.create(null) instanceof Object // false,因为创立的实例没有任何属性和办法,也没有原型

2021/07/24更新

  • null没有任何属性和办法
  • 如何生成一个没有任何属性和办法的对象

    • Object.create(null)
  • 如何模仿一个Object.create
  • 批改prototype属性时,肯定要同时批改constructor属性,避免援用出错,不然会指向被赋值对象的构造函数的prototype上的constructor