JavaScript - Objects

对象定义:

    let person = {
        name: {
            first: "Bob",
            last: "smith"
        },
        age: 32,
        gender: 'male',
        interests: ['music', 'skiing'],
        bio: function () {
            alert(this.name[0] + ' ' + this.name[1] + ' is ' + this.age + ' years old. He likes ' + this.interests[
                0] + ' and ' + this.interests[1] + '.');
        },
        greeting: function () {
            alert('Hi! I\'m ' + this.name[0] + '.');
        }
    };
/*
对象访问方式
person.name.first
person.name.last
person.age
person.interests[1]
person.bio()

person['age']
person['name']['first']
*/

更新对象成员:

// 更新对象现有成员的值
person.age = 45;
person['name']['last'] = 'Cratchit';

// 对象中加入新成员
person['eyes'] = 'hazel';
person.farewell = function() { alert("Bye everybody!"); }

let myDataName = 'height';
let myDataValue = '1.75m';
person[myDataName] = myDataValue;

对象中 'this' 关键字:

this 关键字代表当前对象的实体。

创建对象实体:

    function createNewPerson(name) {
        let obj = {};
        obj.name = name;
        obj.greeting = function () {
            alert("Hi! I\'m " + name + ".");
        };
        return obj;
    }
    let salva = createNewPerson("Salva");
    salva.name;
    salva.greeting();



// 類構造函數
function Person(first, last, age, gender, interests) {
  this.name = {
    'first': first,
    'last' : last
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
  this.bio = function() {
    alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
  };
  this.greeting = function() {
    alert('Hi! I\'m ' + this.name.first + '.');
  };
}
var person1 = new Person('Bob', 'Smith', 32, 'male', ['music', 'skiing']);
/*
person1['age']
person1.interests[1]
person1.bio()
// etc.
*/

其他创建对象实体的方式:

Object() 构造器

// 使用 Object() 构造器,创建一个空白的对象
var person1 = new Object();
// 之后给空白对象,加入属性和方法
person1.name = 'Chris';
person1['age'] = 38;
person1.greeting = function() {
  alert('Hi! I\'m ' + this.name + '.');
};



var person1 = new Object({
  name: 'Chris',
  age: 38,
  greeting: function() {
    alert('Hi! I\'m ' + this.name + '.');
  }
});

使用 JavaScript 内置的 create() 方法创建对象,该方法会基于已存在的对象,来创建另一个对象。被创建对象会拥有同所基于对象相同的属性和方法。

注意:IE8 不支持通过 create() 方法创建对象的方式。

var person2 = Object.create(person1);
/*
person2.name
person2.greeting()
*/

Object prototypes

更精确的说,属性和方法是定义在对象构造器函数中的,而不是在对象实例自身当中。__proto__ 是连接对象实例和原型蓝本之间的桥梁。__proto__ 派生自构造器的 prototype 属性。

注意:对象的原型(Object.getPrototypeOf(person3) 或者 obj.__proto__) 同 构造器函数 prototype 属性之间的区别,前者是各个对象实例的属性,后者是构造器的属性。

person1.valueOf()
/*
valueOf() 继承自 Object
Object 是 Person 的原型类
*/

Object.create()

var person2 = Object.create(person1);
person2.__proto__
/*
返回值是 person1
因为创建 person2 的原型类就是 person1
*/

Constructor property

构造器属性,指向原始的构造器方法。

person1.constructor
person2.constructor

var person3 = new person1.constructor('Karen', 'Stephenson', 26, 'female', ['playing drums', 'mountain climbing']);
/*
person3.name.first
person3.age
person3.bio()
*/

// 取得构造器名称
instanceName.constructor.name
person1.constructor.name

变更原型蓝本

function Person(first, last, age, gender, interests) {

  // property and method definitions

}

var person1 = new Person('Tammi', 'Smith', 32, 'neutral', ['music', 'skiing', 'kickboxing']);

// 向原型中加入新方法
Person.prototype.farewell = function() {
  alert(this.name.first + ' has left the building. Bye for now!');
};

Inheritance 继承

Prototype inheritance

function Person(first, last, age, gender, interests) {
  this.name = {
    first,
    last
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
};

Person.prototype.greeting = function() {
  alert('Hi! I\'m ' + this.name.first + '.');
};

// 声明子类
function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}
/*
结果类似如此
function Teacher(first, last, age, gender, interests, subject) {
  this.name = {
    first,
    last
  };
  this.age = age;
  this.gender = gender;
  this.interests = interests;
  this.subject = subject;
}
*/

// 无参数构造器继承
function Brick() {
  this.width = 10;
  this.height = 20;
}

function BlueGlassBrick() {
  Brick.call(this);

  this.opacity = 0.5;
  this.color = 'blue';
}

设定继承类的蓝本和构造器参考

        // Person 對象構造器
        function Person(first, last, age, gender, interests) {
            this.name = {
                first,
                last
            };
            this.age = age;
            this.gender = gender;
            this.interests = interests;
        };
        // 向 Person 構造器藍本中加入方法
        Person.prototype.greeting = function () {
            alert("Hi! I\'m " + this.name.first + ".");
        };

        // Teacher 對象構造器,部分屬性繼承自 Person
        function Teacher(first, last, age, gender, interests, subject) {
            Person.call(this, first, last, age, gender, interests);
            // this 指該該方法被調用時,調用者自身
            this.subject = subject; // Teacher 對象擁有的新屬性
        }

如以上方式的定义,Teacher 原始蓝本属性中没有 greeting,以上的继承方式,只能继承基准构造器蓝本中定义的属性和方法。

Object.getOwnPropertyNames(Teacher.prototype)
// 返回值:["constructor"]

Object.getOwnPropertyNames(Person.prototype)
// 返回值:["constructor", "greeting"]

执行此语句加入 Person 中的 greeting 方法

Teacher.prototype = Object.create(Person.prototype);
// 此时 Teacher.prototype.constructor 就为 Person 的构造器
// 使用下方语句,以指定其构造器为 Teacher
Teacher.prototype.constructor = Teacher;

此时,Teacher 蓝本中也包含 greeting 方法了,但是通过 Object.getOwnPropertyNames(Teacher.prototype) 的返回值会变为空白数组,需要使用以下代码修复

        Object.defineProperty(Teacher.prototype, 'constructor', {
            value: Teacher,
            enumerable: false, // so that it does not appear in 'for in' loop
            writable: true
        });

定义继承类中的新方法

        // 定義繼承類的新方法
        Teacher.prototype.greeting = function () {
            var prefix;

            if (this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
                prefix = 'Mr.';
            } else if (this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender ===
                'F') {
                prefix = 'Mrs.';
            } else {
                prefix = 'Mx.';
            }

            alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
        };

定义新的继承类 Student

        // Student 對象構造器,全部屬性都繼承自 Person
        function Student(first, last, age, gender, interests) {
            Person.call(this, first, last, age, gender, interests);
        }
        Student.prototype = Object.create(Person.prototype);
        Student.prototype.constructor = Student;
        Student.prototype.greeting = function () {
            alert("Yo! I\'m " + this.name.first + ".");
        };
        let student1 = new Student('Liz', 'Sheppard', 17, 'female', ['ninjitsu', 'air cadets']);

ECMAScript 2015 Classes

Internet Explorer 对此支持很欠缺

        class Person {
            constructor(first, last, age, gender, interests) {
                this.name = {
                    first,
                    last
                };
                this.age = age;
                this.gender = gender;
                this.interests = interests;
            }

            greeting() {
                console.log(`Hi! I'm ${this.name.first}`);
            };

            farewell() {
                console.log(`${this.name.first} has left the building. Bye for now!`);
            };
        }

使用 class 关键字,定义类;constrcutor() 方法定义构造器;greeting() farewell() 为此类的方法,注意方法定义末尾的分号【;

使用 new 关键字,创建类,并且调用该类的方法。

        let han = new Person('Han', 'Solo', 25, 'male', ['Smuggling']);
        han.greeting();
        // Hi! I'm Han

        let leia = new Person('Leia', 'Organa', 19, 'female', ['Government']);
        leia.farewell();
        // Leia has left the building. Bye for now

定义继承类

        // 基於 Person 的子類 Teacher
        console.log("Subclass Teacher");
        // class Teacher extends Person {
        //     constructor(first, last, age, gender, interests, subject, grade) {
        //         this.name = {
        //             first,
        //             last
        //         };
        //         this.age = age;
        //         this.gender = gender;
        //         this.interests = interests;
        //         // subject and grade are specific to Teacher
        //         this.subject = subject;
        //         this.grade = grade;
        //     }
        // }
        class Teacher extends Person {
            constructor(first, last, age, gender, interests, subject, grade) {
                super(first, last, age, gender, interests); // 使用 super 關鍵字,調用父類的構造函數,初始化變量
                // subject and grade are specific to Teacher
                this.subject = subject;
                this.grade = grade;
            }
        }
        let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5);
        snape.greeting(); // Hi! I'm Severus.
        snape.farewell(); // Severus has left the building. Bye for now.
        console.log(snape.age); // 58
        console.log(snape.subject); // Dark arts

使用 extends 指明子类的父类;在子类构造函数中,使用 super() 方法,调用父类的构造函数,初始化子类继承自父类的属性。

Getters and Setters

        class Teacher extends Person {
            constructor(first, last, age, gender, interests, subject, grade) {
                super(first, last, age, gender, interests); // 使用 super 關鍵字,調用父類的構造函數,初始化變量
                // subject and grade are specific to Teacher
                this._subject = subject;
                this.grade = grade;
            }

            get subject() {
                return this._subject;
            }

            set subject(newSubject) {
                this._subject = newSubject;
            }
        }
        let snape = new Teacher('Severus', 'Snape', 58, 'male', ['Potions'], 'Dark arts', 5);
        snape.greeting(); // Hi! I'm Severus.
        snape.farewell(); // Severus has left the building. Bye for now.
        console.log(snape.age); // 58
        console.log(snape.subject); // Dark arts
        snape.subject = "Balloon animals"; // Change the subject
        console.log(snape.subject); // Balloon animals

在属性名称前使用 _ 来分离属性名称的定义,若没有此符号,那么在每次调用 get set 方法时,都会报错。

JSON - JavaScript Object Notation

JSON 结构

        let superHeroes = {
            "squadName": "Super hero squad",
            "homeTown": "Metro City",
            "formed": 2016,
            "secretBase": "Super tower",
            "active": true,
            "members": [{
                    "name": "Molecule Man",
                    "age": 29,
                    "secretIdentity": "Dan Jukes",
                    "powers": [
                        "Radiation resistance",
                        "Turning tiny",
                        "Radiation blast"
                    ]
                },
                {
                    "name": "Madame Uppercut",
                    "age": 39,
                    "secretIdentity": "Jane Wilson",
                    "powers": [
                        "Million tonne punch",
                        "Damage resistance",
                        "Superhuman reflexes"
                    ]
                },
                {
                    "name": "Eternal Flame",
                    "age": 1000000,
                    "secretIdentity": "Unknown",
                    "powers": [
                        "Immortality",
                        "Heat Immunity",
                        "Inferno",
                        "Teleportation",
                        "Interdimensional travel"
                    ]
                }
            ]
        }

若在程式中载入,可以如此访问

superHeroes.homeTown // "Metro City"

superHeroes["active"] // true

superHeroes['members'][1]['powers'][2] // "Superhuman reflexes"

数组样式的 JSON 也是格式正确的

[
  {
    "name": "Molecule Man",
    "age": 29,
    "secretIdentity": "Dan Jukes",
    "powers": [
      "Radiation resistance",
      "Turning tiny",
      "Radiation blast"
    ]
  },
  {
    "name": "Madame Uppercut",
    "age": 39,
    "secretIdentity": "Jane Wilson",
    "powers": [
      "Million tonne punch",
      "Damage resistance",
      "Superhuman reflexes"
    ]
  }
]
  • JSON 只是一种纯粹的数据格式,只包含属性,其中没有方法。
  • JSON 中的属性名称、string 类型的属性值,需要用双引号包裹,若用单引号包裹是错误的。

示例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Our superheroes</title>
    <link href="https://fonts.googleapis.com/css?family=Faster+One" rel="stylesheet">
    <link rel="stylesheet" href="./heroes.css">
</head>

<body>

    <header>
    </header>

    <section>
    </section>

    <script>
        let header = document.querySelector('header');
        let section = document.querySelector('section');

        let requestURL = "https://mdn.github.io/learning-area/javascript/oojs/json/superheroes.json";
        let request = new XMLHttpRequest();
        request.open("GET", requestURL); // 開啟請求
        request.responseType = "json";
        request.send();
        request.onload = function () {
            let superHeroes = request.response;
            populateHeader(superHeroes);
            showHeroes(superHeroes);
        };

        function populateHeader(jsonObj) {
            let myH1 = document.createElement("h1");
            myH1.textContent = jsonObj["squadName"];
            header.appendChild(myH1);

            let myPara = document.createElement("p");
            myPara.textContent = "Hometown: " + jsonObj["homeTown"];
            header.appendChild(myPara);
        }

        function showHeroes(jsonObj) {
            let heroes = jsonObj["members"];

            for (let i = 0; i < heroes.length; i++) {
                let myArtical = document.createElement("article");
                let myH2 = document.createElement("h2");
                let myPara1 = document.createElement("p");
                let myPara2 = document.createElement("p");
                let myPara3 = document.createElement("p");
                let myList = document.createElement("ul");

                myH2.textContent = heroes[i].name;
                myPara1.textContent = "Secret identity: " + heroes[i].secretIdentity;
                myPara2.textContent = "Age: " + heroes[i].age;
                myPara3.textContent = "Superpower:";

                let superPowers = heroes[i].powers;
                for (let j = 0; j < superPowers.length; j++) {
                    let listItem = document.createElement("li");
                    listItem.textContent = superPowers[j];
                    myList.appendChild(listItem);
                }

                myArtical.appendChild(myH2);
                myArtical.appendChild(myPara1);
                myArtical.appendChild(myPara2);
                myArtical.appendChild(myPara3);
                myArtical.appendChild(myList);

                section.appendChild(myArtical);
            }
        }
    </script>
</body>

</html>
html {
    font-family: 'helvetica neue', helvetica, arial, sans-serif;
}

body {
    width: 800px;
    margin: 0 auto;
}

h1,
h2 {
    font-family: 'Faster One', cursive;
}

/* header styles */

h1 {
    font-size: 4rem;
    text-align: center;
}

header p {
    font-size: 1.3rem;
    font-weight: bold;
    text-align: center;
}

/* section styles */

section article {
    width: 33%;
    float: left;
}

section p {
    margin: 5px 0;
}

section ul {
    margin-top: 0;
}

h2 {
    font-size: 2.5rem;
    letter-spacing: -5px;
    margin-bottom: 10px;
}

对象和文本之间的转换

request.responseType = 'json';
/*
使用这个设置,使 XHR 请求直接将 JSON 响应,转换为 JavaScript 对象
*/

parse() 使用此方法,将对应的 JSON 文本,转换为对应的 JavaScript 对象。

request.open('GET', requestURL);
request.responseType = 'text'; // now we're getting a string!
request.send();

request.onload = function() {
  var superHeroesText = request.response; // get the string from the response
  var superHeroes = JSON.parse(superHeroesText); // convert it to an object
  populateHeader(superHeroes);
  showHeroes(superHeroes);
}

stringify() 使用此方法,将对应的 JavaScript 对象,转换为 JSON 字符串。

var myJSON = { "name": "Chris", "age": "38" };
// myJSON
// {name: "Chris", age: "38"}
var myString = JSON.stringify(myJSON);
// myString
// "{"name":"Chris","age":"38"}"

弹跳球示例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <title>Bouncing balls</title>
    <link rel="stylesheet" href="./bounceBall.css">
</head>

<body>
    <h1>Bouncing Balls</h1>
    <p>Ball count: </p>
    <canvas></canvas>

    <script src="./bounceBall.js"></script>
</body>

</html>
html,
body {
    margin: 0;
}

html {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
    height: 100%;
}

body {
    overflow: hidden;
    height: inherit;
}

h1 {
    font-size: 2rem;
    letter-spacing: -1px;
    position: absolute;
    margin: 0;
    top: -4px;
    right: 5px;
    color: transparent;
    text-shadow: 0 0 4px white;
}

p {
    position: absolute;
    margin: 0;
    top: 35px;
    right: 5px;
    color: #aaa;
}
let para = document.querySelector('p');
let count = 0;

// 設置畫布
let canvas = document.querySelector('canvas'); // 取得畫布參考
let ctx = canvas.getContext('2d'); // 獲得可用於繪製的上下文

let width = canvas.width = window.innerWidth;
let height = canvas.height = window.innerHeight;

// 生成隨機數
function random(min, max) {
    let num = Math.floor(Math.random() * (max - min)) + min;
    return num;
}

function Shape(x, y, velX, velY, exists) {
    this.x = x; // X 坐標
    this.y = y; // Y 坐標
    this.velX = velX; // 水平速率
    this.velY = velY; // 垂直速率
    this.exists = exists;
}

// 圓球構造函數
function Ball(x, y, velX, velY, exists, color, size) {
    // this.x = x; // X 坐標
    // this.y = y; // Y 坐標
    // this.velX = velX; // 水平速率
    // this.velY = velY; // 垂直速率
    // this.color = color; // 顏色
    // this.size = size; // 尺寸,圓球的半徑
    Shape.call(this, x, y, velX, velY, exists);

    this.color = color; // 顏色
    this.size = size; // 尺寸,圓球的半徑
}
Ball.prototype = Object.create(Shape.prototype);
Ball.prototype.constructor = Ball;

// 繪製圓球
Ball.prototype.draw = function () {
    ctx.beginPath(); // 開始向畫布繪製圖形
    ctx.fillStyle = this.color; // 繪製圖形的顏色
    // 參數1、2:圖形中心位置坐標;參數3:圖形半徑;參數4、參數5:圖形開始-結束角度
    ctx.arc(this.x, this.y, this.size, 0, (2 * Math.PI));
    ctx.fill(); // 填充圓弧圖形
};

// 更新圓球位置
Ball.prototype.update = function () {
    if ((this.x + this.size) >= width) {
        this.velX = -(this.velX);
    }

    if ((this.x - this.size) <= 0) {
        this.velX = -(this.velX);
    }

    if ((this.y + this.size) >= height) {
        this.velY = -(this.velY);
    }

    if ((this.y - this.size) <= 0) {
        this.velY = -(this.velY);
    }

    this.x += this.velX;
    this.y += this.velY;
};

// 圓球碰撞檢測
Ball.prototype.collisionDetect = function () {
    for (let index = 0; index < balls.length; index++) {
        if (!(this === balls[index])) {
            let dx = this.x - (balls[index]).x;
            let dy = this.y - (balls[index]).y;
            let distance = Math.sqrt((dx * dx) + (dy * dy));
            if (distance < (this.size + (balls[index]).size)) {
                (balls[index]).color = this.color = "rgb(" + random(0, 255) + "," + random(0, 255) + "," + random(0, 255) + ")";
            }
        }
    }
};

// 吃掉圓球
function EvilCircle(x, y, exists) {
    Shape.call(this, x, y, 20, 20, exists);

    this.color = "white";
    this.size = 10;
}
EvilCircle.prototype = Object.create(Shape.prototype);
EvilCircle.prototype.constructor = EvilCircle;

EvilCircle.prototype.draw = function () {
    ctx.beginPath();
    ctx.strokeStyle = this.color;
    ctx.lineWidth = 3;
    ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
    ctx.stroke();
};

EvilCircle.prototype.checkBounds = function () {
    if ((this.x + this.size) >= width) {
        this.x -= this.size;
    }

    if ((this.x - this.size) <= 0) {
        this.x += this.size;
    }

    if ((this.y + this.size) >= height) {
        this.y -= this.size;
    }

    if ((this.y - this.size) <= 0) {
        this.y += this.size;
    }
};

EvilCircle.prototype.setControls = function () {
    let _this = this;
    window.onkeydown = function (e) {
        if (e.keyCode === 65) { // a
            _this.x -= _this.velX;
        } else if (e.keyCode === 68) { // d
            _this.x += _this.velX;
        } else if (e.keyCode === 87) { // w
            _this.y -= _this.velY;
        } else if (e.keyCode === 83) { // s
            _this.y += _this.velY;
        }
    };
};

EvilCircle.prototype.collisionDetect = function () {
    for (let j = 0; j < balls.length; j++) {
        if (balls[j].exists) {
            let dx = this.x - balls[j].x;
            let dy = this.y - balls[j].y;
            let distance = Math.sqrt((dx * dx) + (dy * dy));

            if (distance < this.size + balls[j].size) {
                balls[j].exists = false;
                count--;
                para.textContent = 'Ball count: ' + count;
            }
        }
    }
};

let balls = [];

let evil = new EvilCircle(random(0, width), random(0, height), true);
evil.setControls();

function loop() {
    // 繪製黑色背景矩形畫布
    ctx.fillStyle = "rgba(0,0,0,0.25)";
    ctx.fillRect(0, 0, width, height);

    while (balls.length < 50) {
        let size = random(10, 20);
        let ball = new Ball(
            // ball position always drawn at least one ball width
            // away from the edge of the canvas, to avoid drawing errors
            random(0 + size, width - size),
            random(0 + size, height - size),
            random(-7, 7),
            random(-7, 7),
            true,
            'rgb(' + random(0, 255) + ',' + random(0, 255) + ',' + random(0, 255) + ')',
            size
        );
        balls.push(ball);

        count++;
        para.textContent = "Ball count: " + count;
    }

    for (let index = 0; index < balls.length; index++) {
        if ((balls[index]).exists) {
            (balls[index]).draw();
            (balls[index]).update();
            (balls[index]).collisionDetect();
        }
    }

    evil.draw();
    evil.checkBounds();
    evil.collisionDetect();

    requestAnimationFrame(loop);
}

loop();

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值