前言
大家好,我是林三心,置信大家都听过前端的三座大山:闭包,原型链,作用域,这三个其实都只是算根底。而我始终感觉根底是进阶的前提,所以不能因为是根底就漠视他们。明天我就以我的形式讲讲原型链吧,心愿大家能牢固地把握原型链常识
很多文章一上来就扔这个图,然而我不喜爱这样,我感觉这样对根底不好的同学很不好,我喜爱率领大家去从零实现这个图,在实现的过程中,一直地把握原型链的所有常识!!!来吧!!!跟着我从零实现吧!!!跟着我驯服原型链吧!!!
prototype和__proto__
是啥
这两个货色到底是啥呢?
- prototype: 显式原型
- __ proto__: 隐式原型
有什么关系
那么这两个都叫原型,那他们两到底啥关系呢?
个别,构造函数
的prototype和其实例
的__proto__是指向同一个中央的,这个中央就叫做原型对象
那什么是构造函数呢?俗话说就是,能够用来new
的函数就叫构造函数,箭头函数不能用来当做构造函数哦
function Person(name, age) { // 这个就是构造函数 this.name = name this.age = age}const person1 = new Person('小明', 20) // 这个是Person构造函数的实例const person2 = new Person('小红', 30) // 这个也是Person构造函数的实例
构造函数
的prototype和其实例
的__proto__是指向同一个中央的,咱们能够来验证一下
function Person(name, age) { this.name = name this.age = age}Person.prototype.sayName = function() { console.log(this.name)}console.log(Person.prototype) // { sayName: [Function] }const person1 = new Person('小明', 20)console.log(person1.__proto__) // { sayName: [Function] }const person2 = new Person('小红', 30)console.log(person2.__proto__) // { sayName: [Function] }console.log(Person.prototype === person1.__proto__) // trueconsole.log(Person.prototype === person2.__proto__) // true
函数
咱们下面提到了构造函数
,其实他说到底也是个函数,其实咱们平时定义函数,无非有以下几种
function fn1(name, age) { console.log(`我是${name}, 我往年${age}岁`)}fn1('林三心', 10) // 我是林三心, 我往年10岁const fn2 = function(name, age){ console.log(`我是${name}, 我往年${age}岁`)}fn2('林三心', 10) // 我是林三心, 我往年10岁const arrowFn = (name, age) => { console.log(`我是${name}, 我往年${age}岁`)}arrowFn('林三心', 10) // 我是林三心, 我往年10岁
其实这几种的实质都是一样的(只思考函数的申明),都能够应用new Function
来申明,是的没错Function
也是一个构造函数。下面的写法等同于上面的写法
const fn1 = new Function('name', 'age', 'console.log(`我是${name}, 我往年${age}岁`)')fn1('林三心', 10) // 我是林三心, 我往年10岁const fn2 = new Function('name', 'age', 'console.log(`我是${name}, 我往年${age}岁`)')fn2('林三心', 10) // 我是林三心, 我往年10岁const arrowFn = new Function('name', 'age', 'console.log(`我是${name}, 我往年${age}岁`)')arrowFn('林三心', 10) // 我是林三心, 我往年10岁
咱们之前说过,构造函数
的prototype
和其实例
的__proto__
是指向同一个中央的,这里的fn1,fn2,arrowFn
其实也都是Function构造函数
的实例,那咱们来验证一下吧
function fn1(name, age) { console.log(`我是${name}, 我往年${age}岁`)}const fn2 = function(name, age){ console.log(`我是${name}, 我往年${age}岁`)}const arrowFn = (name, age) => { console.log(`我是${name}, 我往年${age}岁`)}console.log(Function.prototype === fn1.__proto__) // trueconsole.log(Function.prototype === fn2.__proto__) // trueconsole.log(Function.prototype === arrowFn.__proto__) // true
对象
咱们平时开发中,创立一个对象,通常会用以下几种办法。
构造函数创建对象
,他创立进去的对象都是此Function构造函数
的实例,所以这里不探讨它字面量创建对象
new Object创建对象
Object.create创建对象
,创立进去的是一个空原型的对象,这里不探讨它// 第一种:构造函数创建对象function Person(name, age) {this.name = namethis.age = age}const person1 = new Person('林三心', 10)console.log(person1) // Person { name: '林三心', age: 10 }// 第二种:字面量创建对象const person2 = {name: '林三心', age: 10}console.log(person2) // { name: '林三心', age: 10 }// 第三种:new Object创建对象const person3 = new Object()person3.name = '林三心'person3.age = 10console.log(person3) // { name: '林三心', age: 10 }// 第四种:Object.create创建对象const person4 = Object.create({})person4.name = '林三心'person4.age = 10console.log(person4) // { name: '林三心', age: 10 }
咱们来看看
字面量创建对象
和new Object创建对象
两种形式,其实字面量创建对象
的实质就是new Object创建对象
// 字面量创建对象const person2 = {name: '林三心', age: 10}console.log(person2) // { name: '林三心', age: 10 }实质是// new Object创建对象const person2 = new Object()person2.name = '林三心'person2.age = 10console.log(person2) // { name: '林三心', age: 10 }
咱们之前说过,构造函数
的prototype
和其实例
的__proto__
是指向同一个中央的,这里的person2,person3
其实也都是Object构造函数
的实例,那咱们来验证一下吧
const person2 = {name: '林三心', age: 10}const person3 = new Object()person3.name = '林三心'person3.age = 10console.log(Object.prototype === person2.__proto__) // trueconsole.log(Object.prototype === person3.__proto__) // true
Function和Object
下面咱们常说
函数
是Function构造函数
的实例对象
是Object构造函数
的实例
那Function构造函数
和Object构造函数
他们两个又是谁的实例呢?
function Object()
其实也是个函数,所以他是Function构造函数
的实例function Function()
其实也是个函数,所以他也是Function构造函数
的实例,没错,他是他本人自身的实例
咱们能够试验一下就晓得了
console.log(Function.prototype === Object.__proto__) // trueconsole.log(Function.prototype === Function.__proto__) // true
constructor
constructor和prototype是成对的,你指向我,我指向你。举个例子,如果你是我老婆,那我必定是你的老公。
function fn() {}console.log(fn.prototype) // {constructor: fn}console.log(fn.prototype.constructor === fn) // true
原型链
Person.prototype 和 Function.prototype
探讨原型链之前,咱们先来聊聊这两个货色
- Person.prototype,它是
构造函数Person
的原型对象 - Function.prototype,他是
构造函数Function
的原型对象
都说了原型对象,原型对象,能够晓得其实这两个实质都是对象
那既然是对象
,实质必定都是通过new Object()
来创立的。既然是通过new Object()
创立的,那就阐明Person.prototype 和 Function.prototype
都是构造函数Object
的实例。也就阐明了Person.prototype 和 Function.prototype
他们两的__proto__
都指向Object.prototype
咱们能够验证一下
function Person(){}console.log(Person.prototype.__proto__ === Object.prototype) // trueconsole.log(Function.prototype.__proto__ === Object.prototype) // true
什么是原型链?
什么是原型链呢?其实俗话说就是:__proto__的门路
就叫原型链
原型链起点
下面咱们看到,三条原型链结尾都是Object.prototype
,那是不是阐明了Object.prototype
就是原型链的起点呢?其实不是的,Object.prototype
其实也有__proto__,指向null,那才是原型链的起点
至此,整个原型示意图就画完啦!!!
原型继承
说到原型,就不得不说补充一下原型继承
这个知识点了,原型继承
就是,实例
能够应用构造函数上的prototype
中的办法
function Person(name) { // 构造函数 this.name = name}Person.prototype.sayName = function() { // 往原型对象增加办法 console.log(this.name)}const person = new Person('林三心') // 实例// 应用构造函数的prototype中的办法person.sayName() // 林三心
instanceof
应用办法
A instanceof B
作用:判断B的prototype是否在A的原型链上
例子
function Person(name) { // 构造函数 this.name = name}const person = new Person('林三心') // 实例console.log(Person instanceof Function) // trueconsole.log(Person instanceof Object) // trueconsole.log(person instanceof Person) // trueconsole.log(person instanceof Object) // true
练习题
练习题只为了大家能坚固本文章的常识
第一题
var F = function() {};Object.prototype.a = function() { console.log('a');};Function.prototype.b = function() { console.log('b');}var f = new F();f.a();f.b();F.a();F.b();
答案
f.a(); // af.b(); // f.b is not a functionF.a(); // aF.b(); // b
第二题
var A = function() {};A.prototype.n = 1;var b = new A();A.prototype = { n: 2, m: 3}var c = new A();console.log(b.n);console.log(b.m);console.log(c.n);console.log(c.m);
答案
console.log(b.n); // 1console.log(b.m); // undefinedconsole.log(c.n); // 2console.log(c.m); // 3
第三题
var foo = {}, F = function(){};Object.prototype.a = 'value a';Function.prototype.b = 'value b';console.log(foo.a);console.log(foo.b);console.log(F.a);console.log(F.b);
答案
console.log(foo.a); // value aconsole.log(foo.b); // undefinedconsole.log(F.a); // value aconsole.log(F.b); // value b
第四题
function A() {}function B(a) { this.a = a;}function C(a) { if (a) { this.a = a; }}A.prototype.a = 1;B.prototype.a = 1;C.prototype.a = 1;console.log(new A().a); console.log(new B().a);console.log(new C(2).a);
答案
console.log(new A().a); // 1console.log(new B().a); // undefinedconsole.log(new C(2).a); // 2
第五题
console.log(123['toString'].length + 123)
答案:123是数字,数字实质是new Number()
,数字自身没有toString
办法,则沿着__proto__
去function Number()
的prototype
上找,找到toString办法,toString办法的length是1,1 + 123 = 124
,至于为什么length是1,能够看95%的人都答复不上来的问题:函数的length是多少?
console.log(123['toString'].length + 123) // 124
结语
如果你感觉此文对你有一丁点帮忙,点个赞,激励一下林三心哈哈。或者退出我的群哈哈,咱们一起摸鱼一起学习