- 常用js類定義的方法有哪些?
參考答案:主要有構(gòu)造函數(shù)原型和對(duì)象創(chuàng)建兩種方法。原型法是通用老方法,對(duì)象創(chuàng)建是ES5推薦使用的方法.目前來(lái)看,原型法更普遍.
代碼演示
-
構(gòu)造函數(shù)方法定義類
function Person(){
this.name = 'michaelqin';
}
Person.prototype.sayName = function(){
alert(this.name);
}var person = new Person();
person.sayName(); -
對(duì)象創(chuàng)建方法定義類
var Person = {
name: 'michaelqin',
sayName: function(){ alert(this.name); }
};var person = Object.create(Person);
person.sayName();
- js類繼承的方法有哪些
參考答案:原型鏈法,屬性復(fù)制法和構(gòu)造器應(yīng)用法. 另外,由于每個(gè)對(duì)象可以是一個(gè)類,這些方法也可以用于對(duì)象類的繼承.
代碼演示
-
原型鏈法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = {
alert(this.name);
};function Person() {}
Person.prototype = Animal.prototype; // 人繼承自動(dòng)物
Person.prototype.constructor = 'Person'; // 更新構(gòu)造函數(shù)為人 -
屬性自制法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = {
alert(this.name);
};function Person() {}
for(prop in Animal.prototype) {
Person.prototype[prop] = Animal.prototype[prop];
} // 復(fù)制動(dòng)物的所有屬性到人量邊
Person.prototype.constructor = 'Person'; // 更新構(gòu)造函數(shù)為人 -
構(gòu)造器應(yīng)用法
function Animal() {
this.name = 'animal';
}
Animal.prototype.sayName = {
alert(this.name);
};function Person() {
Animal.call(this); // apply, call, bind方法都可以.細(xì)微區(qū)別,后面會(huì)提到.
}
js類多重繼承的實(shí)現(xiàn)方法是怎么樣的?
參考答案:就是類繼承里邊的屬性復(fù)制法來(lái)實(shí)現(xiàn).因?yàn)楫?dāng)所有父類的prototype屬性被復(fù)制后,子類自然擁有類似行為和屬性.js里的作用域是什么樣子的?
參考答案:大多數(shù)語(yǔ)言里邊都是塊作作用域,以{}進(jìn)行限定,js里邊不是.js里邊叫函數(shù)作用域,就是一個(gè)變量在全函數(shù)里有效.比如有個(gè)變量p1在函數(shù)最后一行定義,第一行也有效,但是值是undefined.
代碼演示
var globalVar = 'global var';
function test() {
alert(globalVar); // undefined, 因?yàn)間lobalVar在本函數(shù)內(nèi)被重定義了,導(dǎo)致全局失效,這里使用函數(shù)內(nèi)的變量值,可是此時(shí)還沒(méi)定義
var globalVar = 'overrided var'; // globalVar在本函數(shù)內(nèi)被重定義
alert(globalVar); // overrided var
}
alert(globalVar); // global var,使用全局變量
- js里邊的this指的是什么?
參考答案: this指的是對(duì)象本身,而不是構(gòu)造函數(shù).
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var person1 = new Person();
person1.name = 'michaelqin';
person1.sayName(); // michaelqin
- apply, call和bind有什么區(qū)別?
參考答案:三者都可以把一個(gè)函數(shù)應(yīng)用到其他對(duì)象上,注意不是自身對(duì)象.a(chǎn)pply,call是直接執(zhí)行函數(shù)調(diào)用,bind是綁定,執(zhí)行需要再次調(diào)用.a(chǎn)pply和call的區(qū)別是apply接受數(shù)組作為參數(shù),而call是接受逗號(hào)分隔的無(wú)限多個(gè)參數(shù)列表,
代碼演示
function Person() {
}
Person.prototype.sayName() { alert(this.name); }
var obj = {name: 'michaelqin'}; // 注意這是一個(gè)普通對(duì)象,它不是Person的實(shí)例
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需要先綁定,再執(zhí)行
sn(param1, param2, param3); // bind需要先綁定,再執(zhí)行
- caller, callee和arguments分別是什么?
參考答案: caller,callee之間的關(guān)系就像是employer和employee之間的關(guān)系,就是調(diào)用與被調(diào)用的關(guān)系,二者返回的都是函數(shù)對(duì)象引用.a(chǎn)rguments是函數(shù)的所有參數(shù)列表,它是一個(gè)類數(shù)組的變量.
代碼演示
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');
什么是閉包,閉包有哪些用處?
參考答案: 閉包這個(gè)術(shù)語(yǔ),無(wú)論中文翻譯還是英文解釋都太2B了,我必須罵人,因?yàn)樗裁雌鋵?shí)都不是.非要講它是什么的話,兩個(gè)字函數(shù),更多字嵌套函數(shù)的父子自我引用關(guān)系.所有函數(shù)都是閉包.通俗的說(shuō),閉包就是作用域范圍,因?yàn)閖s是函數(shù)作用域,所以函數(shù)就是閉包.全局函數(shù)的作用域范圍就是全局,所以無(wú)須討論.更多的應(yīng)用其實(shí)是在內(nèi)嵌函數(shù),這就會(huì)涉及到內(nèi)嵌作用域,或者叫作用域鏈.說(shuō)到內(nèi)嵌,其實(shí)就是父子引用關(guān)系(父函數(shù)包含子函數(shù),子函數(shù)因?yàn)楹瘮?shù)作用域又引用父函數(shù),這它媽不是死結(jié)嗎?所以叫閉包),這就會(huì)帶來(lái)另外一個(gè)問(wèn)題,什么時(shí)候引用結(jié)束?如果不結(jié)束,就會(huì)一直占用內(nèi)存,引起內(nèi)存泄漏.好吧,不用的時(shí)候就引用設(shè)為空,死結(jié)就解開了.defineProperty, hasOwnProperty, isEnumerable都是做什么用的?
參考答案:Object.defineProperty(obj, prop, descriptor)用來(lái)給對(duì)象定義屬性,有value,writable,configurable,enumerable,set/get等.hasOwnProerty用于檢查某一屬性是不是存在于對(duì)象本身,繼承來(lái)的父親的屬性不算.isEnumerable用來(lái)檢測(cè)某一屬性是否可遍歷,也就是能不能用for..in循環(huán)來(lái)取到.-
js常用設(shè)計(jì)模式的實(shí)現(xiàn)思路,單例,工廠,代理,裝飾,觀察者模式等
參考答案:單例: 任意對(duì)象都是單例,無(wú)須特別處理
var obj = {name: 'michaelqin', age: 30};工廠: 就是同樣形式參數(shù)返回不同的實(shí)例
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- 代理: 就是新建個(gè)類調(diào)用老類的接口,包一下
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.personfunctionName; // 代理
console.log('after proxy:', functionName);
}
}var pp = new PersonProxy();
pp.callMethod('sayName'); // 代理調(diào)用Person的方法sayName()
pp.callMethod('sayAge'); // 代理調(diào)用Person的方法sayAge()-
觀察者: 就是事件模式,比如按鈕的onclick這樣的應(yīng)用.
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);
}
}
}
}; // 發(fā)布者
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}); // 發(fā)布一個(gè)對(duì)象到所有訂閱者
publisher.notify('2 subscribers will both perform process'); // 發(fā)布一個(gè)字符串到所有訂閱者
列舉數(shù)組相關(guān)的常用方法
參考答案: push/pop, shift/unshift, split/join, slice/splice/concat, sort/reverse, map/reduce, forEach, filter列舉字符串相關(guān)的常用方法
參考答案: indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase