Tracy JS 小笔记 - 对象,包装类,原型,原型链

对象

  • 引用值
  • var obj = {
    Name : "Tracy",
    Age : "18",
    Key : "Value",
    health : 100,
    smoke: function(){this.health --;}
    }
    注意,对象里的 smoke 方法,想要改变 health 值,也不能直接写 health, 而是要写 this.health 或者是 obj.health;
  • 对象的方法 obj.smoke();
    对象的属性有两种调用方法: obj.Name; obj['Name'];
  • 属性的增删改查

    • 对象增加 wife 属性: obj.wife = "小刘"; //原来有 wife 属性就是增加,没有就是赋值
    • 对象属性的删除 delete obj.Name

      但是,我们说 window.name 的两种情况

      • 一旦经历了 var 操作,所得出的属性,window, 这种属性叫作不可配置的属性
        不可配置的属性 delete 不掉
        var name = "abc"; window.name 只能查看和修改,删除不掉 (但是删除不会报错)
      • 一个属性是 window.name = "abc"; 添加出来的,就可以删除 delete window.num

       

    • 对象的属性修改 obj.Name = "Others";
    • 对象的属性查看 obj.Name //Tips: 如果打印对象没有的一个属性 比如 obj.abc 那么程序不会报错,而是输出 undefined
  • 对象的两种创建方法
    1. var obj = {} plainObject 对象字面量/对象直接量, 它也有原型,它的原型是 Object.prototype
    2. 构造函数
      1. 系统自带构造函数 Object(), Array(), Number()
        eg : var obj = new Object(); 完全等于 var obj = {} 没有任何区别 (所以硕对象 obj 的原型是 Object.prototype)
        然后自己加属性 obj.name = 'Tracy';

        公司里用的都是对象字面量来写,没有任何理由来用 “var obj = new Object();” 来创建对象,又麻烦 又没有用
      2. 自定义构造函数 (构造函数和正常函数没有任何区别)
        function abc(){} //构造函数
        var var abc1 = new abc(); //有 new 的话 就是生成了一个对象
        abc1.name = 'Tracy'; // 加属性

        为了不要给后面的人增加困难,所以我们构造函数的命名规则一定是大驼峰(首字母也大写)
        function Car(color){
        this.color = color;
        this.name = 'BMW';
        this.height = '1400';
        this.health = 100;
        this.run = function (){this.health-- }
        }

        var car1 = new Car('green');
    3. 构造函数内部原理 这个原理的一切前提都是 这个对象是用 new 来创建的
      1. 在执行体最前面上加一个隐式的 this 对象: var this{ __proto__: 函数名.prototype}
      2. 执行 this.XXX = ZZZ;
      3. 在执行体的最后一行 隐式的返回对象 this

        Tips: 由于这里是隐式放回对象,我们就可以捣乱了
        eg: function Person(name)
        {
        // var this{ __proto__: Person.prototype}
        this.name = name;
        this.age = 10;
        return {};
        //return this;
        }

        var a = Person("Tracy"); 此时输出 a 永远都等于 {} 无论我们赋值什么

        但是如果我们 return 123; 那么是不影响最后 return this 的,系统会自动忽略 return 123. 因为 new 一个对象的时候 返回值一定得是一个对象,不能是一个原始值,返回其他无效

    4. 除了 new 了一个对象里面 的 this 代表一个空对象之外,其他函数里面的new, 统统代表 windows 对象

包装类

  • var a = "abc"; var b = new String ("abc");
    都是字符串,但是 b 是字符串对象了
    a 是原始值, b 是引用值
    b 是可以加属性的 eg: b.Name = "Tracy";

    同理 new Number(); new Boolean();
    var num = new Number(123);
    var bol = new Boolean(true);
  • 原始值坚决不能有属性和方法,属性和方法是对象才可以有的
  • 包装类就是原始值调用属性的时候,隐式的中间系统帮忙转换的过程


    var num = 4;// 原始值 num 为 4

    num.leg = 3;//原始值是没有属性的,这里系统发现傻了吧唧的你给加属性了,系统没办法 就给隐式新 new 了一个对象 new Number(4).leg = 3; 新建对象后,系统马上将该对象删除

    consol.log (num.leg); // undefined
    这里系统发现你竟然又给原始值调用属性了,就有 new Number(4).leg 这里又新建了一个对象,和上一个对象已经没有什么关系了,所以这个对象的leg 属性是 undefined;
  • var arr = [1,2,3,4,5]; arr.length = 2; 此时 arr = [1,2]; 字符串是被截断了

    var str = "12345";
    str.length = 2;
    此时 str 仍然保持原来的值

    var str = "12345";
    str.length = 2; //系统发现,你是一个原始值,你没有 length 属性啊,就新建对象 new String("12345").length = 2 这个新建的对象确实被截断了, 然后马上删除该对象 //然后你打印,就发现,被改变的对象马上就删除了,和你原始值一毛钱关系都没有啊. console.log(str.length); //仍然是 4
  • undefined 和 null 是没有包装类的,它就是普通的原始值,没有任何方法和属性
    比如说 undefined.toString() 是会报错的

原型

  • 对我们人类来说, 人类的祖先就是原型
  • 原型是 function 对象的一个属性, 它定义了构造函数制造出来的对象的公共祖先。 通过该构造函数产生的对象,可以继承该原型的属性和方法。 原型也是对象
    //这里 Person.prototype = {} 就是原型, 它是一个空对象
    function Person(){} //构造函数特点,命名大驼峰
    var person1 = new Person();
    Person.prototype.name = "Tracy"; //祖先添加了属性,那它的所有孙子辈的就自动继承该属性
    此时 person1.name 也有值了, 因为它是祖先的孙子
    • 原型的增删改查
    • Person.prototype.newitem = "增,改,查"
    • delete Person.prototype.newitem 删
  • 原型的应用: 利用原型特点和概念,可以提取共有属性
    function Car(color){
    this.color = color;
    this.carName = "BWM";
    this.height = 100;
    this.leng = 420;
    }
    此时每次 new 一个新对象的时候,就会 新建一些一模一样的 height, leng 等固定的值,这就产生了冗余。 此时我们就想到要用 原型。
    Car.prototype.height = 100;
    Car.prototype.leng = 420;
    Car.prototype.carName = "BWM";
    function Car(color){
    this.color = color;

    }

    上面的三句原型可以简写为
    Car.prototype = {
    height : 100,
    leng : 420,
    carName : "BWM"
    }
  • constructor 对象如何查看对象的构造函数
    function Car(){}
    var car1 = new Car();
    car1.constructor; //constructor 是构造器的意思,返回的是构造这个对象的构造函数
    它其实是 Car 的原型里自带的属性,是继承来的属性. 返回的值是 "function Car(){}"

    constructor 是系统自动生成的,但是我们其实可以是手动改 constructor 的 比如:
    function Person(){}
    Car.prototype = {
    constructor : Person //它原来系统给默认写的是 Car
    }
    function Car(){}
    var car1 = new Car();
    此时 car1.constructor 值为 "function Person(){}",这招就叫作“认贼作父”
  • 隐式属性 __proto__ 对象如何查看原型
    系统自定义属性, 它里面放的就是原型,它把原型和类之间联系到了一起。 在对象自身找不到某属性的时候,它就通过这个 __proto__ 联系,来找原型中的属性
    eg: function Person(name)
    {// 新建对象的时候 隐式生成 var this{ __proto__: Person.prototype}
    this.name = name;
    this.age = 10;
    return {};
    //return this;
    }

    var a = Person("Tracy"); 此时输出 a 永远都等于 {} 无论我们赋值什么


    Person.prototype.name = "abc";
    function Person(){}
    function obj (){name:"tracy"}
    var person1 = new Person();
    此时 person1.name 值为 "abc"
    person1.__proto__ = obj; //把对象 person1 的原型手动给改了
    此时 person1.name 值为 "tracy"
    这招就叫作“认贼作祖父”
  • 一个陷阱
    Person.prototype.name = "abc";
    function Person(){}
    var person1 = new Person();
    Person.prototype.name = "funny"
    console.log(person1.name); //输出 funny
    Person.prototype = {
    name: "Tracy"
    };
    console.log(person1.name); //仍然输出 funny,想想这是为什么呢?

    举个例子
    var obj = {name:"a"};
    var obj1 = obj;
    obj = {name:"b"};
    此时 obj1.name 为 a; obj.name 为 b, 因为 obj = {name:"b"}; 的时候 obj 完全指向了不同的房间

    然后我们分析 Person.prototype.name = "abc";
    function Person(){
    //var this {__proto__: Person.prototype} //在 new 一个对象的时候 这里会有个隐式声明 this
    }
    var person1 = new Person();
    Person.prototype = {name: "Tracy"}; //注意这里是把它在 new 对象的下面
    console.log(person1.name); //输出 abc
    注意 "__proto__" 和 "Person.prototype" 就相当于两个对象的赋值, 而后来的 "Person.prototype = {name: "Tracy"};" 已经是说明了 其中一个对象 "Person.prototype" 指向了不同的房间,但是我们的 "__proto__" 仍然指向以前的房间,所以输出的值仍然是原来的 abc


    另一个骗局 Person.prototype.name = "abc";
    function Person(){}
    Person.prototype = {name: "Tracy"}; //注意这里是把它在 new 对象的上面
    var person1 = new Person();
    console.log(person1.name); //输出 Tracy
    这回我们在还没有 new 的时候就改了,所以就直接指向新的了

原型链

  • 原型本身自己也是有原型的,那么就形成了一个原型链
  • Grand.prototype.lastName = "Deng";
    function Grand(){}

    var grand1 = new Grand();

    Father.prototype = grand1;
    function Father(){}

    var father1 = new Father();

    Son.prototype = father1;
    function Son(){}

    var son1 = new Son();
    这个 son1 可以有它上面的链儿上的所有属性, 原型链的链接点就是 prototype
  • Object.prototype 是绝大多数对象的原型链的终端
    也就是说 : 绝大多数的对象最终都会继承自 Object.prototype

    所以 Object.prototype.__proto__ 的值为 null

    例外就是: Object.create(null) 创建的对象, 这样创建出来的对象的原型就是 null

  • Object.create(原型)

    • 它是一种更加灵活的创建对象的方法,你可以自己指定原型
    • var obj = {name: "Tracy"}
      var obj1 = Object.create(obj);
      这样 obj 就是 obj1 的原型了
    • var obj = Object.create(null) ;创建的对象没有原型
      那么打印 document.write(obj) 的时候系统就会报错
      因为这个 document.write 方法是把里面的东西给加一个 toString() 方法,
      就像这样 document.write(obj.toString())
      而 obj 没有原型 也就不继承 Object.Prototype.toString 方法,因此报错
    • Object.create(原型, 特性)
      后面的这个特性,可以设置成可枚举性,只读,读写之类的,以后讲
  • 原型链方法的重写:
    如果原型里也有一个方法,我们的子类里也写了相同的方法,那么这叫做 “方法的重写” 既: 我覆盖了你原来的 方法。
    Eg: Person.prototype = {
    toString : function(){return "重写了Object.prototye 里的 toString() 方法";}
    }

    function Person(){}
    var person1 = new Person()
    person1.toString();

    Object.prototype.toString = function(){return "哈哈";}
    var a = {};
    a.toString(); //此时返回 哈哈, 因为我们把最底层的 toString 方法给覆盖了
    var a = "字符串"
    a.toString();//此时返回正常结果,因为 a.toString == new String("aa").toString, 而 String 类里是有自己的 toString 方法的,还没有到 Object.prototype 里取方法那一步

    我们也可以很任性把全局的都给改了
    • Object.prototype.toString = function(){return "哈哈";}
    • String.prototype.toString = function(){return "哈哈";}
    • Number.prototype.toString = function(){return "哈哈";}
    • Boolean.prototype.toString = function(){return "哈哈";}
    • Array.prototype.toString = function(){return "哈哈";}
  • This

    • aa.action(); // action 方法里面的this : 谁调用的这个方法,this 就指向谁
      因此 Demo:

      Person.prototype = {
      name : "a",
      sayName : function(){console.log(this.name);}
      }

      function Person(){
      this.name = "b";
      }

      var person1 = new Person();
      person1.sayName(); //值为 b, this 值向的是 person1
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值