Js学习笔记 - 初识Js对象

前言

最近在廖雪峰的官方网站,看了一些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();//特殊地图:弗格体育场
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容