JavaScript 进阶营让前端飞

【重学】原型链

2019-06-23  本文已影响0人  woow_wu7

大纲:
构造函数
手写new命令
原型链
Object对象的相关方法

(x)易错点

var P = function () {};
var p = new P();

var C = function () {};
C.prototype = p;  -------- C.prototype修改成了p,所以c.constructor === p.constructor === P.prototype.constructor,
var c = new C();

c.constructor.prototype === p // false --------------- 要想是p,就需要指定c.constructor = C
c.constructro.prototype === P.prototype // true 
(1) 实例只能访问构造函数prototype上的属性,不能直接修改构造函数的prototype属性
(2) 如果要修改,只能通过 x.constructor.prototype.color='yellow'方式修改

function A() {}
A.prototype.color = 'red'
const x = new A()
const y = new A()
x.color = 'yellow' ------------- 因为x.color是给x本身添加属性并赋值,而不是修改x的原型对象的属性
y.color?????  // 'red'
1. instanceof原理:检查 ( 右边构造函数的prototype属性 ) 是否在 ( 左边对象的原型链上 )

2. instanceof失效的情况:
  - 如果一个对象的__proto__是null,instanceof就会判断失效
  - Object.prototype.__prototo__ === null
  - Object.prototype instanceof Ojbect       // false  
  // Object.create(null) instanceof Object   // false,因为创建的实例没有任何属性和方法,也没有原型

(1)构造函数

前置知识:

1. new命令返回值
  - new命令总是返回一个对象,要么是( 实列对象 ),要么return后面所跟的 (对象)

2. 构造函数中的return语句,使用new命令时的返回情况
  - return 一个原始类型的值,使用new命令返回的是:-------------------------- this对象
  - return 一个对象,使用new命令返回的是:--------------------------------- return后面紧跟的那个对象,而不是this对象
  - 如果构造函数中没有return语句,则默认返回的是:-------------------------- this对象

3. 如何判断一个数据的数据类型?
  - typeof:返回 number,string,boolean,undefined,symbol,ojbect,function(七种)
  - instanceof:- 原理是检测 ( 右边构造函数的显示原型prototype )是否在左边 ( 实列对象的原型链上 )
                - instanceof只能用于对象,不能用于原始类型的值
  - Object.prototype.toString().call(参数) ----------- 返回"[object 类型]"
  - js中的数据类型 number, string, boolean, null, undefined, symbol, object (七种)

4. arguments对象
  - 返回实参组成的类似数组的对象,该对象具有length属性
 
5. 如何把arguments对象转换成真正的数组
  - Array.from(arguments)
  - Array.prototype.slice.call(arguments)

6. new命令的原理
  - 新建一个空对象,作为要返回的实列对象
  - 将空对象的隐式原型__proto__指向构造函数的显示原型prototype
  - 将构造函数中的this指向空对象
  - 执行构造函数

7. 如何新建一个对象
  - Object.create(b) : 以参数对象为原型,生成实列对象
  - new Object()
  - 对象字面量
  - 注意:const a = Object.create(b) 即可以实现 a.__proto__ === b == 构造函数.prototype

8. push unshift  和  pop shift
- push unsift 向数组添加数据,改变原数组,有参数,返回值是添加过后的数组长度 ( 不是返回添加的值,因为参数中已经知道 )
- pop shift 删除数据,改变原数组,没有参数,所以返回值是删除的数据值

9. new命令实行后的效果:
  - 生成的对象可以访问构造函数的属性
  - 生成的对象可以访问构造函数prototype上的属性

10. 手写new命令

function Constructor(name, age) {
  this.name = name
  this.age = age
  // 构造函数如果执行new命令,默认返回的是this对象
  // 这里模拟的是new命令,所以手动返回this对象

  // 如果返回其他对象,不是this对象,需要在构造函数返回值中做判断
  return this
}
Constructor.prototype.address = function() {
  console.log('shanghai')
}
function _new() {
  const obj = new Object()
  // 等于 const obj = {}
  // 等于 const obj = Object.create(null)       -------   以null为原型,生成实例对象

 const paramsConstructor =  Array.prototype.shift.call(arguments)
  // 等于 [].prototype.shift.call(arguments)
  // 等于 Array.prototype.shift.apply(arguments)
  // shift 删除数组的第一个参数,改变原数组,返回被删除的值 ---------- push, unshift 返回被添加删除的值
  // unshift 在数组的最前面添加数据,返回添加过后数组的长度 ---------- pop, shift 返回更新后的数组长度
  // 把arguments对象中的构造函数参数取出
  
  obj.__proto__ = paramsConstructor.prototype
  // 将空对象的隐式原型指向构造函数的显示原型

  const res = paramsConstructor.apply(obj, arguments)
  // 将构造函数中的this指向空对象
  // 空对象就能访问构造函数中的属性
  // apply第二个参数是数组,但是类似数组的对象也可以,会转化成数组

  return /Object/.test(Object.prototype.toString.call(res)) ? res : obj
  // 如果构造函数的返回的是一个和this无关对象则返回该对象,即res(this对象也返回)
  // 如果返回不是对象,就返回this对象,即空对象ojb
}
const b =  _new(Constructor, 'wu', 10)
console.log(b)

1.https://github.com/mqyqingfeng/Blog/issues/13

  1. https://segmentfault.com/a/1190000014452865

  2. https://segmentfault.com/a/1190000015276659

function A() {
  this.name = 'wang'
}
const a = new A()


----

const resa = Object.setPrototypeOf({}, A.prototype) --------------- 将A.prototype设置成空对象的原型对象
A.call(resa) ------------------------------------------------------ 将构造函数中的this指向空对象,并执行构造函数

(2) 原型链

  1. constructor属性的作用

特殊的原型链

特殊的原型链:

结论:
(1) 所有 ( 函数对象 ) 都是 ( Function构造函数 ) 的实例
  - 所以 Function.__proto__ === Function.prototype
  - 所以 fn.__protot__ === Function.prototype
  - 所以 Function instanceof Function  // true

(2) 所有函数的prototype对象都是Obect构造函数的实例(!但是Object除外)
  - Function.prototype instanceof Object // true
  - function.prototype.__proto__ === Object.prototype
  - Object.protype instanceof Object  // false

(3)
Function instanceof Function   ------------------- true
Function instanceof Object     ------------------- true
Object instanceof Object       ------------------- true
Object instanceof Function     ------------------- true
原型链 20170503152146141.png

(3)Object对象的相关方法

1. Object.getPrototypeOf

Object.getPrototypeOf()返回参数对象的原型对象,是获取原型对象的标准方法

Object.getPrototypeOf(params) 返回参数对象的原型对象,是获取原型对象的标准方法

    function A() {}
    const a = new A()
    const res = Object.getPrototypeOf(a)
    console.log(a.__proto__ === res) // true
    console.log(A.prototype === res) // true

2. Object.setPrototypeOf(origin, pro)

将第二个参数设置成第一个参数的原型,返回该参数对象即第一个对象

Object.setPrototype(a,b) 将b对象设置成a对象的原型对象,返回值是a对象

    const a = {}
    const b = {name: 'wang'}
    const res = Object.setPrototypeOf(a, b)
    console.log(res) // {}
    console.log(Object.getPrototypeOf(a)) // {name: 'wang'}

Object.setPrototypeOf(a, b)可以用来模拟new命令

function A() {
  this.name = 'wang'
}
const a = new A()


----


const resa = Object.setPrototypeOf({}, A.prototype) --------------- 将A.prototype设置成空对象的原型对象
A.call(resa) ------------------------------------------------------ 将构造函数中的this指向空对象,并执行构造函数

3. Object.create()

Object.create()以参数对象为原型,返回实例对象

以下生成对象的方式等价
Object.create({})
Object.create(Object.prototype)
new Object()

如果想要生成不继承任何属性的对象,可以用如下写法

var obj = Object.create(null)


obj.valueOf()
// TypeError: Object [object Object] has no method 'valueOf'

因为obj的原型是null,所以obj不具备 Object.prototype上挂在的属性和方法,比如 valueOf,toString

Object.create()参数必须是个对象,不能为空或者不是对象

4. Object.prototype.isPrototypeOf

实例对象的isPrototypeOf用来判断该对象是否为参数对象的原型

var o1 = {};
var o2 = Object.create(o1); // o1是o2的原型对象
var o3 = Object.create(o2); // o2是o3的原型对象

o2.isPrototypeOf(o3) // true ---------------------- 实例对象的isPrototypeOf用来判断该实例对象是否是参数对象的原型
o1.isPrototypeOf(o3) // true
上一篇 下一篇

猜你喜欢

热点阅读