写在最前:构造函数和原型模式的使用场景很普遍,但由于对概念的混淆不清致使没法熟练掌握。切图带你从代码和流程图一步步攻克,纯干货,建议收藏详看,原型模式理解图很是重要,务必多看几遍!
// 构造函数 function Person(name, age) { this.name = name this.age = age this.introduction = function() { console.log(`my name is ${this.name}, I'm ${this.age} years old`) } //return this //构造函数默认有这句 } var p = new Person('qietuniu', 18) // this=Person p.introduction() // 普通函数 function person(name, age) { this.name = name this.age = age this.introduction = function() { console.log(`my name is ${this.name}, I'm ${this.age} years old`) } return `直接返回:个人名字 ${this.name}, 我 ${this.age} 岁` } console.log(person('qietuniu', 18)) //this=window window.introduction()
构造函数内的上下文this指向即将要生成的实例对象Person,普通函数内使用this,指向window时容易形成全局污染
。该构造函数将陪着咱们读完这篇文章,以后的示例将在这基础上演示!vue
语法糖:更简单表达一个操做的语法,可以增长程序的可读性,在性能上不会带来损失的同时提升开发编码的效率,从而减小程序代码出错的机会!
可以使用instanceof判断一个函数是不是一个变量的构造函数.jquery
解析:instanceof的判断逻辑是实例p的__proto__一层一层往上,可否对应到Person.prototype,一样也能到Object.prototype.
解析(以Person函数为例):
1.建立一个新对象p
2.将构造函数Person()中的this指向新建立的对象p
3.p的_proto_(隐式原型)属性指向Person函数的prototype(显示原型),建立构造函数与原型以及对象的关系
4.调用对象,执行Person内属性或方法
原型对象的constructor是构造函数Fngithub
Person.prototype.constructor = Person
实例的构造函数属性(constructor)指向构造函数segmentfault
p的__proto__.constructor = Person
实例的__proto__(隐式原型)是原型对象数组
p的__proto__ =Person.prototype
Fn.prototype是对象,它的__proto__是object的prototype浏览器
Person.prototype的__proto__ = Object.prototype
Object的prototype的__proto__为nullecharts
Object.prototype的__proto__ = null
Person.prototype的__proto__的__proto__ = null
熟记该图,万变不离其宗
1. 全部的引用类型(数组、对象、函数),都具备对象特性,便可自由扩展属性(null除外)函数
var obj = {} obj.a = 100 //自由扩展属性 var arr = [] arr.a = 100 function fn() {} fn.a = 100
建立对象的三种方法
// 字面量 var o1 = { name: 'o1' } var o2 = new Object({ name: 'o2' }) // 构造函数 var M = function() { this.name = 'o3' } var o3 = new M() // Object.create var O = { name: 'o4' } var o4 = Object.create(O) console.log(o1) console.log(o2) console.log(o3) console.log(o4)
2. 全部的引用类型(数组、对象、函数),都有一个__proto__属性(隐式原型),属性是一个普通的对象
//隐式原型 console.log(obj.__proto__) console.log(arr.__proto__) console.log(fn.__proto__)
3. 全部的函数,都有一个prototype属性(显式原型),属性也是一个普通的对象
//显式原型 console.log(fn.prototype)
4. 全部的引用类型(数组、对象、函数),_proto_属性值指向它的构造函数的“prototype”的值
//_proto_属性值指向它的构造函数的“prototype”的值 console.log(`arr.__proto__ === Array.prototype:${arr.__proto__ === Array.prototype}`) console.log(`obj.__proto__ === Object.prototype:${obj.__proto__ === Object.prototype}`) console.log(`fn.__proto__ === Function.prototype:${fn.__proto__ === Function.prototype}`)
5. 当试图获得一个对象的某个属性时,若是这个对象自己没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找
Person.prototype.sayName = function() { console.log(`个人名字:${this.name}`) } p.introduction() p.sayName()
执行sayName时的时候,对象p自己没有该方法,会去它的__proto__即它的构造函数的prototype中寻找(p.__proto__或者Person.prototype),因而找到sayName.
什么是原型对象
Person这个构造函数的显式原型是一个对象,简称原型对象。Person.prototype
就是原型对象。
每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,即原型对象(Person.prototype)是 构造函数(Person)的一个实例。
Person.prototype = p.__proto__
原型对象的优势
能够 让全部对象实例共享它所包含的属性和方法。换句话说,没必要在构造函数中定义对象实例的信息,而是 能够将这些信息直接添加到原型对象中,好比下面的sayName方法。
Person.prototype.sayName = function() { console.log(`个人名字:${this.name}`) }
如何查找对象自身的属性
var item for (item in p) { // 高级浏览器已经在for in中屏蔽了来自原型的属性 // 如下的判断可保证程序的健壮性,hasOwnProperty方法会返回一个布尔值,指示对象自身属性中是否具备指定的属性 if (p.hasOwnProperty(item)) { // 输出name和printName,没有alerName console.log(item) } }
ECMAScript 中描述了原型链的概念,并将原型链做为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另外一个引用类型的属性和方法。
p.toString()是如何调用的
执行toString方法时,p自己没有该方法,p.__proto__也没有,继续往上p.__proto__.__proto__即Person.prototype.__proto__,Person.prototype就是普通对象,Person.prototype.__proto__ = Object.prototype,Object中存在toString方法。
原型链图
每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型。对象的内部指针这么一层一层的查找就是原型链查找,如此层层递进,就构成了实 例与原型的链条,这种链式结构叫作“原型链“。
jQuery.fn.init.prototype = jQuery.fn,将原型方法为何放在jQuery.fn中,是由于要扩展插件以下面的printQT 方法, 只有$会暴露在window全局变量(太多会形成污染),将插件扩展统一到jQuery.fn.xxx这一个接口方便使用。
var jQuery = function() { return new jQuery.fn.init(); } jQuery.fn = jQuery.prototype = { constructor: jQuery, init: function() { this.jquery = "1.9.1"; return this; } } jQuery.fn.init.prototype = jQuery.fn; jQuery.fn.printQT = function() { console.log("切图") return this; } window.jQuery = window.$ = jQuery; console.log(jQuery().printQT())
除了jquery中的运用,在vue中使用诸如echarts的插件时,咱们会使用Vue.prototype.$echarts = echarts,将echarts引入到全局使用,一样自定义方法变量也能够如此使用。
尊重原创,如需转载请注明出处!