根据视频进行整理
【https://www.bilibili.com/video/BV14s411E7qf?p=15】
视频对应资源(百度网盘):
链接:【https://pan.baidu.com/s/1q9LnJcRt5alTV67gUDqpnw】
提取码:1234
1 原型与原型链
1.1 原型 prototype
1、每个函数都有一个prototype属性
// 每个函数都有一个prototype属性 function myfunc() { } console.log(myfunc.prototype) console.log(Date.prototype)
2、函数的prototype属性,其类型为object
// 每个函数都有一个prototype属性 function myfunc() { } console.log( typeof myfunc.prototype) console.log( typeof Date.prototype)
3、函数的prototype属性默认指向一个Object空对象(即称为: 原型对象)
Object空对象:
是指该对象上没有我们自定义的属性
console.dir( myfunc.prototype) console.log(new Object())
4、函数的prototype属性指向的对象为原型对象
5、原型对象中有一个属性constructor, 它指向函数对象
console.log(myfunc.prototype.constructor === myfunc) console.log(Date.prototype.constructor === Date)
6、可以通过prototype给原型对象添加属性(一般是方法)
作用:
可以使函数的所有实例对象都自动拥有原型中的属性(方法)
通过prototype给原型对象添加属性,添加的属性供实例对象使用
// 构造函数 function Fun() {} // 向函数的原型对象上添加属性 Fun.prototype.test = function() { console.log('Fun.prototype.test') } // 实例化对象 const fun1 = new Fun() console.log(fun1) fun1.test()
1.2 显示原型与隐式原型
1、每个函数function都有一个prototype,即显式原型(属性)
2、每个实例对象都有一个__proto__,可称为隐式原型(属性)
// 每个函数function都有一个prototype,即显式原型(属性) function Fun() {} console.log(Fun.prototype) // 每个实例对象都有一个__proto__,可称为隐式原型(属性) var fun = new Fun() console.log(fun.__proto__)
3、实例化出来的对象的隐式原型的值为其对应构造函数的显式原型的值
显示原型属性指向一个没有我们自定义属性的对象,隐式原型属性指向显示原型属性指向的对象。
// 实例化出来的对象的隐式原型的值为其对应构造函数的显式原型的值 console.log(fun.__proto__ === Fun.prototype)
// 通过函数的prototype给原型添加属性 Fun.prototype.test = function() { console.log('test') } // 实例对象调用添加的属性 fun.test()
函数向原型中添加属性通过显示原型属性
实例对象使用新添加的属性通过隐式原型属性进行查找
输出结果:
小结
- 函数的prototype属性: 在定义函数时自动添加的, 默认值是一个没有自定义属性的Object对象
- 对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
- 程序员能直接操作显式原型, 但不要直接操作隐式原型(ES6之前)
1.3 原型链
function Fn() { this.test1 = function () { console.log('test1()') } } Fn.prototype.test2 = function () { console.log('test2()') } var fn = new Fn() fn.test1() fn.test2() console.log(fn.toString()) fn.test3()
访问一个对象的属性时:
- 先在自身属性中查找,找到返回
- 如果没有, 再沿着__proto__这条链向上查找, 找到返回
- 如果最终没找到, 返回undefined
原型链的尽头为Object的原型对象。
原型链:
- 本质上是隐式原型链
- 作用: 查找对象的属性(方法)
fn.test3() 会在对象的属性和其原型链中查找
test3() 函数变量,会在作用域链中进行查找
所有函数的隐式原型都相等,因为所有函数都是函数构造器函数Function()的实例对象,所以所有函数对象的隐式原型属性都相等,都等于函数构造器函数Function()的显示原型属性
补充:
1、函数的显示原型指向的对象默认是空Object实例对象(但Object函数的原型对象不满足)
空:对于程序员来说,没有放任何的属性方法到对象中
Object的显示原型对象为null
Object函数:对象的构造函数 Object()
console.log(Fn.prototype instanceof Object) // true // Object的显示原型对象再向上就没了 console.log(Object.prototype instanceof Object) // false console.log(Function.prototype instanceof Object) // true
2.、所有函数都是Function的实例(包含Function)
// 自身的实例,隐式原型的指向和现实原型的指向相等 console.log(Function.__proto__ === Function.prototype)
3、Object的原型对象是原型链尽头
console.log(Object.prototype.__proto__) // null
1.4 原型链_属性问题
1、读取对象的属性值时: 会自动到原型链中查找
2、设置对象的属性值时: 不会查找原型链, 如果当前对象中没有此属性, 直接添加此属性并设置其值
function Fn() {} // 在原型上设置一个属性 a 值为 xxx Fn.prototype.a = 'xxx' // Fn实例化对象 fn1 var fn1 = new Fn() console.log(fn1.a, fn1) // Fn实例化对象 fn2 var fn2 = new Fn() // 给 fn2 对象设置属性 a 值为 yyy // fn2 中没有 a 属性,会给 fn2 添加一个 a 属性 fn2.a = 'yyy' console.log(fn1.a, fn2.a, fn2)
3、方法一般定义在原型中, 属性一般通过构造函数定义在对象本身上
对象的属性一般在构造函数中进行设置
function Person(name, age) { this.name = name this.age = age } Person.prototype.setName = function (name) { this.name = name }
属性在自身身上(每个对象的属性值会有所不同),方法在原型上
var p1 = new Person('Tom', 12) p1.setName('Bob') console.log(p1) var p2 = new Person('Jack', 12) p2.setName('Cat') console.log(p2)
1.5 instanceof
instanceof是如何判断的?
表达式: A instanceof B
如果B函数的显式原型对象在A对象的原型链上, 返回true, 否则返回false
// Object这里为构造器函数,是Function的一个实例对象 // Object => Object.__proto__ === Function.prototype console.log(Object instanceof Function) // true // Object作为对象的显示原型属性为Object.prototype // Object作为构造函数是Function的实例对象,Function是Object的实例(函数是特殊的对象) // Object => Object.__proto__ === Function.prototype => Object console.log(Object instanceof Object) // true console.log(Function instanceof Function) // true // 函数是特殊的对象 console.log(Function instanceof Object) // true function Foo() {} // 函数类型的数据对象 // Foo.prototype // Object.__proto__ => Function.prototype => Object.prototype console.log(Object instanceof Foo) // false
1.6 面试题
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)
function F (){} Object.prototype.a = function(){ console.log('a()') } Function.prototype.b = function(){ console.log('b()') } var f = new F() // f是一个对象 // f => Object => Object.prototype // F是一个函数,Function的实例 // F => Function => Object => Object.prototype f.a() // f.b() // 不存在,会报错 F.a() F.b() // console.log(f) // console.log(Object.prototype) // console.log(Function.prototype)