美文网首页
RYF javascript笔记3

RYF javascript笔记3

作者: 暗夜的怒吼 | 来源:发表于2016-05-15 23:08 被阅读15次

    4. 面向对象编程

    4.1 面向对象编程概述

    4.1.1 简介

    4.1.1.1 构造函数

    js没有“类”,而改用构造函数作为对象的模板。

    var Vehicle = function() {
        this.price = 1000;
    };
    

    构造函数是一个正常函数。但是:它使用new命令调用;函数体内部使用this代表要生成的对象实例。

    4.1.1.2 new命令

    new命令执行构造函数,返回一个实例对象。

    使用new调用构造函数时,传多少个参数都可以,甚至可以可以省略括号。

    var Car = function(p) {
        this.price = p;
    };
    var c1 = new Car(); //price:undefined
    var c2 = new Car(1); //price:1
    var c3 = new Car(1,2); //price:1
    var c2 = new Car; //price:undefined
    

    不使用new调用构造函数时,构造函数就变成了普通函数,并不会生成实例对象。而且由于this这时代表全局对象,将造成一些意想不到的结果。

    var c4 = Car();  //c4:undefined
    

    因此,为了保证构造函数必须与new命令一起使用,可以在构造函数内部使用严格模式

    var Lorry = function() {
        "use strict" // 严格模式
        this.price = 1;
    };
    var l = Lorry(); // 无法设置未定义或 null 引用的属性“price”
    

    或者在构造函数内部判断是否使用了new命令。

    function Vehicle (p) {
      if (!(this instanceof Vehicle)) {
        return new Vehicle(p);
      } 
      this._p = p;
    }
    var v1 = new Vehicle(9); // Vehicle里的this指向的是new出来的对象
    var v2 = Vehicle(9); // Vehicle里的this指向的是window对象
    

    4.1.1.3 instanceof运算符

    instanceof用来确定对象是否是某个构造函数的实例。

    在JavaScript之中,所有对象都有对应的构造函数。

    [1, 2, 3] instanceof Array // true
    ({}) instanceof Object // true
    

    但是,由于原始类型的值不是对象,所以不能使用instanceof运算符判断类型。

    "" instanceof String // false
    1 instanceof Number // false
    

    如果存在继承关系,那么instanceof运算符对这些构造函数都返回true。

    var a = [];
    a instanceof Array // true
    a instanceof Object // true
    

    4.1.2 this关键字

    4.1.2.1 涵义

    this是指函数当前的运行环境。

    难点是:JavaScript支持运行环境动态切换。

    function f(){ console.log(this.x); };
    var a = {x:'a'};
    var b = {x:'b'};
    a.m = f;
    b.m = f;
    a.m() // a
    b.m() // b
    

    4.1.2.2 this的使用场合

    1、全局环境
    在全局环境使用this,它指的就是顶层对象window。

    this === window // true 
    function f() {
        console.log(this === window); // true
    }
    

    2、构造函数
    构造函数中的this,指的是实例对象。

    3、对象的方法
    将对象的方法赋值给另一个对象,会改变this的指向。

    var o1 = {m:1};
    o1.f = function (){ console.log(this.m);};
    o1.f() // 1
    
    var o2 = {m:2};
    o2.f = o1.f
    o2.f() // 2
    
    o1.f() // 1
    

    将对象内部的方法赋值给一个变量,也可能改变this的指向。

    var a = {
            b : {
                m : function() {
                    console.log(this.p);
                },
                p : 'Hello'
            }
    };
    var t = a.b.m;
    t(); // undefined
    a.b.m(); // Hello
    

    4.1.2.3 使用注意点

    1、避免多层this
    2、避免数组处理方法中的this
    数组的map和foreach方法,允许提供一个函数作为参数。这个函数内部不应该使用this。

    var o = {
        v: 'hello',
        p: [ 'a1', 'a2' ],
        f: function f() {
            this.p.forEach(function (item) {
                console.log(item); 
                console.log(this.v);
            });
        }
    }
    o.f(); // f函数里的item正确,但this.v是undefinded
    

    解决问题的一种方法,是使用中间变量。

    var o = {
        v: 'hello',
        p: [ 'a1', 'a2' ],
        f: function f() {
            var that = this;
            this.p.forEach(function (item) {
                console.log(this.v);
            });
        }
    }
    

    3、避免回调函数中的this
    回调函数中的this往往会改变指向,最好避免使用。

    4.1.3 固定this的方法

    4.1.3.1 call方法

    函数的call方法,可以改变指定该函数内部this的指向,然后再调用该函数。

    var n = 123;
    var o = { n : 456 };
    
    function a() {
      console.log(this.n);
    }
    
    a.call() // 123
    a.call(null) // 123
    a.call(undefined) // 123
    a.call(window) // 123
    a.call(o) // 456
    

    如果this所要指向的对象,设定为null或undefined,则等同于指向全局对象。

    call方法的完整使用格式如下:

    func.call(thisValue, arg1, arg2, ...)
    

    4.1.3.2 apply方法

    apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。它的使用格式如下。

    func.apply(thisValue, [arg1, arg2, ...])
    

    apply的第一个参数如果设为null或undefined,则等同于指定全局对象。第二个参数则是一个数组。

    function f(x,y){ console.log(x+y); }
    f.call(null,1,1) // 2
    f.apply(null,[1,1]) // 2
    f.apply(null,[1,1,1]) // 2
    f.apply(null,[]) // NaN
    

    4.1.3.3 bind方法

    bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。它的使用格式如下。

    func.bind(thisValue, arg1, arg2,...)
    

    4.2 封装

    4.2.1 prototype对象

    4.2.1.1 构造函数的缺点

    构造函数定义的属性和方法是属于具体对象的,无法共享。(当然了)

    4.2.1.2 prototype属性的作用

    js的每个对象都有一个原型对象(prototype)。

    • 定义在prototype上面的属性和方法,能被所有实例对象共享。
    • 修改prototype对象会影响所有实例对象。
    • 实例优先调用自身的属性或方法,然后才是prototype的属性或方法。

    示例:

    function Animal () {
    }
    var cat1 = new Animal();
    var cat2 = new Animal();
    
    Animal.prototype.color = "white";
    cat1.color // 'white'
    cat2.color // 'white'
    
    Animal.prototype.color = "yellow";
    cat1.color // 'yellow'
    cat2.color // 'yellow'
    
    cat1.color = 'black';
    cat1.color // 'black'
    cat2.color // 'yellow'
    

    4.2.1.3 原型链

    从自身到原型,再到原型的原型,这样就形成了原型链。直至Object.prototype,它的原型是null,因此原型链结束。

    function MyArray (){}
    MyArray.prototype = new Array();
    
    var mine = new MyArray();
    mine.push(1, 2, 3);
    
    mine.length // 3
    mine instanceof Array // true
    

    4.2.1.4 constructor属性

    prototype对象有一个constructor属性,默认指向prototype对象的构造函数。

    function P() {}
    P.prototype.constructor === P // true
    

    4.2.2 Object.getPrototypeOf方法

    返回对象的原型。

    // 空对象的原型是Object.prototype
    Object.getPrototypeOf({}) === Object.prototype // true
    
    // 函数的原型是Function.prototype
    function f() {}
    Object.getPrototypeOf(f) === Function.prototype // true
    
    // 假定F为构造函数,f为F的实例对象
    // 那么,f的原型是F.prototype
    var f = new F();
    Object.getPrototypeOf(f) === F.prototype // true
    

    4.2.3 Object.create方法

    Object.create方法用于生成新的对象,可以替代new命令。它接受一个原型对象作为参数,返回一个新对象,后者完全继承前者的属性。

    var oldObj = {
        id: 123,
        "name": "Hello"
    };
    var newObj = Object.create(oldObj)
    

    4.2.4 isPrototypeOf方法

    isPrototypeOf方法用来判断一个对象是否是另一个对象的原型。

    var o1 = {};
    var o2 = Object.create(o1);
    var o3 = Object.create(o2);
    o2.isPrototypeOf(o3) // true
    o1.isPrototypeOf(o3) // true
    

    4.3 继承

    4.3.1 proto属性

    在Object对象的实例有一个非标准的proto属性,指向该对象的原型对象,即构造函数的prototype属性。

    var o = new Object();
    o.__proto__ === o.constructor.prototype // true
    o.__proto__ === Object.getPrototypeOf(o) // true
    

    4.3.2 属性的继承

    属性有两种。一种是对象自身的原生属性,另一种是继承自原型的继承属性。

    4.3.2.1 对象的原生属性

    对象的原生属性,可以用Object.getOwnPropertyNames获得。

    Object.getOwnPropertyNames(Date)
    // ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]
    

    只获原生属性中可枚举的,用Object.keys

    Object.keys(Date)// []
    

    判断对象是否具有某个属性,使用hasOwnProperty

    Date.hasOwnProperty('length') // true
    Date.hasOwnProperty('toString') // false
    

    4.3.2.2 对象的继承属性

    用Object.create创建的对象,会继承所有原型对象的属性。

    var proto = { p1: 123 };
    var o = Object.create(proto);
    o.p1 // 123
    o.hasOwnProperty("p1") // false
    

    4.3.2.3 获取所有属性

    判断一个对象是否具有某个属性(不管是自身的还是继承的),使用in运算符。

    "length" in Date // true
    "toString" in Date // true
    

    可用for-in循环所有可枚举属性。

    var o1 = {p1:123};
    var o2 = Object.create(o1,{
        p2: { value: "abc", enumerable: true }
    });
    for (p in o2) {
        console.log(p);
    }
    // p2
    // p1
    

    4.4 JavaScript模块化编程

    4.4.1 使用构造函数封装私有变量

    4.4.2 IIFE封装私有变量

    相关文章

      网友评论

          本文标题:RYF javascript笔记3

          本文链接:https://www.haomeiwen.com/subject/gptbrttx.html