共计 8707 个字符,预计需要花费 22 分钟才能阅读完成。
导航
- 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(){} //---------------------- 定义构造函数 A A.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) // true console.log(a.constructor === A.prototype.constructor) // true,constructor 属性在 prototype 对象上,所以能被实例继承并拜访 console.log(a.constructor === A) // true,constructor 的作用是能够确定实例由哪个构造函数产生 console.log(a.constructor === RegExp) // false console.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>
constructor constructor 示意原型对象和构造函数之间的关联关系,批改 prototype,须要同时批改 constructor,避免援用出错 <script> function A () {console.log('A 构造函数') } console.log(A.prototype, '批改之前的 A.prototype') console.log(A.prototype.constructor, '批改之前的 A.prototype.constructor') // A console.log(A.prototype.constructor.name, '批改之前的 A.prototype.constructor.name => 批改前的 constrctor 名称') A.prototype = {name: 'woow_wu7'} console.log(A.prototype.constructor, '批改之后的 A.prototype.constructor') // Object console.log(A.prototype.constructor.name, '批改之后的 A.prototype.constructor.name => 批改后的 constrctor 名称') A.prototype.constructor = A console.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>
instanceof function 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 查看的是左边构造函数的实例,是否在右边实例对象的原型链上,查看整个原型链 // 所以同一个实例,可能对多个构造函数返回 ture var 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 的原型,留神返回值是 a Object.getPrototypeOf(a) === b // true console.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.prototype F.call(f);
Object.create
-
生成实例对象
- 通过 new 命令执行构造函数的形式生成
(构造函数其实就是一般的函数,只是用 new 命令调用时,this 指向了实例,并且首字母大写来辨别,不大写也行,但约定俗成)
- 通过一个对象生成,
有时候只能拿到一个对象,要生成实例对象。Object.create,该实例齐全继承原型对象的属性和办法
- 通过 new 命令执行构造函数的形式生成
-
<font color=red>Object.create() 以参数对象为原型返回实例对象,该实例齐全继承原型对象的属性和办法 </font>
手动实现一个 Object.create Object._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 = a
const 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 = a
B.prototype.constructor = B // 批改了 prototype,同时批改 constructor 则援用不会出错
const b = new B()
b.constructor.prototype === a // true
Object.prototype.hasOwnProperty
-
返回一个布尔值,示意是否是对象本身的属性,不蕴含原型链上的属性
Date.hasOwnProperty('length') // true Date.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 所在的构造函数)
- constructor 示意构造函数和原型对象之间的关联关系,如果批改了原型对象,须要一起批改构造函数,避免援用出错。
-
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