程序员の必经之路js基础

Js学习笔记 - 初识Js对象

2016-11-14  本文已影响50人  Ursus_M

前言

最近在廖雪峰的官方网站,看了一些Javascript的相关教程,感觉这套教程里的思路还是挺清晰明了的,该篇读书笔记就是将其中对象方面的内容进行了一个总结性的整理。

关于js中的对象

格式

var hero = {
    name: 'hero',
    sex: 'male' ,
    'code-name': 'codename',
    shoot: function () {
        console.log(this.name + ' is shooting');
    }
    info: function () {
        console.log('name:' + this.name + '\n'
            + 'sex:' + this['sex'] + '\n'
            + 'code-name:' + this['code-name']);
    }
};

在javascript中,对象是以键值对的形式存在的,格式上:

  1. 格式和json有点类似,用 {} 括起来,属性和值之间用 : 隔开,而非 =
  2. 每组键值对(属性与值)之间用 , 隔开
  3. 如果属性名中包含特殊字符,比如 - 的话,属性名要用 ''括起来
  4. 属性的值可以是一个函数

用法

调用
console.log('name:' + hero.name + '\n'
            + 'sex:' + hero['sex'] + '\n'
            + 'code-name:' + hero['code-name']);
            
hero.shoot();
hero.info();
  1. 直接用 变量.属性 或者 变量['属性'],如果属性名是用 '' 隔开的只能用 变量['属性'] 方式
  2. 如果属性是方法,也是用 变量.属性(参数..)的方式调用。
属性增加删除
    console.log(hero.height);//undefined
    
    hero.height = 180;//添加属性
    console.log(hero.height);//180
    
    delete hero.height;//删除属性
    console.log(hero.height);//undefined

添加的话,直接赋值即可。删除时,如果属性不存在也不会报错

判断属性是否存在

判断属性存在有两种方式

  1. '属性名' in '变量', 返回true/false,存在true,不存在就是false。如果该属性是继承下来的属性那么同样返回 true
  2. hasOwnProperty方法,返回 true/false,存在true,不存在就是false。只有是自身属性才返回true。
   console.log('name' in hero);//true
   console.log('height' in hero);//false
   console.log('toString' in hero);//true
   hero.hasOwnProperty('name');//true
   hero.hasOwnProperty('height');//false
   hero.hasOwnProperty('toString');//false

特性

_proto_ 和 Object.create()

将A对象的原型指向B对象,那么A对象就获得了B对象中的属性

    var dva = {
        name: 'D.VA',
        height: 180,
    }
    dva.__proto__ = hero;
    dva['code-name'];//codename

不过一般不直接使用对象的 __protp__ 属性,部分浏览器不支持,通常的做法是使用 Object.create 方法

    function createStudent(name) {
        var s = Object.create(hero);
        s.name = name;
        return s;
    }
    var mercy = createStudent("mercy");
    mercy['code-name'];//codename
new一个对象

js中 用 new 调用一个函数会返回一个新创建的对象,该函数中的 this 就指向这个新创建的对象。

    function Map(name) {
        this.name = name;
        this.start = function () {
            console.log('正在前往' + name);
        }
    }

    var Dorado = new Map('多拉多');
    Dorado.name;//多拉多
    Dorado.start();//正在前往多拉多

    var Numbani = new Map('努巴尼');
    Numbani.name;//努巴尼
    Numbani.start();//正在前往努巴尼

js中调用普通函数,会返回一个 undefined

原型链
js原型链

当在js中访问某个对象的属性时(obj.xxx

  1. 首先会在改对象中查找该属性
  2. 如果第1步找不到该属性,就会从该对象的原型对象中查找(该对象 __proto__ 属性指向的对象)
  3. 找不到的话会一直找下去,直到找到 Object.prototype,如果还没有就会返回undefined。

这样就形成了原型链

Dorado ----> Map.prototype ----> Object.prototype ----> null

    Dorado.__proto__ === Map.prototype;//true
    Map.prototype.__proto__ === Object.prototype;//true
    Object.prototype.__proto__ === null;//true
    Dorado.constructor === Map;//true

上面对象中 _Dorado__Numbani_ 中的 _start_ 属性一个函数,函数名和代码都相同,根据原型链,DoradoNumbani 上找不到的属性,会从他们的原型上找,于是我们可以将 _start_ 属性移动到 Map.prototype上。

    function Map(name) {
        this.name = name;
    }

    Map.prototype.start = function () {
        console.log('正在前往' + this.name);
    };
jsc_pic002.png
create一个对象三步曲
  1. 创建构造函数
  2. 添加通用方法
  3. 封装构造函数
    //第一步:创建构造函数(首字母一般大写,用于和普通函数区分)
    function Map(props){
        this.name = props.name || '训练靶场';
    }

    //第二步:添加通用方法(方法写在构造函数prototype中)
    Map.prototype.start = function () {
        console.log('正在前往' + this.name);
    }

    //第三步:封装构造函数(把构造函数封装一下,省的调用的时候每次都写new)
    function createMap(props){
        return new Map(props || {});
    }

    var Trainrang = createMap();
    Trainrang.start();//正在前往训练靶场

    var Nepal = createMap({
        name : '尼泊尔'
    });
    Nepal.start();//正在前往尼泊尔
原型继承

当一个对象中的某个属性找不到时,会在原型上去找,所以可以通过原型在js中完成继承操作。
如果想创建Map的一个子类FestvialMap,那么FestvialMap的原型链应该是:
FerguGym ----> FestivalMap.prototype ----> Map.prototype ----> Object.prototype ----> null

js原型链

如上图,最简单的方式就是将 FestivalMap.prototype.__proto__ = Map.prototype,不过一般不会直接操作对象的__proto__属性。于是采用下面的方案

  1. 创建一个空函数 M ,这时 new M() 对象的 __proto__ 属性就指向了 M.prototype
  2. M.prototype 赋值为 Map.prototype,这时 new M() 对象的 __proto__就指向了 Map.prototype
  3. FestivalMap.prototype 赋值为 new M(),这时 FestivalMap.prototype 对象的 __proto__就指向了 Map.prototype
  4. 由于现在的 FestivalMap.prototype 就是刚才新创建的 new M(),将他的 constructor 属性指向他本身
    function FestivalMap(props) {
        Map.call(this, props);
    }

    function createFestivalMap(props) {
        return new FestivalMap(props || {});
    }

    //创建一个空函数 M ,这时 new M() 对象的 __proto__ 属性就指向了 `M.prototype`
    function M() {

    }

    //将 M.prototype 赋值为 Map.prototype,这时 new M() 对象的 __proto__就指向了 Map.prototype
    M.prototype = Map.prototype;
    
    //将 FestivalMap.prototype 赋值为 new M(),这时 FestivalMap.prototype 对象的 __proto__就指向了 Map.prototype
    FestivalMap.prototype = new M();
    
    //由于现在的 FestivalMap.prototype 就是刚才新创建的 new M(),将他的 constructor 属性指向他本身
    FestivalMap.prototype.constructor = FestivalMap;
    
    FestivalMap.prototype.type = function () {
        console.log('特殊地图:' + this.name)
    }
    
    var FerguGym = createFestivalMap({
        name: '弗格体育场',

    });
    console.log(FerguGym.name);//弗格体育场
    FerguGym.start();//正在前往弗格体育场
    FerguGym.type();//特殊地图:弗格体育场

封装这几步

    function inherits(Child,Parent){
        var F = function(){};
        F.prototype = Parent.prototype;
        Child.prototype = new F();
        Child.prototype.constructor = Child;
    }
class继承

在ES6新增了用关键字 class 来定义类的方式,和原型类继承原理是一样的,只是简化了代码。

    class Map {
    
        //构造方法
        constructor(name) {
            this.name = name || '训练靶场';
        }

        //相当于之前的 Map.prototype.start = function(){...},前面不加function
        start() {
            console.log('正在前往' + this.name);
        }
    }

    var LijiangTower = new Map('漓江塔');
    LijiangTower.start();//正在前往漓江塔

    class FestivalMap extends Map {
        constructor(name) {
            //调用父类构造方法
            super(name);
        }

        type() {
            console.log('特殊地图:' + this.name);
        }
    }

    var FerguGym = new FestivalMap('弗格体育场');
    FerguGym.start();//正在前往弗格体育场
    FerguGym.type();//特殊地图:弗格体育场
上一篇下一篇

猜你喜欢

热点阅读