new操作符调用的作用
如果一个函数被使用new操作符调用了,那么它会执行如下操作:
1.在内存中创建一个新的对象(空对象);
2.这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;(后面详细讲);
3.构造函数内部的this,会指向创建出来的新对象;
4·执行函数的内部代码(函数体代码);
5·如果构造函数没有返回非空对象,则返回创建出来的新对象;
1 function foo(){ 2 var moni={} 3 this={} 4 this.__proto__=foo.prototype 5 return this 6 } 7 var fn=new foo() 8 fn.__proto__===foo.prototype
面向对象的特性-继承 面向对象有三大特性:封装、继承、多态
口封装:我们前面将属性和方法封装到一个类中,可以称之为封装的过程;
口继承:继承是面向对象中非常重要的,不仅仅可以减少重复代码的数量,也是多态前提(纯面向对象中);
口多态:不同的对象在执行时表现出不同的形态;
继承-原型链的继承方案
1 //继承-原型链的继承方案 2 function Person(){ 3 this.name='koo' 4 this.friends=[] 5 } 6 Person.prototype.eating=function(){ 7 console.log(this.name+'在吃东西') 8 } 9 function Student(){ 10 this.sno=88 11 } 12 13 var p1=new Person() 14 Student.prototype=p1 15 16 Student.prototype.studing=function(){ 17 console.log('在学习') 18 } 19 // var s1=new Student() 20 // console.log(s1.name) 21 // s1.eating() 22 23 // 原型链实现继承的弊端: 24 // 1.打印stu对象,继承的属性是看不到的 25 // console.log(s1) 26 27 //2.创建出来两个stu的对象 引用数据共享 不独立 28 var stu1=new Student() 29 var stu2=new Student() 30 31 //直接修改对象上的属性,是给本对象添加了一个新属性 32 stu1.name='kobe' 33 console.log(stu2.name) 34 35 //获取引用,修改引用中的值,会相互影响 36 stu1.friends.push('john') 37 console.log(stu1.friends) // 俩个相同 38 console.log(stu2.friends) // 俩个相同 应该每个学生的朋友不同才对 39 40 //3.第三个弊端:在前面实现类的过程中都没有传递参数 41 var stu3=new Student('lilei',222)View Code
借用构造函数继承
为了解决原型链继承中存在的问题,开发人员提供了一种新的技术:constructor stealing(有很多名称:借用构造函数或者称之为经典继承或者称之为伪造对象):
口steal是偷窃、剽窃的意思,但是这里可以翻译成借用;
借用继承的做法非常简单:在子类型构造函数的内部调用父类型构造函数.
口因为函数可以在任意的时刻被调用;
口因此通过apply(和call()方法也可以在新创建的对象上执行构造函数;
coderwhy组合借用继承的问题
组合继承是JavaScript最常用的继承模式之一:
口如果你理解到这里,点到为止,那么组合来实现继承只能说问题不大;
口但是它依然不是很完美,但是基本已经没有问题了;(不成问题的问题,基本一词基本可用,但基本不用)
组合继承存在什么问题呢?
口组合继承最大的问题就是无论在什么情况下,都会调用两次父类构造函数。
一次在创建子类原型的时候;
另一次在子类构造函数内部(也就是每次创建子类实例的时候);
口另外,如果你仔细按照我的流程走了上面的每一个步骤,你会发现:所有的子类实例事实上会拥有两份父类的属性
一份在当前的实例自己里面(也就是person本身的),另一份在子类对应的原型对象中(也就是person.proto_里面);
当然,这两份属性我们无需担心访问出现问题,因为默认一定是访问实例本身这一部分的;
1 //继承-借用构造函数方案 2 function Person(name,friends){ 3 this.name=name 4 this.friends=friends 5 } 6 Person.prototype.eating=function(){ 7 console.log(this.name+'在吃东西') 8 } 9 function Student(name,friends,sno){ 10 Person.call(this,name,friends) 11 this.sno=sno 12 } 13 14 var p1=new Person() 15 Student.prototype=p1 16 17 Student.prototype.studing=function(){ 18 console.log('在学习') 19 } 20 // var s1=new Student() 21 // console.log(s1.name) 22 // s1.eating() 23 24 // 原型链实现继承的弊端: 25 // 1.第一个弊端 打印stu对象,继承的属性是看不到的 也解决3个弊端 26 // console.log(s1) 27 28 //2.第二个弊端,创建出来两个stu的对象 引用数据共享 不独立 也解决3个弊端 29 // var stu1=new Student('koo',['ohn'],88) 30 // var stu2=new Student('kok',['too'],38) 31 32 //直接修改对象上的属性,是给本对象添加了一个新属性 33 // stu1.name='kobe' 34 // console.log(stu2.name) 35 36 //获取引用,修改引用中的值,会相互影响 37 // stu1.friends.push('john') 38 // console.log(stu1.friends) // 俩个相同 39 // console.log(stu2.friends) // 俩个相同 应该每个学生的朋友不同才对 40 41 //3.第三个弊端:在前面实现类的过程中都没有传递参数 也解决3个弊端 42 // var stu3=new Student('lilei',['lisi'],222) 43 44 // 强调:借用构造函数也是有弊端 45 // 1.第一个弊端:Person函数至少被调用了两次 46 // 2.第二个弊端:-stu的原型对象上会多出一些属性,但是这些属性是没有存在的必要View Code
原型式继承函数
原型式继承的渊源
口这种模式要从道格拉斯·克罗克福德(Douglas Crockford,著名的前端大师,JSON的创立者)在2006年写的一篇文章说起:Prototypal Inheritance in JavaScript(在JS中使用原型式继承)
口在这篇文章中,它介绍了一种继承方法,而且这种继承方法不是通过构造函数来实现的.
口为了理解这种方式,我们先再次回顾一下JavaScript想实现继承的目的:重复利用另外一个对象的属性和方法.
1 //继承-原型式继承-对象 2 var obj={ 3 name:'koo', 4 age:18 5 } 6 //原型式继承函数 7 //1 8 function createObject1(o){ 9 var newObj={} 10 Object.setPrototypeOf(newObj,o) 11 return newObj 12 } 13 14 //还没有Object.setPrototypeOf时 写的 15 //2 16 function createObject2(o){ 17 function Fn(){} 18 Fn.prototype=o 19 var newObj=new Fn() 20 return newObj 21 } 22 23 // var info=createObject1(obj) 24 //3 25 var info=Object.create(obj) 26 console.log(info)//{} 27 console.log(info.__proto__)//{ name: 'koo', age: 18 }View Code
寄生式继承函数
寄生式(Parasitic)继承
口寄生式(Parasitic)继承是与原型式继承紧密相关的一种思想,并且同样由道格拉斯·克罗克福德(Douglas Crockford)提出和推广的;
口寄生式继承的思路是结合原型类继承和工厂模式的一种方式;
口即创建一个封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再将这个对象返回;
1 //继承-寄生式继承-对象 2 var personObj={ 3 running:function(){ 4 console.log('running') 5 } 6 } 7 function createStudent(name){//工厂模式 8 var stu=Object.create(personObj)//原型式继承 9 stu.name=name 10 stu.studying=function(){//弊端 每个学生都会创建一个studying方法 11 console.log('studying') 12 } 13 return stu 14 } 15 var stuObj=createStudent('koo') 16 var stuObj1=createStudent('john')View Code
寄生组合式继承
现在我们来回顾一下之前提出的比较理想的組合继承
口组合继承是比较理想的继承方式,但是存在两个问题:
口问题一:构造函数会被调用两次:一次在创建子类型原型对象的时候,一次在创建子类型实例的时候.
口问题二:父类型中的属性会有两份:一份在原型对象中,一份在子类型实例中.
事实上,我们现在可以利用寄生式继承将这两个问题给解决掉.
口你需要先明确一点:当我们在子类型的构造函数中调用父类型.call(this,参数)这个函数的时候,就会将父类型中的属性和方法复制一份到了子类型中.所以父类型本身里面的内容,我们不再需要.
口这个时候,我们还需要获取到一份父类型的原型对象中的属性和方法.
能不能直接让子类型的原型对象 = 父类型的原型对象呢?
口不要这么做因为这么做意味着以后修改了子类型原型对象的某个引用类型的时候,父类型原生对象的引用类型也会被修改.
口我们使用前面的寄生式思想就可以了.
1 //继承-寄生组合式继承 2 function createObj(o){//替代Object.create 3 function fn(){} 4 fn.prototype=o 5 var newObj=new fn() 6 return newObj 7 } 8 function inheritPrototype(subType,superType){ //多个子类用 9 // subType.prototype=Object.create(superType.prototype) 10 subType.prototype=createObj(superType.prototype) 11 // subType.prototype.constructor=subType 12 Object.defineProperty(subType.prototype,'constructor',{ 13 enumerable:false, 14 writable:true, 15 configurable:true, 16 value:subType 17 }) 18 } 19 20 function Person(name,age){ 21 this.name=name 22 this.age=age 23 } 24 Person.prototype.eating=function(){ 25 console.log('eating') 26 } 27 function Student(name,age,sno){ 28 Person.call(this,name,age) 29 this.sno=sno 30 } 31 32 inheritPrototype(Student,Person) 33 34 Student.prototype.studying=function(){ 35 console.log('studying') 36 } 37 38 var stu=new Student('koo',18,88) 39 console.log(stu) 40 stu.eating() 41 stu.studying()
class定义类
1 class Person{ 2 constructor(){ 3 this._address='beijing' 4 } 5 //类的访问器方法 6 get address(){ 7 return this._address 8 } 9 set address(newAddress){ 10 this._address=newAddress 11 } 12 //类的静态方法(类方法) 13 //Person.randomPerson() 14 static randomPerson(){} 15 } 16 var p=new Person() 17 console.log(p.address) 18 p.address='guangzhou'View Code
1 class Person{ 2 constructor(name,age){ 3 this.name=name 4 this.age=age 5 } 6 personMethod(){ 7 console.log('处理逻辑1') 8 } 9 static staticMethod(){ 10 console.log('static method') 11 } 12 } 13 class Student extends Person{ 14 //那么子类的构造方法中,在使用this之前,必须调用super 15 constructor(name,age,sno){ 16 super(name,age) 17 this.sno=sno 18 } 19 //调用 父对象/父类 上的方法 重写 20 personMethod(){ 21 super.personMethod() //复用父类中的处理逻辑 22 console.log('处理逻辑2') 23 } 24 static staticMethod(){ 25 console.log('student static method') 26 } 27 } 28 var stu=new Student('koo',28,88) 29 stu.personMethod() 30 Student.staticMethod()
标签:function,console,name,继承,JavaScript,实现,var,log From: https://www.cnblogs.com/KooTeam/p/17659372.html