Chapter 16. JavaScript Objects
JavaScriptはprototypal inheritanceを元にした言語。
クラスベースとは違い、最初にクラスを作ることを心配しなくて良い。
オブジェクトは再利用性が高い。
クラスベースとは違い、最初にクラスを作ることを心配しなくて良い。
オブジェクトは再利用性が高い。
■16.1 Defining a Basic JavaScript Object
newとthisキーワードについて。オブジェクトの初期化(構築)を行う関数をコンストラクタ関数。
コンストラクタ関数にあるthisはインスタンス(実体)を示す。
// コンストラクタ関数
function Tune (song, artist) {
this.title = song;
this.artist = artist;
this.concat=function() {
return this.title + "-" + this.artist;
}
}
window.onload=function() {
var happySong = new Tune("Putting on the Ritz", "Ella Fitzgerald");
// print out title and artist
alert(happySong.concat());
}
コンストラクタをnewした時、thisは空のオブジェクト{}を示すので。var happySong = new Tune("Putting on the Ritz", "Ella Fitzgerald");は以下のような感じになる。
var happySong = {
title : song,
artist : artist,
concat : function() {
return this.title + "-" + this.artist;
}
}
newを付けないでTuneを呼んだ場合は、コンストラクタ内のthisはwindowを示すので、windowにメソッドやプロパティが追加されてしまう。
// treating Tune like a function
Tune("the title", "the singer");
alert(window.concat()); // lo and behold,
// "the title the singer" prints out
これのthisが示すものをもっとわかりやすくするとwindow.Tuneを呼び出してるので、thisが示すインスタンスはwindowとなっている。
window.Tune("the title", "the singer");
alert(window.concat());
■16.3 Expanding Objects with prototype
prototypeの追加方法■16.4 Adding Getter/Setter to Objects
getterとsetterの使い方
function Tune() {
var artist;
var song;
this.__defineGetter__("artist", function() {
return artist
});
this.__defineSetter__("artist", function(val) {
artist = "By: " + val
});
this.__defineGetter__("song", function() {
return "Song: " + song
});
this.__defineSetter__("song", function(val) {
song = val
});
}
window.onload = function() {
var happySong = new Tune();
happySong.artist = "Ella Fitzgerald";
happySong.song = "Putting on the Ritz";
alert(happySong.song + " " + happySong.artist);// Song: Putting on the Ritz By: Ella Fitzgerald
}c
■16.5 Inheriting an Object’s Functionality
constructor chainingについて。(正直この継承は手順が複雑すぎるので使いにくい
function oldObject(param1) {
this.param1 = param1;
this.getParam=function() {
return this.param1;
}
}
function newObject(param1,param2) {
this.param2 = param2;
this.getParam2 = function() {
return this.param2;
}
oldObject.apply(this,arguments);// oldに引数を渡して実行
// thisのコンテキストはparam2と同じになる
/* ここにoldObjectを書くのと大体同じ
this.param1 = param1;
this.getParam=function() {
return this.param1;
}
*/
this.getAllParameters=function() {
return this.getParam() + " " + this.getParam2();
}
}
newObject.prototype = new oldObject();// 引数はない
var obj = new newObject("value1","value2");// 一度にまとめて引数を渡したい
// prints out both parameters
alert(obj.getAllParameters());
■16.6 Extending an Object by efining a New Property
*こんなとこを読むなら、ES5, Property Descriptor解説 - 枕を欹てて聴くを読みましょう。コンストラクタ関数を変更しないで、新しいプロパティを追加するには
Object.definePropertyを使う。(ECMAScript 5)
まあ普通にドット演算子でプロパティ作ってやることもできますが、definePropertyはプロパティの性質(ここではPropertyDescriptorとしておきます)についても決定できる。
someObject.newProperty = "somevalue";definePropertyの場合
Object.defineProperties(newBook, {
"stock": {
value: true,
writable: true,
enumerable: true,
},
"age": {
value: "13 and up",
writable: false
}
});
PropertyDescriptor- writable
- configurable
falseだとプロパティは削除できなくて、PropertyDescriptor
writable, enumerable, configurable の値を変更できない(プロパティ値の変更はできる)
=>ECMA3 の DontDelete
- enumerable
また、defineProperty内でgetterやsetterを決めたときはwritableの設定をすることができません。
Object.defineProperty(TechBook, "category", {
get: function () { return category; },
set: function (value) { category = value; },
value: "O'Reilly",//デフォルトの値
enumerable: true,
configurable: true});
var newBook = new TechBook(...);
newBook.publisher="O'Reilly";
設定されているenumerableなどのPropertyDescriptorの情報は Object.getOwnPropertyDescription を使う事で取得できます。
var propDesc = Object.getOwnPropertyDescriptor(newBook,"category");
alert(JSON.stringify(val)); // {"enumerable":true,"configurable":true}
- ECMA-262 » ECMA-262-5 in detail. Chapter 1. Properties and Property Descriptors.
- ECMAScript 5の"Object" - JavaScriptで遊ぶよ - g:javascript
■16.7 Enumerating an Object’s Properties
オブジェクトがどんなプロパティを持っているか知りたい。今まではfor...inループを使ってたりしたけど、ECMA5ではObject.keysというメソッドが存在する。
alert(Object.keys(obj).join(", "));
// for ( var prop in obj ) if ( obj.hasOwnProperty( prop ) ) と似たような感じで
getOwnPropertyNamesというメソッドはObject.keysと似ているが、本来なら列挙されないプロパティ(配列のlengthなど)も取得できる。var props = Object.getOwnPropertyNames(obj);
■16.8 Preventing Object Extensibility
ECMA5にはObject.preventExtensionsというオブジェクトの拡張をロックするメソッドがある。つまりオブジェクトに新しいプロパティやメソッドを追加させなくさせるメソッド
"use strict";
var Test = {
value1 : "one",
value2 : function() {
return this.value1;
}
};
try {
Object.preventExtensions(Test);
// the following fails, and throws an exception in Strict mode
Test.value3 = "test";
} catch(e) {
alert(e);
}
既にロックされているかは Object.isExtensibleメソッドで確認できる。
if (Object.isExtensible(obj)) {
// extend the object
}
(Strict modeどうなるんですかねー■16.9 Preventing Object Additions and Changes to Property Descriptors
Object.preventExtensionsは新たに追加するのを防止するメソッドだったが、PropertyDescriptorの変更をできなくさせるメソッドがObject.sealである。Object.preventExtensions + configurable:false
"use strict";
var Test = {
value1 : "one",
value2 : function() {
return this.value1;
}
}
try {
// オブジェクトをfreezeする
Object.seal(Test);
// プロパティは変更できる
Test.value2 = "two";
// 追加はできない。 throw an error in Strict Mode
Test.newProp = "value3";
// PropertyDescriptorはへんこうできない
Object.defineProperty(Title, "category", {
get: function () { return category; },
set: function (value) { category = value; },
enumerable: true,
configurable: true});
} catch(e) {
alert(e);
}
同じようにif (Object.isSealed(obj)) で既に適応されてるかを判定できる。ECMA3.1の[[Flexible]]はECMA5だと[[configurable]]?
■16.10 Preventing Any Changes to an Object
プロパティの追加、変更、削除、PropertyDescriptorの変更などすべてできなくさせるにはObject.freezeメソッドを使う。
"use strict";
var Test = {
value1 : "one",
value2 : function() {
return this.value1;
}
}
try {
// freeze the object
Object.freeze(Test);
// さっきとは違いここでもエラーになる。変更も不可
Test.value2 = "two";
// so would the following
Test.newProperty = "value";
// and so would the following
Object.defineProperty(Title, "category", {
get: function () { return category; },
set: function (value) { category = value; },
enumerable: true,
configurable: true});
} catch(e) {
alert(e);
}
freezeするとno additions,no changes to existing propertiesになる。if (Object.isFrozen(obj)) ...で確認。
- つまり、Object.seal()、Object.freeze()、Object.preventExtensions() は Object.defineProperty() の糖衣構文 (syntax sugar) だったのだ。そりゃ、機能が制限されていて当然である。
- http://end-of-file.net/blog/2008-08.html#date-2008-08-21
■16.11 One-Off Objects and Namespacing Your JavaScript
ネームスペースを設けて衝突を防ぐ
var jQuery = {
//プロパティとかメソッドとか
}
みたいな話です。グローバルなものは一つか二つぐらいにするってやつ。
■16.12 Rediscovering “this” with Prototype.bind
ECMAScript 5にはFunctionオブジェクトにbindというメソッドがあり、thisを設定できる。
window.name = "window";
var newObject = {
name: "object",
sayGreeting: function() {
alert("Now this is easy, " + this.name);
nestedGreeting = function(greeting) {
alert(greeting + " " + this.name);
}.bind(this);
nestedGreeting("hello");
}
}
newObject.sayGreeting("hello");
// 今まではprototype.jsのようにprottotype拡張してた
Function.prototype.bind = function(scope) {
var _function = this;
return function() {
return _function.apply(scope, arguments);
}
}
特にsetTImeoutとかの時にスコープを設定するのに使う事多い。■16.13 Chaining Your Object’s Methods
メソッドチェーンについて。メソッドチェーンするにはthisを返すのが定説。
function Book(title, author) {
var title = title;
var author = author;
this.getTitle = function() {
return "Title: " + title;
}
this.getAuthor = function() {
return "Author: " + author;
}
this.replaceTitle = function(newTitle) {
var oldTitle = title;
title = newTitle;
}
this.replaceAuthor = function(newAuthor) {
var oldAuthor = author;
author = newAuthor;
}
}
function TechBook(title, author, category) {
var category = category;
this.getCategory = function() {
return "Technical Category: " + category;
}
Book.apply(this, arguments);
this.changeAuthor = function(newAuthor) {
this.replaceAuthor(newAuthor);
return this;// ここでthisを返してる
}
}
window.onload = function() {
try {
var newBook = new TechBook("I Know Things", "Shelley Powers", "tech");
alert(newBook.changeAuthor("Book K. Reader").getAuthor());//changeAuthorではnewBookが返るのでチェーンできる
} catch (e) {
alert(e.message);
}
}
メソッドチェーンはコード量が減ったり、まとめて処理を行えるので便利だけどデバッグがしににくなったり読むのに慣れが必要。
短く書き捨てる場合はメソッドチェーンのメリットは光ますが、メソッドチェーンはデバッグを難しくします。 「数分でbugfixしなければ殺される」風味な状況で「メソッドチェーンの部分がネックでデバッグが進まない」という悲惨な状況に10年前遭遇したことがあります。
Twitter / uupaa: 短く書き捨てる場合はメソッドチェーンのメリットは光ま ...
ブラウザ間でちゃんと互換性があれば、かなりかたーいものも書けるようになるはずなんですよね。まだ未実装のブラウザの方が多い話。
コメント(0件)
- TB-URL http://efcl.info/adiary/078/tb/