javascript高級(jí)話題(面向?qū)ο?,作用域,閉包,設(shè)計(jì)模式等)

  1. 常用js類定義的方法有哪些?
    參考答案:主要有構(gòu)造函數(shù)原型和對(duì)象創(chuàng)建兩種方法。原型法是通用老方法,對(duì)象創(chuàng)建是ES5推薦使用的方法.目前來(lái)看,原型法更普遍.

代碼演示

  1. 構(gòu)造函數(shù)方法定義類

    function Person(){
    this.name = 'michaelqin';
    }
    Person.prototype.sayName = function(){
    alert(this.name);
    }

    var person = new Person();
    person.sayName();

  2. 對(duì)象創(chuàng)建方法定義類

    var Person = {
    name: 'michaelqin',
    sayName: function(){ alert(this.name); }
    };

    var person = Object.create(Person);
    person.sayName();

  1. js類繼承的方法有哪些
    參考答案:原型鏈法,屬性復(fù)制法和構(gòu)造器應(yīng)用法. 另外,由于每個(gè)對(duì)象可以是一個(gè)類,這些方法也可以用于對(duì)象類的繼承.

代碼演示

  1. 原型鏈法

    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ù)為人

  2. 屬性自制法

    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ù)為人

  3. 構(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ì)提到.
    }

  1. js類多重繼承的實(shí)現(xiàn)方法是怎么樣的?
    參考答案:就是類繼承里邊的屬性復(fù)制法來(lái)實(shí)現(xiàn).因?yàn)楫?dāng)所有父類的prototype屬性被復(fù)制后,子類自然擁有類似行為和屬性.

  2. 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,使用全局變量
  1. 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
  1. 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í)行
  1. 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');
  1. 什么是閉包,閉包有哪些用處?
    參考答案: 閉包這個(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é)就解開了.

  2. 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)取到.

  3. js常用設(shè)計(jì)模式的實(shí)現(xiàn)思路,單例,工廠,代理,裝飾,觀察者模式等
    參考答案:

    1. 單例: 任意對(duì)象都是單例,無(wú)須特別處理
      var obj = {name: 'michaelqin', age: 30};

    2. 工廠: 就是同樣形式參數(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

    1. 代理: 就是新建個(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()

    1. 觀察者: 就是事件模式,比如按鈕的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è)字符串到所有訂閱者
  1. 列舉數(shù)組相關(guān)的常用方法
    參考答案: push/pop, shift/unshift, split/join, slice/splice/concat, sort/reverse, map/reduce, forEach, filter

  2. 列舉字符串相關(guān)的常用方法
    參考答案: indexOf/lastIndexOf/charAt, split/match/test, slice/substring/substr, toLowerCase/toUpperCase

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容