JavaScript ES5 原型链(一、原型)
JavaScript 认识普通对象原型
JavaScript中每个对象都是含有一个内置属性的[[prototype]],我们是可以通过这个内置的对象实现指向另外一个对象这个对象就是我们的对象具有的原型对象
实现获取对象的原型对象的方法有:
Object.getProrotypeof(obj)标准的用法obj.__proto__不标准的用法
var obj = { name: "76433", age: 18, school: "university of post in chongqing", } console.log(obj)
- 首先通过上面的打印输出,我们的调试者工具的话,是会出现原型的,就是我们的 prototype
- 我们实现获取对象中的原型的方法有:
obj.__proto__或者Object.getPrototypeOf(obj)就可以实现获取对象原型// 实现获取原型的方法 console.log(Object.getPrototypeOf(obj)) // 或者说通过 __proto__ 来实现获取对象原型 console.log(obj.__proto__) console.log(Object.getPrototypeOf(obj) === obj.__proto__) // true
- 我们需要注意的是,我们的每一个对象都是含有原型的
原型具有的作用又是什么呐???
当我们通过一个
[[get]]方法来实现获取我们的一个对象中的属性的value时(obj.name)
- 它实现的的查找规则是现在自己的对象中进行查找我们的值,如果找到了,那就直接返回
- 否则就是进入原型对象,在原型对象中进行查找
- 如果在原型对象中还是没有查找得到,那么最后就是查找到的是
undefinedvar obj = { name: "76433", age: 18, school: "university of post in chongqing", } Object.getPrototypeOf(obj).message = "my github is juwenzhang" // 这个是标准的写法 // obj.__proto__.message = "my github is juwenzhang" // 非标准的写法 console.log(obj) console.log(obj.message)
- 通过运行结果我们就可以知道一点的是,我们的
obj对象本身是不具备message属性的- 但是最终还是可以出来值,这个就是因为我们在原型对象上面添加了这个属性,所以说就可以查找到
JavaScript 函数的原型
JavaScript 中的函数是十分特殊的
不亏是以函数作为头等公民的一门编程语言
函数的原型对象和纯对象的话是有所不同的,是因为,我们的函数既可以看作是一个对象,又可以是一个函数
当看作是一个对象的时候,我们的函数是具有和上面的纯对象一样的获取原型的方法的
- 这个原型是我们的
[[prototype]]- 获取的方法
Object.getPrototypeof(func_name)|func_name.__proto__当看作的是一个函数的时候(除了箭头函数)
- 每个函数都是具有:
prototype属性- 获取方式为:
func_name.prototypevar func = function () {} console.dir(func) console.dir(Object.getPrototypeOf(func)) console.log(func.prototype)
JavaScript 函数的new操作符
new操作符进行操作含有:
- 创建一个空对象,这个空对象就是我们的
[[prototype]]的隐式原型- 将空对象赋值给 this
- 将函数的显式原型**
prototype**赋值给对象作为他的隐式原型__proto__- 执行函数中的代码体
- 将这个对象默认返回
var Func = function () { return this } var func = new Func(); // 常说的就是我们编程人员最不缺的就是对象,缺的话直接 new 一个出来,func 就是对象 console.log(Func.prototype === func.__proto__); // true console.log(Func.prototype === Object.getPrototypeOf(func)); // true
- 在来一个例子吧,来讨论我们的这种操作的具体作用
var Func = function () {} var func = new Func() var func1 = new Func() var func2 = new Func() var func3 = new Func() console.log(Object.getPrototypeOf(func) === Func.prototype) // true console.log(Object.getPrototypeOf(func1) === Func.prototype) // true console.log(Object.getPrototypeOf(func2) === Func.prototype) // true console.log(Object.getPrototypeOf(func3) === Func.prototype) // true // 通过上面的操作的话,类推就出现了、 console.log(Object.getPrototypeOf(func1) === Object.getPrototypeOf(func3)) // true
JavaScript 将方法添加到原型上
以前实现我们的一次性创建多个对象的方法是:
function Stu(name, age) { this.name = name; this.age = age; this.running = function () { console.log("running") } this.studying = function () { console.log("studying") } } var stu1 = new Stu("juwenzhang", 18); var stu2 = new Stu("76433", 18); var stu3 = new Stu("水逆信封", 18);
我们使用这种方法的弊端:
- 通过我们的上章节的描述,函数在执行的时候,都是会开辟一个内存空间的
- 如果通过上面的方法来进行创建我们的三个实例对象,那么最后导致的就是同样的功能代码,连续被开辟
- 了多个内存空间,导致内存的浪费,这个时候,我们的解决方案,就是在原型上面添加一个方法
- 因为在原型上添加的方法,最终还是实现的只是指向的是一块内存区域,这样大大的减少以及优化了我们的代码
现在的操作就是在原型上实现添加方法,减少不必要的内存浪费
function Stu(name, age) { this.name = name; this.age = age; Stu.prototype.running = function () { console.log("running") } Stu.prototype.studying = function () { console.log("studying") } } // new 操作符实际上的话,底层实现的最终的一步源码就是: Object.getPrototypeOf(stu1) = Stu.prototype var stu1 = new Stu("juwenzhang", 18); var stu2 = new Stu("76433", 18); var stu3 = new Stu("水逆信封", 18); // 这个时候的调用方法就有: Object.getPrototypeOf(stu1).running() Stu.prototype.running() stu1.running() console.log(Object.getPrototypeOf(stu1))那么上面的实现的原理是什么呐???
首先的是我们的通过使用了 new 操作符后,下一步进行的操作就是: 实例对象的原型__proto__ 指向 函数的 prototype
又通过上面的第一点的讲解,对于普通对象而言查找属性和方法的机制,本级没有,那就往原型中进行寻找,有的话就返回,没有就是undefined
同时又因为__proto__ 指向的是 prototype ,所以说,最终的前者可以访问得到其内部的方法或者属性
基本的流程就是这样的
我们还需要主要的一点就是:两个对象之间的进行相互赋值的原理
var obj01 = { name: "juwenzhang" } var obj02 = { age: 19, height: 165 } obj01 = obj02 console.log(obj01.name, obj01.age, obj02.height) // undefined 19 165为什么会出现这种情况耶??
obj01 = obj02
首先第一步做的是令我们的 obj01 = null
然后实现的才是将我们的 obj02 的内存地址赋值给 obj01
我们需要注意的一点就是,原型对象和实例对象之间之间的赋值操作是全局堆区中进行的
但是实际上的话,两者的赋值本质和上面的思想原理是一样的呐!!!
JavaScript 函数显式原型(prototype)中的 constructor 属性
在函数的显式原型
prototype指向的 显式原型对象中,是具有一个属性的,就是constrcutor这个属性最终实现的是指向我们函数本身,实现的循环套用,但是循环套用的话,我们的 V8 引擎是具有解决方案的
function Foo() {} var Foo_prototype = Foo.prototype console.log(Foo_prototype.constructor === Foo) // true var foo = new Foo() console.log(Object.getPrototypeOf(foo) === Foo.prototype) // true console.log(Object.getPrototypeOf(foo).constructor === Foo.prototype.constructor) // true console.log(Object.getPrototypeOf(foo).constructor === Foo) // true
补充原型对象和实例对象之间的详细图解
/**
* 创建的是 Foo 构造函数
* @param {string} name
* @param {number} age
* @returns undefined
*/
function Foo(name, age) {
this.name = name
this.age = age
Foo.prototype.running = function() {
console.log(`${this.name} is running`)
}
Foo.prototype.studying = function() {
console.log(`${this.name} is studying`) }
}
/**
* 开始创建实例对象
*/
var foo01 = new Foo("76433", 18)
var foo02 = new Foo("水逆信封", 18)
支持私聊,有错误的话,积极指出,因为光是图形解的,不容易看的清除
练习方式: 3137536916@qq.com