js:實現自定義事件對象接口


網易2017內推筆試題

要求:

  請實現下面的自定義事件Event對象的接口,功能見注釋(測試1)

  該Event對象的接口需要能被其他對象拓展復用(測試2)

 1     //測試1
 2     Event.on('test',function(result){
 3         console.log(result);
 4     });
 5     Event.on('test',function(){
 6         console.log('test');
 7     });
 8     Event.emit('test','hello world');   //輸出'hello world' 和 'test'
 9     //測試2
10     var person1 = {};
11     var person2 = {};
12     Object.assign(person1, Event);
13     Object.assign(person2, Event);
14     person1.on('call1',function(){
15         console.log('person1');
16     });
17     person2.on('call2',function(){
18         console.log('person2');
19     });
20     person1.emit('call1');  //輸出'person1'
21     person2.emit('call2');  //沒有輸出
22     person1.emit('call1');  //沒有輸出
23     person2.emit('call2');  //輸出'person2'
24 
25 
26     var Event = {
27         //通過on接口監聽事件eventName
28         //如果事件eventName被觸發,則執行callback回調函數
29         on:function(eventName, callback){
30             //你的代碼
31         },
32         //觸發事件 eventName
33         emit:function(eventName){
34             //你的代碼
35         }
36     };

 

 

  • Object.assign(target, ...sources)  可以把任意多個的源對象自身的可枚舉屬性拷貝給目標對象,然后返回目標對象。

 

 

這里有篇解決的……但是沒看明白http://blog.daraw.cn/2016/08/02/javascript-event-emitter/

 

 

還是牛客高手多

 1         var Event = {
 2             on: function(eventName, callback){
 3                 this[eventName] = this[eventName] || new Array();
 4                 this[eventName].push(callback);
 5             },
 6 
 7             emit: function(eventName){
 8                 var params = arguments.length>1 ? Array.prototype.slice.call(arguments,1) :[];
 9                 if(this[eventName]){
10                     Array.prototype.forEach.call(this[eventName],function(arg){
11                         arg.apply(this,params);
12                     });
13                 }
14             }
15         }

以上的方法實現過程中,遇到一些問題……

  1) 一開始想茬了,以為this[eventName]可以寫作this.eventName,然而輸出結果總是不對。然后才想到,this.eventName等於是調用了名為'eventName’的屬性,而不是把eventName代表的字符串傳給this的屬性。所以失敗了。

  2)一開始以為Array.prototype.slice/forEach可以寫作Array.方法名,但是會報錯。所以應該是只能通過prototype調用call/apply

  3)一開始沒有理解這道題的意思。其實指的是:Event中的on綁定事件,而emit執行事件。一開始以為觸發事件的代碼:Event.emit('test','hello world'); 是傳入了兩個參數,一次傳入test,一次傳入hello world。其實完全想錯了……很明顯,'test’是一個eventName,是在test綁定的事件里傳入參數hello world.而之所以輸出hello world與test,是因為test綁了兩個事件,一個是有參數的輸出參數,一個是沒有參數的輸出test。所以這里是事件綁定而非賦值。

  4)關於Object.assign(). 其定義是這樣的:

Object.assign(target, ...sources)

Properties in the object will be overwritten by properties in the sources if they have the same key.  Later sources' properties will similarly overwrite earlier ones.  

The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters. For copying property definitions, including their enumerability, into prototypesObject.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead.

Both String and Symbol properties are copied.

In case of an error, for example if a property is non-writable, a TypeError will be raised, and the targetobject remains unchanged.

Note that Object.assign() does not throw on null or undefined source values.

  即:將來自一個或多個源對象中的值復制到一個目標對象。

    此函數返回目標對象。

    可枚舉自有屬性從源對象復制到目標對象。

    可使用此函數合並或克隆對象。

    null 或 undefined 源被視為空對象一樣對待,不會對目標對象產生任何影響。

  【以下是我的渣翻譯】這里意思是說:對象中的屬性會被源中的屬性覆蓋,后面的屬性會被前面的覆蓋。

  這種方法只會從源對象中復制可枚舉的和自己的屬性到一個目標對象。然后返回目標對象。

  如果要復制屬性定義,包括其可枚舉性,應該使用Object.getOwnPrototypeDescriptor()和Object.defineProperty()

  5)牛客網上答題的大神更新了答案,把this復制給一個變量self, var self = this,然后其后的this都用self代替,是【考慮到了參數及this作用域的改進版本】。但是這里並不理解,既然在這個函數里,this和self都指向一樣啊?為何要這么做呢?

    我大概明白了……在函數里調用this可能會引發各種奇怪的問題,因為this的指向並不一定總是你想要指的this。但是用self應該也不恰當,因為“You should avoid self as there is a window.self object and you could end up using that accidentally if you forget to declare your own self var”——應該避免self因為有一個window.self對象。所以這里我改成了that。於是代碼寫作:

 

 1         var Event = {
 2             on: function(eventName, callback){
 3                 if(!this[eventName]){
 4                     this[eventName] = [];
 5                 }
 6                 this[eventName].push(callback);
 7             },
 8             emit: function(eventName){
 9                 var that = this;
10                 var params = arguments.length>1 ? Array.prototype.slice.call(arguments,1) : [];
11                 if(that[eventName]){
12                     Array.prototype.forEach.call(that[eventName],function(arg){
13                         arg.apply(self,params);
14                     });
15                 }
16             }
17         }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM