JavaScript 面相对象

JavaScript 面相对象

简介

JavaScript 并没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承

ECMAScript 6 带来了新的 Class 语法,这让JavaScript 看起来像是一门基于类的语言,但其背后仍是通过原型机制来创建对象

this

javascript 的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境绑定的,而非函数被声明时的环境

1. 作为对象的方法调用

当函数作为对象的方法调用时,this 指向该对象

    var name = null;

    var o = {
        name: 'name',
        getName: function () {
            console.log(this.name);
        }
    }

    o.getName(); // name
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
2. 作为普通函数调用

此时的 this 总是指向全局对象

    window.name = 'globalName';
    var getName = function(){ 
        console.log(this); // window 
        // ECMAScript 5 的 strict 模式下 这里的this不会指向全局变量,而是 undefined
        return this.name;
    };
    console.log( getName() ); // globalName
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
3. 构造器调用

javascript 中通过构造器来创建对象,同时提供了 new 运算符用来调用,并且返回一个对象,通常情况下,构造器里的 this 指向这个返回的对象


    var Anm = function (name) {
        this.name = name;
    }

    var anm = new Anm('xiaobai');
    console.log(anm.name); // xiaobai

    // 如果构造函数显示的返回了一个引用类型数据,那么 new 出来的结果就是这个对象,而不是之前的this
    var Anm = function (name) {
        this.name = name;
        return {
            test: 'test'
        }
    }

    var anm = new Anm('xiaobai');
    console.log(anm); // {test: "test"}
    console.log(anm.name); // undefined

    // 如果返回的不是引用类型的数据,或者没有显示的返回数据,则返回 this 
    var Anm = function (name) {
        this.name = name;
        return 'test';
    }

    var anm = new Anm('xiaobai');
    console.log(anm); // {name: "xiaobai"}
    console.log(anm.name); // xiaobai
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
4. Function.prototype.call 或者 Function.prototype.apply

这两个方法可以动态的改变传入函数的 this ,两个方法的作用一致,区别在于

  • apply 方法接受两个参数(第一个参数指定函数体内this的指向,第二个参数为一个集合,可以是数组也可以是类数组,apply 方法把这个集合中的元素作为参数传递给被调用的函数)
  • call 传入的参数数量是不固定的,第一个参数代表函数体内 this 的指向,第二个参数开始为需要传入函数体的参数
用途
  1. 改变 this 指向
    var a = {
        name: 'a'
    };

    var b = {
        name: 'b',
        getName: function () {
            console.log(this.name);
        }
    };

    b.getName(); // b
    b.getName.call(a); // a
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. 借用其他对象的方法

    var func = function () {
        // var temp = arguments.shift(); // 报错 arguments.shift is not a function
        var temp = [].shift.call(arguments); // 11

        console.log(temp);
    }

    func(11, 22, 33, 44);

    // 借用内置对象的方法
    var a = Math.max.apply(null, [1, 44, 22, 3]);
    console.log(a); // 44
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  1. 当 call 或者 apply 的第一个参数为 null 时,函数体内的指针会默认指向宿主对象,浏览器中就是 window ,但如果在严格模式下,this 指向 null

    var name = 'global';

    function getName(ages) {
        console.log(this); // window 或者 严格模式先的 null
        console.log(this.name, ages);
    }

    var obj = {
        name: 'in obj'
    };

    getName.call(null, [1, 23, 3]);
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

面向对象的三大特性

1. 封装

封装的目的是将信息隐藏,包括封装数据、封装实现、封装类型、封装变化,将操作封闭,对外提供接口使用

    // 构造函数将同一类对象的实现封装起来
    var F = function (name) {
        this.name = name;
    }
    F.prototype.test = function () {
        console.log(this.name);
    }

    var f1 = new F('xiaobai');
    var f2 = new F('xiaolan');

    f1.test(); // xiaobai
    f2.test(); // xiaolan
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
2. 多态

同一操作作用于不同的对象上,可以产生不同的解释和执行不同的结果,实现上是将‘不变的事物’与‘可能改变的事物’分离

多态的思想实际上是把‘做什么’和‘谁去做’分离开,对象在接受命令的时候如何处理不是临时决定,每个对象应该做什么,已经成为了该对象的一个方法,安装在对象内部,每个对象对自己的行为负责,所以这些对象可以根据同一个命令,分别进行各自的工作。


    // 隔离出不变的部分
    var testFn = function (obj) {
        obj.test();
    }

    // 可变的部分各自封装
    var a = {
        name: 'a',
        test: function () {
            console.log(this.name);
        }
    }

    var b = {
        name: 'b',
        test: function () {
            console.log('name is ' + this.name);
        }
    }

    testFn(a); // a
    testFn(b); // name is b
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
3. 继承

在以类为中心的面向对象语言中,对象总是从类中创建,而 javascript 是基于原型的,对它来说,类不是必须的,对象未必需要从类中创建而来,一个对象可以通过克隆另一个对象所得到

JavaScript 遵守原型编程的基本准则

  1. 所有的数据都是对象(其实是绝大多数都是对象 出了 undefined

  2. 要得到一个对象,不是通过实例化类,而是找到一个对象作为原型并且克隆它(引擎内部实现 通过 new 运算符调用函数创建对象时,实际上也是先克隆了 Object.prototype对象,然后在进行其他的额外操作)

  3. 对象会记住它的原型 (JavaScript 给对象提供了一个隐藏的属性 __proto__它会指向它的构造器的原型对象)

  4. 如果不对象无法响应某个请求,他会把这个请求委托给自己的原型

下一篇 JavaScript 原型与原型链

参考文章
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值