參考答案:主要有構造函數原型和對象建立兩種方法。原型法是通用老方法,對象建立是ES5推薦使用的方法.目前來看,原型法更廣泛.javascript
代碼演示
1) 構造函數方法定義類java
function Person(){
this.name = 'michaelqin';
}
Person.prototype.sayName = function(){
alert(this.name);
}
var person = new Person();
person.sayName();
2) 對象建立方法定義類設計模式
var Person = { name: 'michaelqin', sayName: function(){ alert(this.name); } }; var person = Object.create(Person); person.sayName();
參考答案:原型鏈法,屬性複製法和構造器應用法. 另外,因爲每一個對象能夠是一個類,這些方法也能夠用於對象類的繼承.數組
代碼演示
1) 原型鏈法閉包
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function(){
alert(this.name);
};
function Person() {}
Person.prototype = Animal.prototype; // 人繼承自動物
Person.prototype.constructor = 'Person'; // 更新構造函數爲人
2) 屬性複製法app
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function() {
alert(this.name);
};
function Person() {}
for(prop in Animal.prototype) {
Person.prototype[prop] = Animal.prototype[prop];
} // 複製動物的全部屬性到人量邊
Person.prototype.constructor = 'Person'; // 更新構造函數爲人
3) 構造器應用法ide
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function() {
alert(this.name);
};
function Person() {
Animal.call(this); // apply, call, bind方法均可以.細微區別,後面會提到.
}
參考答案:就是類繼承裏邊的屬性複製法來實現.由於當全部父類的prototype屬性被複制後,子類天然擁有相似行爲和屬性.函數
參考答案:大多數語言裏邊都是塊做做用域,以{}進行限定,js裏邊不是.js裏邊叫函數做用域,就是一個變量在全函數裏有效.好比有個變量p1在函數最後一行定義,第一行也有效,可是值是undefined.this
代碼演示spa
var globalVar = 'global var';
function test() {
alert(globalVar); // undefined, 由於globalVar在本函數內被重定義了,致使全局失效,這裏使用函數內的變量值,但是此時還沒定義
var globalVar = 'overrided var'; // globalVar在本函數內被重定義
alert(globalVar); // overrided var
}
alert(globalVar); // global var,使用全局變量
參考答案: this指的是對象自己,而不是構造函數.
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var person1 = new Person();
person1.name = 'michaelqin';
person1.sayName(); // michaelqin
參考答案:三者均可以把一個函數應用到其餘對象上,注意不是自身對象.apply,call是直接執行函數調用,bind是綁定,執行須要再次調用.apply和call的區別是apply接受數組做爲參數,而call是接受逗號分隔的無限多個參數列表,
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var obj = {name: 'michaelqin'}; // 注意這是一個普通對象,它不是Person的實例
1) apply
Person.prototype.sayName.apply(obj, [param1, param2, param3]);
2) call
Person.prototype.sayName.call(obj, param1, param2, param3);
3) bind
var sn = Person.prototype.sayName.bind(obj);
sn([param1, param2, param3]); // bind須要先綁定,再執行
sn(param1, param2, param3); // bind須要先綁定,再執行
參考答案: caller,callee之間的關係就像是employer和employee之間的關係,就是調用與被調用的關係,兩者返回的都是函數對象引用.arguments是函數的全部參數列表,它是一個類數組的變量.
代碼演示
function parent(param1, param2, param3) {
child(param1, param2, param3);
}
function child() {
console.log(arguments); // { '0': 'mqin1', '1': 'mqin2', '2': 'mqin3' }
console.log(arguments.callee); // [Function: child]
console.log(child.caller); // [Function: parent]
}
parent('mqin1', 'mqin2', 'mqin3');
參考答案: 閉包這個術語,不管中文翻譯仍是英文解釋都太2B了,我必須罵人,由於它什麼其實都不是.非要講它是什麼的話,兩個字函數,更多字嵌套函數的父子自我引用關係.全部函數都是閉包.通俗的說,閉包就是做用域範圍,由於js是函數做用域,因此函數就是閉包.全局函數的做用域範圍就是全局,因此無須討論.更多的應用實際上是在內嵌函數,這就會涉及到內嵌做用域,或者叫做用域鏈.說到內嵌,其實就是父子引用關係(父函數包含子函數,子函數由於函數做用域又引用父函數,這它媽不是死結嗎?因此叫閉包),這就會帶來另一個問題,何時引用結束?若是不結束,就會一直佔用內存,引發內存泄漏.好吧,不用的時候就引用設爲空,死結就解開了.
參考答案:Object.defineProperty(obj, prop, descriptor)用來給對象定義屬性,有value,writable,configurable,enumerable,set/get等.hasOwnProerty用於檢查某一屬性是否是存在於對象自己,繼承來的父親的屬性不算.propertyIsEnumerable用來檢測某一屬性是否可遍歷,也就是能不能用for..in循環來取到.
參考答案:
1) 單例: 任意對象都是單例,無須特別處理
var obj = {name: 'michaelqin', age: 30};
2) 工廠: 就是一樣形式參數返回不一樣的實例
function Person() { this.name = 'Person1'; }
function Animal() { this.name = 'Animal1'; }
function Factory() {}
Factory.prototype.getInstance = function(className) {
return eval('new ' + className + '()');
}
var factory = new Factory();
var obj1 = factory.getInstance('Person');
var obj2 = factory.getInstance('Animal');
console.log(obj1.name); // Person1
console.log(obj2.name); // Animal1
3) 代理: 就是新建個類調用老類的接口,包一下
function Person() { }
Person.prototype.sayName = function() { console.log('michaelqin'); }
Person.prototype.sayAge = function() { console.log(30); }
function PersonProxy() {
this.person = new Person();
var that = this;
this.callMethod = function(functionName) {
console.log('before proxy:', functionName);
that.person[functionName](); // 代理
console.log('after proxy:', functionName);
}
}
var pp = new PersonProxy();
pp.callMethod('sayName'); // 代理調用Person的方法sayName()
pp.callMethod('sayAge'); // 代理調用Person的方法sayAge()
4) 觀察者: 就是事件模式,好比按鈕的onclick這樣的應用.
function Publisher() {
this.listeners = [];
}
Publisher.prototype = {
'addListener': function(listener) {
this.listeners.push(listener);
},
'removeListener': function(listener) {
delete this.listeners[listener];
},
'notify': function(obj) {
for(var i = 0; i < this.listeners.length; i++) {
var listener = this.listeners[i];
if (typeof listener !== 'undefined') {
listener.process(obj);
}
}
}
}; // 發佈者
function Subscriber() {
}
Subscriber.prototype = {
'process': function(obj) {
console.log(obj);
}
}; // 訂閱者
var publisher = new Publisher();
publisher.addListener(new Subscriber());
publisher.addListener(new Subscriber());
publisher.notify({name: 'michaelqin', ageo: 30}); // 發佈一個對象到全部訂閱者
publisher.notify('2 subscribers will both perform process'); // 發佈一個字符串到全部訂閱者
參考答案: push/pop, shift/unshift, split/join, slice/splice/concat, sort/reverse, map/reduce, forEach, filter
參考答案: indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase
參考答案:主要有構造函數原型和對象建立兩種方法。原型法是通用老方法,對象建立是ES5推薦使用的方法.目前來看,原型法更廣泛.
代碼演示
1) 構造函數方法定義類
function Person(){
this.name = 'michaelqin';
}
Person.prototype.sayName = function(){
alert(this.name);
}
var person = new Person();
person.sayName();
2) 對象建立方法定義類
var Person = { name: 'michaelqin', sayName: function(){ alert(this.name); } }; var person = Object.create(Person); person.sayName();
參考答案:原型鏈法,屬性複製法和構造器應用法. 另外,因爲每一個對象能夠是一個類,這些方法也能夠用於對象類的繼承.
代碼演示
1) 原型鏈法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function(){
alert(this.name);
};
function Person() {}
Person.prototype = Animal.prototype; // 人繼承自動物
Person.prototype.constructor = 'Person'; // 更新構造函數爲人
2) 屬性複製法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function() {
alert(this.name);
};
function Person() {}
for(prop in Animal.prototype) {
Person.prototype[prop] = Animal.prototype[prop];
} // 複製動物的全部屬性到人量邊
Person.prototype.constructor = 'Person'; // 更新構造函數爲人
3) 構造器應用法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = function() {
alert(this.name);
};
function Person() {
Animal.call(this); // apply, call, bind方法均可以.細微區別,後面會提到.
}
參考答案:就是類繼承裏邊的屬性複製法來實現.由於當全部父類的prototype屬性被複制後,子類天然擁有相似行爲和屬性.
參考答案:大多數語言裏邊都是塊做做用域,以{}進行限定,js裏邊不是.js裏邊叫函數做用域,就是一個變量在全函數裏有效.好比有個變量p1在函數最後一行定義,第一行也有效,可是值是undefined.
代碼演示
var globalVar = 'global var';
function test() {
alert(globalVar); // undefined, 由於globalVar在本函數內被重定義了,致使全局失效,這裏使用函數內的變量值,但是此時還沒定義
var globalVar = 'overrided var'; // globalVar在本函數內被重定義
alert(globalVar); // overrided var
}
alert(globalVar); // global var,使用全局變量
參考答案: this指的是對象自己,而不是構造函數.
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var person1 = new Person();
person1.name = 'michaelqin';
person1.sayName(); // michaelqin
參考答案:三者均可以把一個函數應用到其餘對象上,注意不是自身對象.apply,call是直接執行函數調用,bind是綁定,執行須要再次調用.apply和call的區別是apply接受數組做爲參數,而call是接受逗號分隔的無限多個參數列表,
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var obj = {name: 'michaelqin'}; // 注意這是一個普通對象,它不是Person的實例
1) apply
Person.prototype.sayName.apply(obj, [param1, param2, param3]);
2) call
Person.prototype.sayName.call(obj, param1, param2, param3);
3) bind
var sn = Person.prototype.sayName.bind(obj);
sn([param1, param2, param3]); // bind須要先綁定,再執行
sn(param1, param2, param3); // bind須要先綁定,再執行
參考答案: caller,callee之間的關係就像是employer和employee之間的關係,就是調用與被調用的關係,兩者返回的都是函數對象引用.arguments是函數的全部參數列表,它是一個類數組的變量.
代碼演示
function parent(param1, param2, param3) {
child(param1, param2, param3);
}
function child() {
console.log(arguments); // { '0': 'mqin1', '1': 'mqin2', '2': 'mqin3' }
console.log(arguments.callee); // [Function: child]
console.log(child.caller); // [Function: parent]
}
parent('mqin1', 'mqin2', 'mqin3');
參考答案: 閉包這個術語,不管中文翻譯仍是英文解釋都太2B了,我必須罵人,由於它什麼其實都不是.非要講它是什麼的話,兩個字函數,更多字嵌套函數的父子自我引用關係.全部函數都是閉包.通俗的說,閉包就是做用域範圍,由於js是函數做用域,因此函數就是閉包.全局函數的做用域範圍就是全局,因此無須討論.更多的應用實際上是在內嵌函數,這就會涉及到內嵌做用域,或者叫做用域鏈.說到內嵌,其實就是父子引用關係(父函數包含子函數,子函數由於函數做用域又引用父函數,這它媽不是死結嗎?因此叫閉包),這就會帶來另一個問題,何時引用結束?若是不結束,就會一直佔用內存,引發內存泄漏.好吧,不用的時候就引用設爲空,死結就解開了.
參考答案:Object.defineProperty(obj, prop, descriptor)用來給對象定義屬性,有value,writable,configurable,enumerable,set/get等.hasOwnProerty用於檢查某一屬性是否是存在於對象自己,繼承來的父親的屬性不算.propertyIsEnumerable用來檢測某一屬性是否可遍歷,也就是能不能用for..in循環來取到.
參考答案:
1) 單例: 任意對象都是單例,無須特別處理
var obj = {name: 'michaelqin', age: 30};
2) 工廠: 就是一樣形式參數返回不一樣的實例
function Person() { this.name = 'Person1'; }
function Animal() { this.name = 'Animal1'; }
function Factory() {}
Factory.prototype.getInstance = function(className) {
return eval('new ' + className + '()');
}
var factory = new Factory();
var obj1 = factory.getInstance('Person');
var obj2 = factory.getInstance('Animal');
console.log(obj1.name); // Person1
console.log(obj2.name); // Animal1
3) 代理: 就是新建個類調用老類的接口,包一下
function Person() { }
Person.prototype.sayName = function() { console.log('michaelqin'); }
Person.prototype.sayAge = function() { console.log(30); }
function PersonProxy() {
this.person = new Person();
var that = this;
this.callMethod = function(functionName) {
console.log('before proxy:', functionName);
that.person[functionName](); // 代理
console.log('after proxy:', functionName);
}
}
var pp = new PersonProxy();
pp.callMethod('sayName'); // 代理調用Person的方法sayName()
pp.callMethod('sayAge'); // 代理調用Person的方法sayAge()
4) 觀察者: 就是事件模式,好比按鈕的onclick這樣的應用.
function Publisher() {
this.listeners = [];
}
Publisher.prototype = {
'addListener': function(listener) {
this.listeners.push(listener);
},
'removeListener': function(listener) {
delete this.listeners[listener];
},
'notify': function(obj) {
for(var i = 0; i < this.listeners.length; i++) {
var listener = this.listeners[i];
if (typeof listener !== 'undefined') {
listener.process(obj);
}
}
}
}; // 發佈者
function Subscriber() {
}
Subscriber.prototype = {
'process': function(obj) {
console.log(obj);
}
}; // 訂閱者
var publisher = new Publisher();
publisher.addListener(new Subscriber());
publisher.addListener(new Subscriber());
publisher.notify({name: 'michaelqin', ageo: 30}); // 發佈一個對象到全部訂閱者
publisher.notify('2 subscribers will both perform process'); // 發佈一個字符串到全部訂閱者
參考答案: push/pop, shift/unshift, split/join, slice/splice/concat, sort/reverse, map/reduce, forEach, filter
參考答案: indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase