深入浅析js原型链和vue构造函数
简单回顾下构造函数,原型和实例的关系:
每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针.
然鹅,在js对象里有这么一个规则:
如果试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性.
少废话,先来看个例子:
function Fun1 () { this.win = "skt" } Fun1.prototype.getVal = function () { return this.win } function Fun2 () { this.other_win = "rng" } Fun2.prototype = new Fun1 () Fun2.prototype.getOtherVal = function () { return this.other_win } let instance = new Fun2() console.log(instance.getVal()) //skt
在上述例子中,有一个很有意思的操作,我们让原型对象指向了另一个类型的实例,即: constructor1.property = instance2
那么他是怎么找到instance.getVal()的"color: #ff0000">二、prototype 和 __proto__ 都是个啥"htmlcode">
2.__proto__是对象具有的属性,但__proto__不是一个规范的属性,对应的标准属性是 [[Prototype]] 我们可以把__proto__理解为构造器的原型,大多数情况下 __proto__ === constructor.prototype ( Object.create()除外 ) 三、new又是个什么鬼"htmlcode">
上述代码中,我们通过new命令实例化了一个叫Fun的函数并赋值给f,这个新生成的实例对象f从构造函数Fun中得到了team属性,其实构造函数内部的this,就代表了新生成的实例对象,所以我们打印f.team的值就取到了rng这个值 这又是哪门子原理"构造函数"的原因,就是操作一个空对象(即this对象),将其“构造”为所需要的样子。 如果我不加new呢"htmlcode">
我们可以看出上面打印f为undefined,而team却有值,这又是为什么"color: #ff0000">四、 __proto__指向哪"htmlcode">
2.构造器方式 3.Object.create()方式 注: Object.create(prototype, descriptors) 创建一个具有指定原型且可选择性地包含指定属性的对象 五、如何确定原型和实例的关系"htmlcode">
由于原型链的关系,我们可以说fun2是一个对象Object,Fun1或是Fun2中任何一个类型的实例,所以这三个结果都返回了true 2.isPrototype() 这个方法同样,只要是原型链中出现过的原型,该方法就会返回true,用法如下 六、原型链的问题 什么"color: #ff0000">七、如何解决原型链问题"htmlcode">
我们可以看出,借用构造函数一举解决了原型链的两大问题: 其一, 保证了原型链中引用类型值的独立,不再被所有实例共享; 其二, 子类型创建时也能够向父类型传递参数. 但是还还还有一个问题,如果仅仅借用构造函数,那么将无法避免构造函数模式存在的问题: 方法都在构造函数中定义, 因此函数复用也就不可用了.而且超类型(如Father)中定义的方法,对子类型而言也是不可见的. so,借用构造函数的技术也很少单独使用. 2.组合继承 组合继承, 有时候也叫做伪经典继承,指的是将原型链和借用构造函数的技术组合到一块,从而发挥两者优点的一种继承模式. 基本思想: 使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承. 这样,既通过在原型上定义方法实现了函数复用,又能保证每个实例都有它自己的属性. 接着看例子: 我们可以看出,组合继承既保证了引用类型不再被所有实例所共享,也能够让子类型创建时向父类型传参,同时,原型中的方法又能够被复用,可以说是避免了原型链中的两大问题以及借用构造函数的缺陷,因此他也是js中最常用的继承方式,而且 instanceof 和 isPrototypeOf( )也能用于识别基于组合继承创建的对象. 3.原型继承 基本思想: 借助原型可以基于已有的对象创建新对象, 同时还不必因此创建自定义类型 绳么意思"htmlcode">
在这个例子中,可以作为另一个对象基础的是obj对象,于是我们把它传入到fun()函数中,然后该函数就会返回一个新对象. 这个新对象将arr作为原型,因此它的原型中就包含引用类型值属性. 然后我们向该属性中又增加了一个元素,所以我们能够将它打印出来 *在原型继承中, 包含引用类型值的属性始终都会共享相应的值, 就像使用原型模式一样. 4.寄生式继承 基本思想:创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真的是它做了所有工作一样返回对象 上面的例子中,我们把obj传入createAnother()函数中,返回的新对象clone不仅拥有了该属性,而且还被增强了,拥有了sayHi()方法; 等一下,这里要注意: 使用寄生式继承来为对象添加函数, 会由于不能做到函数复用而降低效率;这一点与构造函数模式类似. 5.寄生组合式继承 前面讲过,组合继承是 JavaScript 最常用的继承模式; 不过, 它也有自己的不足. 组合继承最大的问题就是无论什么情况下,都会调用两次父类构造函数: 一次是在创建子类型原型的时候, 另一次是在子类型构造函数内部. 寄生组合式继承就是为了降低调用父类构造函数的开销而诞生的 基本思想:不必为了指定子类型的原型而调用超类型的构造函数 inheritPrototype函数接收两个参数:子类型构造函数和超类型构造函数。 1. 创建超类型原型的副本。 2. 为创建的副本添加constructor属性,弥补因重写原型而失去的默认的constructor属性 3. 将新创建的对象(即副本)赋值给子类型的原型 inheritPrototype的高效率体现在它没有调用superClass构造函数,因此避免了在subClass.prototype上面创建不必要多余的属性. 同时,原型链还能保持不变,可以说是相当奈斯 由于寄生组合式继承,集寄生式继承和组合继承的优点于一身,是实现基于类型继承的最有效方法. 八.vue构造函数 我们在使用的vue的时候,经常会用new操作符去将他实例化,这说明vue也是一个构造函数,那么他是如何被创建的呢"word-spacing: 0px; text-transform: none; font-weight: bold; color: rgb(0,0,0); font-style: normal; text-align: center; orphans: 2; widows: 2; letter-spacing: normal; text-indent: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px">
let fun = function () {}
console.log(fun.prototype) // object
console.log(fun.__proto__) // function
let obj = {}
console.log(obj.prototype) // underfined
console.log(obj.__proto__) // object
function Fun() {
this.team = "rng"
}
let f = new Fun()
console.log(f.team) // rng
function Fun() {
this.team = "rng"
}
let f = Fun()
console.log(f) // undefined
console.log(team) // rng
let obj = {}
console.log(obj.__proto__) // object
console.log(obj.__proto__ === obj.constructor.prototype) // true 证明用字面量创建的函数,他的__proto__ 等于 该对象构造器的原型
function Func () {}
let a = new Func()
console.log(a.__proto__) // object
console.log(a.__proto__ === a.constructor.prototype) // true
let obj1 = {name:"rng"}
let obj2 = Object.create(obj1)
console.log(obj2.__proto__) //{name: "rng"}
console.log(obj2.__proto__ === obj2.constructor.prototype) // false
function Fun1 () {
this.laji = "uzi"
}
function Fun2 () {
this.strong = "faker"
}
Fun2.prototype = new Fun1()
let fun2 = new Fun2 ()
console.log(fun2 instanceof Fun1) // true
console.log(fun2 instanceof Fun2) // true
console.log(fun2 instanceof Object) // true
console.log(Fun1.prototype.isPrototypeOf(fun2)) // true
console.log(Fun2.prototype.isPrototypeOf(fun2)) // true
console.log(Object.prototype.isPrototypeOf(fun2))// true
function Father () {
this.team = ["letme","mlxg"]
}
function Son () {
Father.call(this)
}
let son = new Son()
son.team.push("uzi")
console.log(son.team) // ["letme", "mlxg", "uzi"]
let little_son = new Son()
console.log(little_son.team) // ["letme", "mlxg"]
function Father (team) {
this.team = team
this.people = ["mlxg","letme"]
}
Father.prototype.sayTeam = function () {
return console.log(this.team)
}
function Son (team,age) {
this.age = age
Father.call(this,team)
}
Son.prototype = new Father()
Son.prototype.sayAge = function () {
return console.log(this.age)
}
let son = new Son("faker",8)
son.people.push("uzi")
console.log(son.people) // ["mlxg", "letme", "uzi"]
son.sayAge() //8
son.sayTeam() // faker
let little_son = new Son("bang",3)
console.log(little_son.people) // ["mlxg", "letme"]
little_son.sayAge() // 3
little_son.sayTeam() // bang
function fun(o){
function F(){}
F.prototype = o;
return new F();
}
let obj = {arr:[11,22]
fun(obj).arr.push(33)
console.log(fun(obj).arr) // [11,22,33]
function fun(o){
function F(){}
F.prototype = o;
return new F();
}
let obj = {a:[11,22]}
function createAnother(z) {
// 通过调用函数创建一个新对象
var clone = fun(z);
clone.sayHi = function () {
alert("hi");
}
return clone;
}
createAnother(obj)
function inheritPrototype(subType, superType) {
var protoType = Object.create(superType.prototype); //创建对象
protoType.constructor = subType; //增强对象
subType.prototype = protoType; //指定对象
}
function Father(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
Father.prototype.sayName = function () {
console.log(this.name);
}
function Son(name, age) {
Father.call(this, name);
this.age = age;
}
inheritPrototype(Son, Father)
Son.prototype.sayAge = function () {
console.log(this.age);
}
var instance = new Son("uzi", 3);
instance.sayName(); //uzi
instance.sayAge(); //3
在第八行代码中,创建了一个Vue的函数,这不就是Vue的构造函数么,而且在12行的警告中我更加肯定了,他说:Vue是一个构造函数,应该使用“new”关键字调用
然后他在下面,他分别在
initMixin()
stateMixin()
eventsMixin()
lifecycleMixin()
renderMixin()
这五个方法中讲Vue作为形参传入,最后将Vue导出.
那么这五个方法是干什么的呢"word-spacing: 0px; text-transform: none; font-weight: bold; color: rgb(0,0,0); font-style: normal; text-align: center; orphans: 2; widows: 2; letter-spacing: normal; text-indent: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px">
其他的代码我们先不管,我们就看该方法的前几行,他在Vue的原型中注入了_init方法,这个方法有点眼熟,我们好像在哪见过,对,就是刚才的index.js文件中
这个this_init(options)看上去像是一个内部初始化的一个方法,而option应该就是初始化时的一些配置项了,在Vue被实例化的时候,this._init()方法就会执行
接下来,我们来看一下./state.js文件,找到stateMixin方法
总结
以上所述是小编给大家介绍的js原型链和vue构造函数,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!