JS Advanced: Prototype and Prototype chain

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: https://blog.csdn.net/weixin_44627407/article/details/102684730

Prototype 1-3

  1. Any function has prototype property, the default pointing to an empty Object object (ie, the prototype object) (not just the properties and methods we want, there will be the default property method)
    prototype object has a constructor property that refers to the function object itself
    (structure function and its prototype object references are related to each other, prototype constructor points to the prototype object, constructor prototype object and returns a pointer to the constructor, you have me I have you)
 function fn() {
    console.log('sss')
   }
  console.log(fn.prototype, typeof fn.prototype) // 'object
  console.log(typeof fn.prototype) // 'object'
  console.log(fn.prototype.constructor)
  //function fn() {xian'shi
   console.log('sss')
   }

2. add properties and methods (General method) to a prototype, for instance

function Fn() {
   }
   Fn.prototype.test1= function () {
     console.log('I am test1')
   }
   var fn1 =new Fn()
   fn1.test1() //I am test1

3. Classification Prototype: Explicit prototype (prototype) and implicit prototype ( proto ) -prototype, __ proto__ address are saved
(1) Each function has a prototype property, the default object points to a null (not really null with default attributes and methods) - prototype displays
(2) each instance of an object has a property __proto__ - implicit prototype
(3) examples of implicit object prototype ( proto ) configuration corresponding to the value display function prototype (the prototype)
(created when the __proto__ instance generation, such as the this. proto = Fn.prototype)
illustrated in Figure 1:
Here Insert Picture Description

function Fn() {  // 内部:this.prototype = { }
   }
   // (1)
  console.log(Fn.prototype) // {constructor: ...}
  var fn = new Fn() // 内部:this.__proto__ = Fn.prototype
  // (2)
  console.log(fn.__proto__) // {constructor: ...}
  // (3)
  console.log(Fn.prototype === fn.__proto__) // true

// add to the prototype method:

Fn.prototype.test1 = function () {
    console.log('hello world')
  }
 fn.test1() // hello world,通过实例对象的隐式原型找到test
// fn.test1()过程:先在fn的内部去找test1,找到救执行,没有找到-->沿着fn的__proto__(值等于构造函数的prototype)找,一直找到Object

总结:
函数的prototyp属性:在定义函数时自动添加,默认值是空Object对象
实例的__proto__属性:创建实例对象时自动添加,默认值是构造函数的prototype属性值
程序员只能操作显式原型prototype,但不能操作隐式原型__proto__(ES6之前)

原型面试题
function A (){

}
A.prototype.n=1
var b = new A()
A.prototype = {
n:2,
m:3
}
var c = new A()
console.log(b.n,b.m,c.n,c.m) // 1 undefined 2 3
// A.prototype = {…}时,A的prototype重新指向另一块内存,此时已经与前一块内存脱离指向关系,但是前一块内存仍然存在,并且b仍然指向它

原型链 4~5

4.原型链——别名:隐式原型链
访问一个对象的属性(一般是方法)时,先在自身找,找到就返回;
如果没有找到,再沿着__proto__这条链往上找,找到就返回;
如果找到Object的__proto__都没有找到,就返回undefined
这样的一个过程就形成一条原型链。
原型链的作用:查找对象的属性(一般是方法方法)(注意/区别:查找对象的变量是通过作用域和作用于链)

4.1 实例、构造函数、原型三者的关系
实例:proto --> 构造函数:prototype、proto(它是Object的实例所以有__proto__属性) --> 空Object:proto(值为null)、prototype(作为构造函数有这个属性)-constructor–>构造函数
(实例通过__proto__与构造函数、原型联系在一起)
见图3
Here Insert Picture Description
栗子:分析见图2

function Fn() {
       this.test1 = function () {
         console.log('I am test1')
       }
   }
   Fn.prototype.test2 = function () {
     console.log('U are test2')
   }
   var fn =new Fn()
  fn.test1() // I am test1
  fn.test2() // U are test2
  fn.test3() // 报错

Here Insert Picture Description
4.2 特殊情况
(1)函数的显式原型指向的对象:默认的空Object对象(不是真的为空,会有自带一些属性)
特殊情况:Object
function Fn() {
}
console.log(Fn.prototype instanceof Object) // true
console.log(Object.prototype instanceof Object) // false–特殊
console.log(Function.prototype instanceof Object) // true

console.log(Object.prototype) // 不包含方法的空对象
console.log(Fn.prototype) // 包含多个方法的对象

(2)所有函数都是Function的实例(包括Function本身)
console.log(Function.prototype === Function.proto) // true

(3)Object的原型对象是原型链的尽头
console.log(Object.prototype.proto) // null

4.3 原型链的属性问题
读取实例对象的属性时,先在自身对象中查找,找到就返回,不会再继续往原型链上找——看到的效果就是实例对象的属性值覆盖了原型链上的属性值,其实不然!原型链上的属性相当于“备胎”
,当实例对象有该属性时并不会用到原型链上的对应的属性,实例对象的属性值也不会改变(覆盖、重写)原型链上的属性值;
如果没有找到就沿着原型链往上找,如果原型链上有该属性,就返回;
当给实例对象设置属性时,如果该属性与原型链中的属性冲突(重名)时,只会讲该属性名写入自己的属性不会改变原型链上的属性的值。
function Fn() {
}
Fn.prototype.name = ‘pipixi’
var fn1 = new Fn()
console.log(fn1.name) // pipixi
var fn2 = new Fn()
fn2.name = ‘pipijie’
console.log(fn2.name) // pipijie
console.log(fn1.name) // pipixi

注意:一般不会把属性写到原型中,写到原型中的是方法,而属性更多的通过参数传进来。栗子:
function Person(name,age) {
this.name = name
this.age = age
}
Person.prototype.SayHello = function () {
console.log(‘Hello’ + " " + this.name + “!” + "Are you " + this.age + “years old?”)
}
var p1 = new Person(‘lily’, 18)
var p2 = new Person(‘kally’, 39)

p1.SayHello() //Hello lily!Are you 18years old?
p2.SayHello() //Hello kally!Are you 18years old?

建议:属性一般通过构造函数定义在实例对象本身(自用)、而通用的方法写在原型(prototype)上(公用) ——好处:既有可以定义各自的属性、又可以共享通用的方法

原型链面试题
function F() {
}
Object.prototype.a = function () {
console.log(‘I am a’)
}
Function.prototype.b = function () {
console.log(‘I am b’)
}
var f = new F()
f.a() // I am a
f.b() // 报错
F.a() // I am a
F.b() // I am b

5. instanceof探索
A instanceof B ——A是实例对象(有隐式原型属性-proto),B是构造函数(有显式原型属性-prototype)
如果B 的显式原型指向A 的隐式原型链上的某个值时,返回true,否则返回false
栗子1:
function Foo() {
}
var f1 = new Foo()
console.log(f1 instanceof Foo) // true – f1由Foo new出来的,f1肯定是Foo的实例对象呀
console.log(f1 instanceof Object) // true --f1不是Object直接new出来的,但是f1可以通过__proto__原型链找到Object,所以f1也是Object的实例对象
console.log(Object.prototype) // 打印的是new出Objectd的构造函数 function Object
console.log(Object.prototype.proto) // null – 原型链的终点

栗子2:
console.log(Object instanceof Function) // true
console.log(Function instanceof Object) // true
console.log(Object instanceof Object) // true
console.log(Function instanceof Function) //true
function Foo() {
}
console.log(Object instanceof Foo) // false

Guess you like

Origin blog.csdn.net/weixin_44627407/article/details/102684730