淮南网站建设好潍坊专业网络营销

当前位置: 首页 > news >正文

淮南网站建设好,潍坊专业网络营销,百度快照官网,360优化大师下载官网一.什么是原型与原型链 根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] #xff0c;对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型#xff0c;并从中继承方法和属性#xff0c;一层一层、以此类…一.什么是原型与原型链 根据MDN官方解释: JavaScript 常被描述为一种基于原型的语言——每个对象拥有一个原型对象[[Prototype]] 对象以其原型为模板、从原型继承方法和属性。原型对象也可能拥有原型并从中继承方法和属性一层一层、以此类推。这种关系常被称为原型链 (prototype chain)它解释了为何一个对象会拥有定义在其他对象中的属性和方法。 以前可以通过proto访问原型,但现在它已经从相关web标准中被移除,后续可通过Object.getPrototypeOf(obj)来获取原型。在 javascript 中函数可以有属性。每个函数都有一个特殊的属性叫作原型prototype,而它主要是用作继承。 二.原型的作用 之所以存在原型,是因为JS语言需要实现面向对象,而原型是面向对象的实现手段之一。一个能支持面向对象的语言必须做到一点:能判断一个实例的类型. 在JS中,通过原型就可以知晓某个对象从属于哪个类型,换句话说,原型的存在避免了类型的丢失。在使用方面,有了原型就可以抽离实例的公共方法到原型上,这样就避免了把方法放到实例中,从而减少了内存的消耗。 三.隐式原型和显示原型的区别 在过去我们常用proto表示隐式原型(它其实就是[[Prototype]])。用prototype代表显示原型。 每个对象(数组,对象,函数)都有自己的proto,通过proto可以添加数据到原型,也可以通过它一层一层查找数据。构造函数默认会有prototype属性,prototype属性是用来继承的,实例化之后proto会指向构造函数的prototype。 四.JS的继承 父类 function Person(name) {this.name namethis.say function () {console.log(1 1 2)}this.colors [red, blue, green]; }Person.prototype.listen function () {console.log(エウテルペ) }Person.prototype.sayName function () { // 父类原型方法return this.name;};4.1 原型继承 将父类的实例作为子类的原型 缺点: 无法实现多继承,即一个子类不能同时继承多个父类所有实例共享同一个父类的原型,修改子类的原型会影响父类的原型创建子类实例时无法向父类构造函数传参 // TODO:思路:将父类的实例作为子类的原型 function Student() {this.type 学生this.name 张三 }Student.prototype new Person(人) //TODO:关键点 通过原型继承父类 无法实现多继承,即一个子类不能同时继承多个父类 Student.prototype.xx 123 Student.prototype.fn (){}const zhangsan new Student() console.log(zhangsan);Person.prototype.eat function () {console.log(吃东西) } console.log(zhangsan);// TODO:缺点 // 1 无法实现多继承,即一个子类不能同时继承多个父类 // 2 所有实例共享同一个父类的原型 function Student2() {this.type 学生this.name 张三 } Student2.prototype new Person(人2) // 3 创建子类实例时无法向父类构造函数传参 const lisi new Student2()4.2 构造继承 在子类的构造函数内部调用父类构造函数并改变构造函数的this指向。 缺点: 父类原型上的属性没有继承过来因为原型没有继承过来所以无法实现函数复用每个子类都有父类构造函数的副本影响性能实例并不是父类的实例只是子类的实例 // TODO:思路:在子类型的构造函数内部调用父类构造函数并改变构造函数的this指向。 function Student(name) {// this.person new Person(name)Person.call(this,name) // TODO:关键点this.age 16 } Student.prototype.run 跑路 const lisi new Student(李四) // 能实现多继承 可以向父类传递参数 // 优点 // 解决了所有实例共享同一个父类的原型实现多继承创建子类实例时可以向父类传递参数 // TODO:缺点 // 1 父类原型上的属性没有继承过来 function Student2(name) {Person.call(this,name)this.age 18 } // 2 因为原型没有继承过来所以无法实现函数复用每个子类都有父类构造函数的副本影响性能// 3 实例并不是父类的实例只是子类的实例(只是实例化了Student,根本就没有实例化Person) const zhangsan new Student(张大帅)4.3 组合继承 顾名思义组合继承就是将原型链继承与构造函数继承组合在一起从而发挥两者之长的一种继承模式。 缺点: 所有实例共享同一个父类的原型,修改子类的原型会影响父类的原型调用了两次父类的构造函数 // TODO:思路:顾名思义组合继承就是将原型链继承与构造函数继承组合在一起从而发挥两者之长的一种继承模式。 function Student(name, subName) {Person.call(this, name) // 构造继承 第一次调用构造函数this.subName subName; } Student.prototype new Person() // TODO:关键点 原型继承 第二次调用构造函数 // Student.prototype Person.prototype Student.prototype.constructor Student // 组合继承需要修复构造函数指向? Student.prototype.saySubName function () { // 子类原型方法return this.subName; }// 子类实例 let instance new Student(王五, sisterAn) instance.colors.push(black) console.log(instance.colors) // [red, blue, green, black] console.log(instance.sayName()) // 王五 console.log(instance.saySubName()) // sisterAn console.log(instance);let instance1 new Student(赵六, sisterAn1) console.log(instance1.colors) // [red, blue, green] console.log(instance1.sayName()) // 赵六 console.log(instance1.saySubName()) // sisterAn1 console.log(instance1); // 优点:解决了构造继承的缺陷,可以继承原型属性/方法,实现复用 // TODO:缺点:调用了两次父类的构造函数4.4 寄生组合继承 通过原型链的混成形式来继承方法,在组合继承的基础上.利用 Object.create() 将Person.prototype通过原型的方式继承给一个对象,这样的访问顺序就还是保持子类优先,同时后续添加原型也不会影响父类的原型 优点: 解决了组合继承的缺陷,只调用一次父类的构造函数修改子类的原型,父类不变 补充 Student.prototype.isPrototypeOf(instance) 用于检测构造函数Student.prototype是否存在于另一个对象instance的原型链上 instance instanceof Student 用于检测实例对象instance的原型链上是否存在构造函数Student的 prototype。
// TODO:思路:通过原型链的混成形式来继承方法 function Student(name, subName) {Person.call(this, name) // 构造继承this.subName subName; } // 用 Object.create() 将参数1通过原型的方式继承给参数2,这样的访问顺序就还是保持子类优先,同时后续添加原型也不会影响父类的原型 console.log(Object.create(Person.prototype)); Student.prototype Object.create(Person.prototype, {varB : {value: null,enumerable: true,configurable: true,writable: true},doSomething : {value: function(){ // overrideA.prototype.doSomething.apply(this, arguments);// call super// …},enumerable: true,configurable: true,writable: true}}); // TODO:关键点 Student.prototype.constructor Student // 组合继承需要修复构造函数指向// 子类实例 let instance new Student(王五, sisterAn) instance.colors.push(black) console.log(instance.colors) // [red, blue, green, black] console.log(instance.sayName()) // 王五 console.log(instance.doSomething()) console.log(instance);let instance1 new Student(赵六, sisterAn1) console.log(instance1.colors) // [red, blue, green] console.log(instance1.sayName()) // 赵六 console.log(instance1.doSomething()) console.log(instance1); // 优点:解决了组合继承的缺陷,只调用一次父类的构造函数,原型链保持不变 // Student.prototype.isPrototypeOf(instance) true // 用于检测构造函数Student.prototype是否存在于另一个对象instance的原型链上 // instance instanceof Student // 用于检测实例对象instance的原型链上是否存在构造函数Student的 prototype。4.5 ES6继承 可以理解ES6继承就是组合寄生继承的一个语法糖. 使用 class People {constructor(name) {this.name name}run() { } }// extends 相当于方法的继承 // 替换了上面的3行代码 class Man extends People {constructor(name) {// super 相当于属性的继承// 替换了 People.call(this, name)super(name)this.gender 男}fight() { } }extends 继承的核心代码如下其实和寄生组合式继承方式一样 function _inherits(subType, superType) {// 创建对象Object.create 创建父类原型的一个副本// 增强对象弥补因重写原型而失去的默认的 constructor 属性// 指定对象将新创建的对象赋值给子类的原型 subType.prototypesubType.prototype Object.create(superType superType.prototype, {constructor: { // 重写 constructorvalue: subType,enumerable: false,writable: true,configurable: true}});if (superType) {Object.setPrototypeOf? Object.setPrototypeOf(subType, superType): subType.
proto__ superType;} }五.关于Object.prototype.proto已经弃用 后续可通过Object.getPrototypeOf(obj)来获取原型!
示例 let Circle function () {}; let shape {}; let circle new Circle();// 设置该对象的原型链引用 // 过时且不推荐使用的。这里只是举个例子尽量不要在生产环境中这样做。 shape.proto circle;// 判断该对象的原型链引用是否属于 circle console.log(shape.proto circle); // true