浅谈面向对象和继承

Posted lianqing

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈面向对象和继承相关的知识,希望对你有一定的参考价值。

1.面向对象和面向过程的区别

  面向过程:注重代码的过程

  面向对象:注重代码的结果

2.面向对象三大特性

  抽象   封装  继承  多态(JS不存在多态)

3.什么是一个构造函数

  new 一个关键字函数  创建一个对象,该对象的的属性this指向window 函数里面指向这个对象

  构造函数和普通函数的区别 :

    1、前者的this的指向是实例化后的对象 后者的指向是指向window

    2、普通函数返回值需要加return 构造函数不需要因为返回的是自己本身


  为什么构造函数没有return却能够有返回值呢?
      因为构造函数在调用的时候系统内部 自动return出了一个this,而这个this就是指的这个对象

这是就不得不说下this的指向问题了

this的指向调用它的对象(可以通过bind/apply/call来改变this的指向)

1.严格模式下this的指向为undefined
2.一个对象 属性this指向window 方法里面的指向为这个对象

3.异步事件this的指向为调用它的对象
  计时器为window
  ajax也为window
4.箭头函数中的this
  此时的 this继承自obj, 指的是定义它的对象obj(也可以理解为它外层的指向就是它的指向)
, 而不是 window,里面只要还是箭头函数就一直是obj 而不是window 如若不是则是window(会继承下来)

var obj={
    say:function(){
        un=()=>{
            console.log(this)  //obj
            cn=function(){
                console.log(this)//window
            }
            cn()
            dn=()=>{
                console.log(this) //obj
            }
            dn()
        }
        un()
    }
}
obj.say()

 

var obj={
    say:function(){
        setTimeout(()=>{
    console.log(this) //obj
  });
        (function(){
            console.log(this) //window
        })()
        setTimeout(function(){
            console.log(this) //window
}) } } obj.say()

这里要注意输出顺序函数声明提升

 


5.箭头函数和普通函数混用
  

var obj = {
  say: function () {
     console.log(this) //obj   un
=function(){     console.log(this) //没有宿主对象,默认是window     setTimeout(()=>{     console.log(this) //定义它对象的obj是window   })   }   un() } } obj.say()

 

6.严格模式下的混用
箭头存在其中依然是undefinde
严格模式下,没有宿主调用的函数中的this是undefined!!!所以箭头函数中的也是undefined!

 

继承:

  call和apply一般情况下我们都是用来做属性继承的。

  第一个参数都是 this的指向

  call第二个参数为一系列的值

  apply第二个参数为一个数组

Object.prototype.toString.call():检测一个复杂数据类型是一个什么样的类型
instanceof:判断一个对象是不是另一个对象创建出来的
typeof:只能判断基本数据类型 引用数据类型统计返回OBject

  原型:

  

prototype:
每一个函数里面都有一个prototype属性 这个属性叫做原型 这个原型指向一个对象 我们把这个对象叫做原型对象
  1、节约内存
  2、扩展属性和方法
  3、实现类的继承
原型对象里面有2个东西
  constructor:构造器-->作用指向创建自己的那个构造函数
  __proto__:__proto__属性指向的是创建自己的那个构造函数的原型


  1、每一个对象里面都会有一个__proto__这个属性
  2、__proto__指向了一个对象 这个对象是原型对象
  3、实例化对象可以直接访问__proto__里面的一些方法

    new person).__proto__==person.prototype
  原型链:
什么叫做原型链?
  原型链:由__proto__形成的链条
  Object里面的__proto__指向的是null 原型链的顶点

 

方法继承:后面改变在加会影响到前面的(引用传递)
1.原型继承 Man.prototype = Person.prototype 缺点:污染父级

function person(name,age) {
    this.name=name
    this.age=age
}

person.prototype.eat = function(){
}

person.prototype.sleep = function(){
}

function man(sex){
    this.sex=sex
}
console.log([person])
man.prototype=person.prototype
man.prototype.work = function(){};
p1=new man()
console.log(p1,[person])

2.原型拷贝:for(var attr in person.prototype){
man.prototype[attr]=person.prototype[attr]
}

function person(name,age) {
    this.name=name
    this.age=age
}
person.prototype.eat = function(){
}

person.prototype.sleep = function(){
}
function man(sex){
    this.sex=sex
}
console.log([person])
for(var key in person.prototype){
    man.prototype[key] = person.prototype[key];
}
man.prototype.work = function(){};
p1=new man()
console.log(p1,[person])


缺点:假设Person上面还有父级 那么我们的Man是无法访问到Person父级的原型上的方法

  
3.原型链继承(Man.prototype = new Person())
多了东西少了东西

person.prototype==new man.__proto__.__proto__

function person(name,age) {
    this.name=name
    this.age=age
}
person.prototype.eat = function(){
}

person.prototype.sleep = function(){
}
function man(sex){
    this.sex=sex
}
console.log([person])
man.prototype=new person()
man.prototype.work = function(){};
p1=new man()

 


4.混合继承:少了contructor 原型对象的指向也发生改变 而且还无缘无故多了好多东西
man.prototype = {
  constructor:man,
  //原型链继承
  __proto__:person.prototype
  }(因此改善)


5.寄生继承(间接继承)
利用的是原型链继承的基础
  function fn(){}
继承空的方法
  fn.prototype=person.prototype
因为它是纯净的只有里面的方法 不能直接Man.prototype = new fn() 这样也会污染
  Man.prototype = new fn()
  少了contructor 原型对象的指向也发生改变 而且还无缘无故多了好多东西
  改善(加contructor)
不能做到函数复用

 

以上是关于浅谈面向对象和继承的主要内容,如果未能解决你的问题,请参考以下文章

浅谈JavaScript的面向对象程序设计

浅谈JavaScript的面向对象和它的封装继承多态

面向对象——浅谈弊端

浅谈面向对象

浅谈JavaScript原型链

浅谈Java三大特性之继承