JS高级:原型与原型链

原型 1~3

  1. 任何函数都有prototype属性,默认指向一个空的Object对象(即原型对象)(只是没有我们要的属性和方法,会有默认的属性方法)
    原型对象都有constructor属性,它指向函数对象本身
    (构造函数和它的原型对象有相互引用的关系,构造函数的prototype指向原型对象,原型对象的constructor又返回指向构造函数,你中有我我中有你)
 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.给原型添加属性和方法(一般是方法),供实例使用

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

3.原型分类:显式原型(prototype)和隐式原型(proto)–prototype、__proto__保存的都是地址
(1)每个函数都有一个prototype属性,默认指向一个空的对象(并不是真的空值,有默认的属性和方法)——显示原型
(2)每个实例对象都有一个__proto__属性——隐式原型
(3)实例对象的隐式原型(proto)的值对应构造函数的显示原型(prototype)
(__proto__在创建实例的时候产生,如this.proto = Fn.prototype)
图解见图1:
在这里插入图片描述

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

// 给原型添加方法:

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
在这里插入图片描述
栗子:分析见图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() // 报错

在这里插入图片描述
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值