Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【JavaScript】原型与原型链 #4

Open
Tracked by #6
swiftwind0405 opened this issue Jan 14, 2020 · 0 comments
Open
Tracked by #6

【JavaScript】原型与原型链 #4

swiftwind0405 opened this issue Jan 14, 2020 · 0 comments

Comments

@swiftwind0405
Copy link
Owner

swiftwind0405 commented Jan 14, 2020

原型

每一个构造函数都有一个 prototype 属性,它指向构造函数的原型对象。 原型对象中有一个 constrcutor 属性,指回构造函数。而每一个实例对象都有一个 __proto__ 属性,当我们用构造函数创建实例时,实例的__proto__属性就会指向该构造函数的原型对象。而构造函数也是一种对象,其__proto__属性指向 Function.prototype

所有 Function 的实例都是函数对象,其他的均为普通对象,其中包括 Function 实例的实例。

image

Function.prototype__proto__属性又指向 Object.prototype(鸡生蛋,蛋生鸡),而Object.prototype__proto__属性最终指向 null

JavaScript 中万物皆对象,而对象皆出自构造(构造函数)。

经典神图。必须理解到位:
image

原型链

当我们试图访问一个对象的属性或方法时,不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索:
image

  • 原型链查找会一直持续,直到找到同名的属性或方法,或者到达原型链的末尾 null
  • 原型链查找会遵循 属性遮蔽 原则,位于底层的属性或方法会被优先找到

每个对象拥有一个原型对象,通过 __proto__ 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层向上,最终指向 null,这就是原型链。

hasOwnProperty

hasOwnPropertyObject.prototype 的一个方法,他能判断一个对象是否包含自定义属性而不是原型链上的属性,因为 hasOwnProperty 是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

in

prop in object

如果指定的属性在指定的对象或其原型链中,则 in 运算符返回 true

对被删除或值为 undefined 的属性使用in:

  • 如果使用 delete 运算符删除了一个属性,则 in 运算符对所删除属性返回 false
  • 如果只是将一个属性的值赋值为 undefined,而没有删除它,则 in 运算仍然会返回 true

instanceof

object instanceof Constructor

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

即通过下面的操作来判断:

object.__proto__ === Constructor.prototype ?
object.__proto__.__proto__ === Constructor.prototype ?
object.__proto__.__proto__....__proto__ === Constructor.prototype

当左边的值是 null 时,会停止查找,返回 false。实际是检测 Constructor.prototype 是否存在于参数 object 的原型链上。

手写实现 instanceof

function _instanceOf(left, right) {
  if (right === null || right === undefined) {
    throw new TypeError(`Right-hand side of ' instanceof ' is not an object`)
  }
  const rightPrototype = right.prototype
  left = Object.getPrototypeOf(left)

  while (left !== null) {
    if (left === rightPrototype) return true
    left = Object.getPrototypeOf(left)
  }

  return false
}

Object.prototype.isPrototypeOf()

prototypeObj.isPrototypeOf(object)

isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上。

Object.getPrototypeOf

Object.getPrototypeOf(object)

Object.getPrototypeOf() 方法返回指定对象的原型(内部 [[Prototype]] 属性的值)。如果没有继承属性,则返回 null

手写实现 getPrototypeOf

Object.getPrototypeOf = function(obj) {
  if (obj === null || obj === undefined) {
    throw new Error('Cannot convert undefined or null to object')
  }
  if (typeof obj === 'boolean' || typeof obj === 'number' || typeof obj === 'string') return Object(obj).__proto__
  return obj.__proto__
}

Object.setPrototypeOf

Object.setPrototypeOf(obj, prototype)

Object.setPrototypeOf() 方法设置一个指定的对象的原型 ( 即内部 [[Prototype]] 属性)到另一个对象或 null

如果 prototype 参数不是一个对象或者 null (例如,数字,字符串,boolean,或者 undefined),则会报错。该方法将 obj 的 [[Prototype]] 修改为新的值。

如果不指定对应的属性描述符,则默认都是 false。描述符有以下几个:

  • enumerable 可枚举,默认 false
  • configurable 可删除,默认 false`
  • writable 可赋值,默认 false`
  • value 属性的值

手写实现 setPrototypeOf

Object.create = function(proto, propertiesObject) {
  const res = {}
  // proto 只能为 null 或者 type 为 object 的数据类型
  if (!(proto === null || typeof proto === 'object')) {
    throw new TypeError('Object prototype may only be an Object or null')
  }
  Object.setPrototypeOf(res, proto)

  if (propertiesObject === null) {
    throw new TypeError('Cannot convert undefined or null to object')
  }
  if (propertiesObject) {
    Object.defineProperties(res, propertiesObject)
  }

  return res
}

参考链接:

@swiftwind0405 swiftwind0405 changed the title 从原型到原型链 【Day01】prototype 原型与原型链 Feb 24, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day01】prototype 原型与原型链 【Day01】原型与原型链 Feb 24, 2020
@swiftwind0405 swiftwind0405 changed the title 【Day01】原型与原型链 【JavaScript】原型与原型链 Apr 29, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant