再学javascript高级程序设计之对象

javascript红宝书关于对象、类与面向对象编程的重点230~290的重点知识

对象的声明方式

//第一种方法
var person = new Object();
person.name = "Gaofeng";
person.age = 23;
person.job = "web fronter";
person.sayName = function () {
  console.log(this.name);
};
//第二种方法
let person = {
  name: "gaofeng",
  age: 23,
  sayName() {
    console.log(this.name);
  },
};

//第三种申明属性的方法
let person1 = {};

Object.defineProperty(person1, "name", {
  configurable: true, //表示属性是否可以通过 delete 删除并重新定义
  writable: true, //表示属性的值是否可以被修改
  enumerable: true, //标示属性是否可以枚举列出
  value: "Nicholas", //包含属性实际的值。
});
console.log(person1.name);
person1.name = "nelsen";
console.log(person1.name);

工厂模式

抽象创建特定对象的方法,这种工厂模式虽然可以解决创建多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)。

function createPerson(name, age, job) {
  let o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function () {
    console.log(this.name);
  };

  return o;
}

let p1 = createPerson("zhangsan", 23, "tester");
p1.sayName();
let p2 = createPerson("lisi", 24, "fronter");
p2.sayName();
//zhangsan
//lisi

构造函数模式

特点:
函数名大写了
没有显示创建一个对象
属性和方法直接赋值给了this
没有返回值return

function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    console.log(this.name);
  };
}
let p1 = new Person("zh", 23, "tester");
let p2 = new Person("lisi", 25, "fronter");

p1.sayName();
p2.sayName();
/* zh
 * lisi 
*/

//这两个对象都有一个constructor 属性指向 Person
console.log(p1.constructor == Person); // true
console.log(p2.constructor == Person);  // true

new一个构造函数的时候,主要执行了一下几步

  1. 隐式的创建了一个新对象
  2. 新对象的prototype属性指向了构造函数的prototype属性
  3. 构造函数内部的this被赋值为新对象的this
  4. 执行构造函数内部的代码,即为新对象添加属性和方法
  5. 如果构造函数返回非空对象,则返回这个对象,否则返回新创建的对象

构造函数不一样要写成函数声明的方式,函数表达式也是可以的

let Person = function (name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    console.log(this.name);
  };
}

构造函数的问题,是构造函数内部定义的方法啊,会在每个实例上创建一遍,这是一种浪费!前面的p1和p2来说,sayName方法是两个不同的方法。
因为做的是同一件事情,所以没必要创建两个不同的方法

let Person = function (name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = sayName
}

function sayName(){
  console.log(this.name);
}
let p1 = new Person("zh", 23, "tester");
let p2 = new Person("lisi", 25, "fronter");

p1.sayName();
p2.sayName();

此时的p1.sayName和p2.sayName就是引用了全局的sayName,
但是其封装性也就没有了,一个方法还好,但是实际业务中会有很多方法,这样看起来就会很散乱!

原型模式

每个函数创建的时候,都会默认的带上一个prototype属性,包含了实例的属性方法。好处是在prototype上面创建的属性和方法会被所以实例共享,原来在构造函数内部赋值的属性和方法现在可以赋值在原型prototype上面

function Animal() {}
Animal.prototype.name = "duck";
Animal.prototype.eat = function () {
  return "fish";
};
```js
function Person(name, age, job) {
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function () {
    console.log(this.name);
  };
}
let p1 = new Person("zh", 23, "tester");
let p2 = new Person("lisi", 25, "fronter");

p1.sayName();
p2.sayName();
/* zh
lisi */

function Animal() {}
Animal.prototype.name = "duck";
Animal.prototype.eat = function () {
  return "fish";
};

let a1 = new Animal();
console.log(a1.name);
console.log(a1.eat());
let a2 = new Animal();
console.log(a2.name);
console.log(a2.eat());
/* 
duck
fish
duck
fish
*/

可以看到创建的两个实例属性,返回的是一模一样的结果!

在对象中实现get/set定义对象的属性

		//get/set访问器属性
        let obj = {
            name: "gaofeng",
            _age: 23 // _私有属性的标志
        }
        Object.defineProperty(obj, 'age', {
            get() {
                return this._age
            },
            set(newValue) {
                this._age = newValue;
                this.name += " " + this._age - 3
            }
        })
        obj.age = 30
        console.log(obj.age);
        console.log(obj.name); 

实例与构造函数之间的关系,如下:

		function Person(name) {
            this.name = name
        }
        let p1 = new Person()
        //chrome浏览器中

        console.log(Person.prototype, 'Person');
        /*
               {
                constructor: ƒ Person(name),
                [[Prototype]]: Object
               }
            */

        console.log(p1.__proto__, 'p1')

        /* 
          {
              constructor: ƒ Person(name),
              [[Prototype]]: Object
          }
               
        */
        console.log(Person.prototype.constructor == Person)
        console.log(Person.prototype.__proto__.constructor == Object)
        console.log(Person.prototype.__proto__.__proto__ == null)
        console.log(Person.prototype.__proto__, 'Person.prototype.__proto__')
        /* 
          
        {
            constructor: ƒ Object(),
            hasOwnProperty: ƒ hasOwnProperty(),
            isPrototypeOf: ƒ isPrototypeOf()
        }
        
        */

        //实例与构造函数没有关系,实例与构造函数原型对象有关系
        console.log(p1.__proto__ == Person.prototype, '__proto__')
        console.log(p1.__proto__.constructor === Person, 'constructor')
        /*
            true "__proto__"
            demo2.html:69 true "constructor"
        */

下图很清晰额展示了这种关系
在这里插入图片描述

通过对象访问属性时,会按照这个属性的名称开始搜索。搜索开始于对象实例本身。如果在这个 实例上发现了给定的名称,则返回该名称对应的值。如果没有找到这个属性,则搜索会沿着指针进入原型对象,然后在原型对象上找到属性后,再返回对应的值。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值