Skip to content

1.每一个函数(箭头函数除外), 都有一个自带的属性: prototype, 这个属性指向一个对象, 这个对象存储着给实例提供的公有的属性和方法,它有一个自带的属性: constructor, 这个属性指向当前函数, Function.prototype 除外, 它指向一个匿名函数,这个匿名函数没有 prototype 属性, 另外这个匿名函数有个 constructor 属性,自然是指向 Function,

2.每一个引用数据类型的值,有一个天生自带的属性: proto,这个属性指向父类的原型

js
{}.__proto__ === Object.prototype
[].__proto__ === Array.prototype
Array.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null // 原型链尽头
// ...

3.函数是引用数据类型的值, 所有每个函数(包括箭头函数)也都有一个天生自带的属性: proto, 这个属性指向父类的原型 -> Function.prototype

js
fn.__proto__ === Funtion.prototype
Array.__proto__ === Function.prototype
Object.__proto__ === Function.prototype
Function.__proto__ === Funtion.prototype
// ...
Function.prototype.__proto__ === Object.prototype

4.函数的prototype是一个对象, 是引用数据类型值, 有一个天生自带的属性: proto, 这个属性指向父类的原型

js
fn.prototype.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype

5.Object()构造函数的prototype指向一个对象,这个对象的__proto__指向null,这就是原型链的尽头

js
Object.prototype.__proto__ === null

原型链

访问一个对象的属性时 先在自身属性中查找,找到返回 如果没有,再沿着__proto__这条隐式原型链上查找,找到返回 如果最终没找到,返回undefined

设置对象属性时,不会查找原型链,如果当前对象没有该属性,会直接添加该属性

为什么getElementById的上下文只能是document?

document的父类是Document,而只有Document.prototype中的getElementById这个方法

js
// example1
function Fn () {
  this.x = 100
  this.y = 200
  this.getX = function () {
    console.log(this.x)
  }
}
Fn.prototype.getX = function () {
  console.log(this.x)
}
Fn.prototype.getY = function () {
  console.log(this.y)
}
let f1 = new Fn
let f2 = new Fn
console.log(f1.getX === f2.getX) 
console.log(f1.getY === f2.getY) 
console.log(f1.__proto__.getX === f2.__proto__.getX) 
console.log(f1.__proto__.getX === f2.getX) 
console.log(f1.getX === Fn.prototype.getX) 
console.log(f1.constructor) 
console.log(Fn.constructor.__proto__.constructor) 
f1.getX() 
f1.__proto__.getX() 
f2.getY() // 函数前有 .,this 就是 . 之前的对象
Fn.prototype.getY() 

// example2
function fun () {
  this.a = 0
  this.b = function () {
    console.log(this.a)
  }
}
fun.prototype = {
  b: function () {
    this.a = 20
    console.log(this.a)
  },
  c: function () {
    this.a = 30
    console.log(this.a)
  }
}
var f1 = new fun()
f1.b()
f1.c()

// example3
function C1 (name) {
  if (name) {
    this.name = name
  }
}
function C2 (name) {
  this.name = name
}
function C3 (name) {
  this.name = name || 'Jack'
}
C1.prototype.name = 'Tom'
C2.prototype.name = 'Tom'
C3.prototype.name = 'Tom'
console.log((new C1().name) + (new C2().name) + (new C3().name)) 

// example3
function Fn (num) {
  this.x = this.y = num
}
Fn.prototype = {
  x: 20,
  sum: function () {
    console.log(this.x + this.y)
  }
}
let f = new Fn(10)
console.log(f.sum === Fn.prototype.sum) 
f.sum() 
Fn.prototype.sum() 
console.log(f.constructor)

// example4
function Fn () {
  let a = 1
  this.a = a
}
Fn.prototype.say = function () {
  this.a = 2
}
Fn.prototype = new Fn
let f1 = new Fn
Fn.prototype.b = function () {
  this.a = 3
}
console.log(f1.a) 
console.log(f1.prototype) 
console.log(f1.b) 
console.log(f1.hasOwnProperty('b')) 

// example3
// 编写两个方法plus/minus,实现如下功能
let n = 10
let m = n.plus(10).minus(5)
console.log(m)

~(function (proto) {
  function check (x) {
    return isNaN(x) ? 0 : Number(x)
  }

  function plus (x) {
    x = check(x)
    return this + x 
  }
  function minus (x) {
    x = check(x)
    return this - x 
  }
  proto.plus = plus
  proto.minus = minus
})(Number.prototype)