js-继承和闭包

2020-03-31  本文已影响0人  橙赎

继承和闭包

一、面向对象的三大特征

二、什么是继承

继承是面向对象软件技术当中的一个概念,与多态、封装共为面向对象的三个基本特征。继承可以使得子类具有父类的属性和方法或者重新定义、追加属性和方法等。

三、继承的三种方法

 // 构造函数-Person
        function Person(name, age) {
            this.name = name;
            this.age = age;
            this.Say = function () {
                console.log("吃东西")
            }
        }
        // 构造函数-Student来继承Person
        function Student(name,age){
            Person.call(this,name,age)
        }
        const s1 = new Student('张三',24);
        console.log(s1.name,s1.age);
        s1.Say();

但是上述方法不能继承原型对象的属性和方法

 //人-构造函数
        function Person(name, age) {
            this.type = 'human'
            this.name = name
            this.age = age
            this.say = function () {
                console.log("说话>>");
            }
        }
        Person.prototype = {
            constructor: Person,
            eat: function () {
                console.log('吃东西');
            }
        }

        //学生-构造函数
        function Student(name, age) {
            Person.call(this, name, age); // 借用构造函数继承成员
        }

        // 原型对象拷贝继承原型对象成员
        for (const key in Person.prototype) {
            Student.prototype[key] = Person.prototype[key];
        }

        var s1 = new Student('张三', 18)
        console.log(s1.type, s1.name, s1.age) // => human 张三 18
        s1.say();
        s1.eat();
      function Person(name, age) {
            this.type = 'human'
            this.name = name
            this.age = age
        }

        Person.prototype.sayName = function () {
            console.log('hello ' + this.name)
        }

        function Student(name, age) {

        }

        // 利用原型的特性实现继承
        Student.prototype = new Person()

        var s1 = Student('张三', 18)

        console.log(s1.type) // => human

        s1.sayName() // => hello 张三

四、函数的this指向问题

调用方式 非严格模式 备注
普通函数调用 window 严格模式下是undefined
构造函数调用 实例对象 原型方法中的this也是实例对象
对象方法调用 该方法所属对象 紧挨着的对象
事件绑定方法 绑定事件的对象
定时器函数 window

如下例所示:

 //普通函数调用
    const info = function(){
        console.log('普通函数this  :',this);
    }
    //info(); //window
    // 构造函数调用
    function Person(){
        console.log('构造函数this ',this);//Person
        this.name = '构造函数'
        this.sayName = function(){
            console.log('对象方法this ',this);//Person
        }
    } 
    // 原型对象
    Person.prototype.eat = function(){
        console.log('原型方式this :',this);//Person
    }

    Person.prototype.eat = () => {
        console.log('原型方式this :',this);//箭头函数里没有this,该this指向为外层,即window
    }

    const p = new Person();
    p.sayName();
    p.eat();

    // 事件绑定
    const btn  = document.getElementById('btn');
    btn.onclick = function(){
        console.log('事件绑定this ',this);//<button id="btn">按钮</button>
    }
    // 定时器
    setTimeout(function(){
        console.log('定时器this',this);
    },1000)//window

五、call()和apply()的区别和作用

call()apply()都可以改变this的指向

区别:它们的区别在于接受的参数方式不同

  • call():第一个参数是this值没有变化,变化的是其余参数都直接传递给函数。在使用call()方法时,传递给函数的参数必须逐个列举出来
  • apply():传递给函数的是参数数组

六、闭包

1.变量作用域

要理解闭包,首先必须理解Javascript特殊的变量作用域。

变量的作用域无非就是两种:全局变量和局部变量。

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。

 var n=999;
  function f1(){
    alert(n);
  }
  f1(); // 999

另一方面,在函数外部自然无法读取函数内的局部变量。

function f1(){
    var n=999;
  }
alert(n); // error
2.闭包

出于种种原因,我们有时候需要得到函数内的局部变量。但是,前面已经说过了,正常情况下,这是办不到的,只有通过变通方法才能实现。

那就是在函数的内部,再定义一个函数,只要把f2作为返回值,我们不就可以在f1外部读取它的内部变量了

function f1(){
    var n=999;
    function f2(){
      alert(n);
    }
    return f2;
  }
  var result=f1();
  result(); // 999

上面代码的f2函数就是闭包,简单理解为:闭包就是能够读取其他函数内部变量的函数

闭包形成的条件:

3.闭包的用途和特点
//例题1
var inner;
function outer(){
  var a=250;
  inner=function(){
    alert(a);//这个函数虽然在外面执行,但能够记忆住定义时的那个作用域,a是250
  }
}
outer();
var a=300;
inner();//一个函数在执行的时候,找闭包里面的变量,不会理会当前作用域。

//例题2
function outer(x){
  function inner(y){
    console.log(x+y);
  }
  return inner;
}
var inn=outer(3);//数字3传入outer函数后,inner函数中x便会记住这个值
inner(5);//当inner函数再传入5的时候,只会对y赋值,所以最后弹出8
上一篇 下一篇

猜你喜欢

热点阅读