tSet2018
10
2018-02-13 20:49:26
8
377

javascript 질문 드립니다!


function RollingBanner(userOption){

console.log(userOption);

var options = jQuery.extend({}, $.RollingBannerOptions, userOption);

this._imageItems = null;

this._imgLength = 0;

this._logoHeight = 0;

this._currentItem = null;

this._nextItem = null;

this._currentIndex = 0;

this.innerTime = 0;

this.outerTime = 0;

this.initProperty(userOption);

this.initPosition();

this.startAutoPlay();

}


//생략


function RollingBannerCursor(userOption){

userOption[0].divElement = $('.rolling-bannerCursor');

RollingBanner.call(this, userOption[0]);

}

RollingBannerCursor.prototype = new RollingBanner();

RollingBannerCursor.constructor = RollingBannerCursor;


RollingBanner 함수를 상속받는 함수 RollingBannerCursor 를 만들고 싶은데

Uncaught TypeError: this.initProperty is not a function

라는 에러가 납니다ㅠㅠ


RollingBanner 생성자를 만들 때는 정상적으로 실행이 되는데

RollingBannerCursor 생성자를 만들면 Uncaught TypeError 에러가 납니다.


상속을 이렇게 구현하는게 아닌가요?ㅠㅠ

도와주세요ㅠㅠ

0
0
  • 답변 8

  • 초코쪼꼬
    6k
    2018-02-13 21:58:38 작성 2018-02-14 07:08:38 수정됨

    this 가 window를 바라봐서그럽니다.


    함수 최상단에 var self = this;를 선언하시고 전부 this를 self로 바꾸세요.


    -- 추가

    어제 볼때 대충봐서그런지 못봤네요.

    initProperty는 어디에 선언 한건가요?

    0
  • tSet2018
    10
    2018-02-14 19:20:19

    초코쪼꼬님 답변 감사합니다!

    var self = this; 는 RollingBanner함수 상단에 선언하면 되는건가요?ㅠㅠ

    아직 초보라 오류가 너무 많이 나네요..

    아래는 함수 선언, 사용 부분 소스입니다!


    (function($){
    			$.fn.rollingBanner = function(userOptions){
    				$(this).each(function(index){
    					if(typeof(userOptions[index])=='undefined'){
    						userOptions.push({});
    					}
    					userOptions[index].divElement = $(this);
    					var rbObject = new RollingBanner(userOptions[index]);
    				});
    				return this;
    			}
    		})(jQuery)
    		
    		
    		
    		$(document).ready(function(){
    			$('.rolling-banner').rollingBanner([
    				{
    					innerTime : 2000
    					, outerTime : 4000
    				}, {
    					innerTime : 4000
    					, outerTime : 6000
    				}
    			]);
    			
    			var rbcObject = new RollingBannerCursor([
    				{
    					innerTime : 500
    					, outerTime : 1000
    				}
    			]);
    		});
    		
    		
    		
    		$.RollingBannerOptions = {
    			innerTime : 1000
    			, outerTime : 2000
    		}
    		
    		
    		function RollingBanner(userOption){
    			console.log(userOption);
    			var options = jQuery.extend({}, $.RollingBannerOptions, userOption);
    			this._imageItems = null;
    			this._imgLength = 0;
    			this._logoHeight = 0;
    			this._currentItem = null;
    			this._nextItem = null;
    			this._currentIndex = 0;
    			this.innerTime = 0;
    			this.outerTime = 0;
    			
    			this.initProperty(userOption);
    			this.initPosition();
    			this.startAutoPlay();
    		}
    		
    		
    		RollingBanner.prototype.initProperty = function(userOption){
    			console.log(userOption);
    			this._imageItems = userOption['divElement'].find('img');
    			this._imgLength = this._imageItems.length;
    			this._logoHeight = this._imageItems.height();
    			this._innerTime = userOption.innerTime;
    			this._outerTime = userOption.outerTime;
    		}
    		
    		
    		RollingBanner.prototype.initPosition = function(){
    			this._imageItems.not(':eq(0)').css({
    				'top' : this._logoHeight
    			});
    		}
    		
    		
    		RollingBanner.prototype.startAutoPlay = function(){
    			var objThis = this;
    			setInterval(function(){
    				objThis._currentItem = objThis._imageItems.eq((objThis._imgLength+objThis._currentIndex++)%objThis._imgLength);
    				objThis._nextItem = objThis._imageItems.eq((objThis._imgLength+objThis._currentIndex)%objThis._imgLength);
    				
    				objThis._currentItem.animate({
    					'top' : -objThis._logoHeight
    					, 'opacity' : 0
    				}, objThis._innerTime);
    				objThis._nextItem.css({
    					'top' : objThis._logoHeight
    					, 'opacity' : 0
    				});
    				objThis._nextItem.animate({
    					'top' : 0
    					, 'opacity' : 1
    				}, objThis._innerTime);
    			}, this._outerTime);
    		}
    		
    		
    		function RollingBannerCursor(userOption){
    			userOption[0].divElement = $('.rolling-bannerCursor');
    			RollingBanner.call(this, userOption[0]);
    		}
    		
    		RollingBannerCursor.prototype = new RollingBanner();
    		RollingBannerCursor.constructor = RollingBannerCursor;


    0
  • 초코쪼꼬
    6k
    2018-02-14 20:05:33

    네 this를 가지고 있는 변수를 선언해주면 될 것 같네요.

    0
  • tSet2018
    10
    2018-02-14 20:49:13

    이렇게 수정하는걸 말씀하시는건가요?ㅠㅠ

    Uncaught TypeError: self.initProperty is not a function

    라고 뜹니다ㅠㅠ

    근데 프로토타입 형식(?) 클래스에서 this가 window 객체를 바라볼 수 있는건가요?ㅠㅠ

    혼자 하려니까 너무 어렵네요.. 답변 감사합니다!

    function RollingBanner(userOption){
    			var self = this;
    			console.log(userOption);
    			var options = jQuery.extend({}, $.RollingBannerOptions, userOption);
    			self._imageItems = null;
    self._imgLength = 0;
    self._logoHeight = 0;
    self._currentItem = null;
    self._nextItem = null;
    self._currentIndex = 0;
    self.innerTime = 0;
    self.outerTime = 0;
    self.initProperty(userOption); self.initPosition(); self.startAutoPlay(); }


    0
  • 초코쪼꼬
    6k
    2018-02-14 21:10:21

    음.. 이걸 스마트폰으로 적으려니까 좀 힘들거 같네요.

    pc할 수 있을때 다시 설명드려도 될까요?

    0
  • tSet2
    4
    2018-02-16 20:09:04
    네 그럼요 ㅠㅠ 감사합니다!
    0
  • 초코쪼꼬
    6k
    2018-02-19 08:59:10 작성 2018-02-19 09:01:22 수정됨

    즐거운 명절이 되었는지요.. 고향집에는 컴퓨터가 없어서 이제와서 답변을 달고 있네요..

    이미 답을 찾았다면 늦어서 죄송합니다.


    function RollingBanner(userOption){
        var self = this;
        console.log("userOptopn : " + userOption);
        var options = "option";
        self._imageItems = null;
        self._imgLength = 0;
        self._logoHeight = 0;
        self._currentItem = null;
        self._nextItem = null;
        self._currentIndex = 0;
        self.innerTime = 0;
        self.outerTime = 0;
    
        self.initProperty(userOption);
        self.initPosition();
        self.startAutoPlay();
    }
    
    
    RollingBanner.prototype.initProperty = function(userOption){
        console.log("initProperty");
    }
    
    
    RollingBanner.prototype.initPosition = function(){
        console.log("initPosition");
    }
    
    
    RollingBanner.prototype.startAutoPlay = function(){
        console.log("startAutoPlay");
    }
    
    
    function RollingBannerCursor(userOption){
        RollingBanner.call(this, "userOption");
    }
    
    RollingBannerCursor.prototype = RollingBanner.prototype;
    RollingBannerCursor.constructor = RollingBannerCursor;


    @tSet2 님이 올려준 코드에서 뼈대만 남겨두고 나머지는 전부 제거하였어요.


    우선 parent 개념인 RollingBanner를 선언 하겠죠. 같이 동작할 prototype도 선언하구요.

    그런 다음에 child개념인 RollingBannerCursor를 선언합니다. 그런데 저기서 보면

    RollingBanner.call(this, userOption); 으로 RollingBanner를 호출하네요. 이말은 RollingBannerCursor가 받은 arguments로 RollingBanner와 동일하게 생성자를 만듦으로써 상속받았다는 것처럼 표현하기 위함입니다.


    그렇게 되면 생성자를 만들게 되겠네요. 여기서 한가지 문제가 발생합니다. 생성자는 만들었는데 동작할 method는 안들어와 있네요.


    그래서 아래에 이렇게 선언 합니다.

    RollingBannerCursor.prototype = RollingBanner.prototype;


    실제 올려준 코드는 RollingBannerCursor.prototype = new RollingBanner();

    이렇게 되어 있는데


    RollingBannerCursor.prototype = RollingBanner.prototype;

    RollingBannerCursor.prototype = new RollingBanner();


    이 두가지 코드는 약간 개념이 다릅니다.


    실제로 console.dir(RollingBannerCursor); 이렇게 쳐볼때


    // RollingBannerCursor.prototype = RollingBanner.prototype;

    // console.dir(RollingBannerCursor);

    ƒ RollingBannerCursor(userOption)
    constructor : ƒ RollingBannerCursor(userOption)
    arguments : null
    caller : null
    length : 1
    name : "RollingBannerCursor"
    prototype : {initProperty: ƒ, initPosition: ƒ, startAutoPlay: ƒ, constructor: ƒ}
    __proto__ : ƒ ()
    [[FunctionLocation]] : VM58:35
    [[Scopes]] : Scopes[1]


    이러한 구조로 나오고

    // RollingBannerCursor.prototype = new RollingBanner();

    // console.dir(RollingBannerCursor);


    ƒ RollingBannerCursor(userOption)
    constructor : ƒ RollingBannerCursor(userOption)
    arguments : null
    caller : null
    length : 1
    name : "RollingBannerCursor"
    prototype : RollingBanner {_imageItems: null, _imgLength: 0, _logoHeight: 0, _currentItem: null, _nextItem: null, …}
    __proto__ : ƒ ()
    [[FunctionLocation]] : VM236:35
    [[Scopes]] : Scopes[1]


    중요한 코드인 prototype을 잘 봐보시길 바랍니다.

    위에 RollingBanner.prototype을 넣은 코드는 동작에 필요한 method만 받는 반면

    new RollingBanner(); 를 선언한 코드는 필요하지 않는 RollingBanner내의 선언된 변수 뿐만아니고

    구조 자체가 RollingBannerCursor.prototype.__proto__ (수정함) 으로 사용해야 RollingBanner.prototype을 사용하게 됩니다. 즉.. 구조가 꼬인거죠.


    그리고 this를 self로 만들어서 쓰라고 했던건 this의 고질병 때문에 그렇습니다.

    사용자의 의도는 this가 해당 객체를 바라보게 사용하는 용도로 쓰고 싶지만 this가 보는 target이 없다면 이 this는 Window객체를 바라보게 되어있습니다.

    그렇다는 말은 코드를 사용하다가 target이 혼동이 되면 this는 Window를 바라보게 되기 때문에 this.initProperty(userOption); 와 같은 코드를 실행할때 없는 함수라는 오류가 발생을 하는거죠.


    그렇다면 this.variable을 선언하는게 아니고 var self = this; self.variable 로 선언하게 된다면 여기서 선언된 self는 값이 바뀔 수없는 구조 이기 때문에(** 물론 setter를 만들면 이 self도 값을 바꿀수 있습니다. 단.. 이러한 경우에는 setter를 안만드는게 좋습니다.) self가 항시 객체를 바라보고 있어서 self.variable 및 self.method() 를 선언, 호출해도 오류가 발생하지 않는거죠.


    코드를 적용해보고 궁금한점이 있으면 질문 주세요.

    ** 중요한건 위코드가 정상적으로 도는지를 바로 운영 소스에 적용하지말고 browser에 개발자도구를 켜보고 제가 적어드린 제일 처음 코드를 쓰게되면 구조가 잡히는지부터 테스트해보고 적용을 하기 바랍니다.


    0
  • tSet2
    4
    2018-02-21 23:15:50

    초코쪼꼬님 답변 정말 감사합니다!

    설명도 너무 친절하게 해주시고... 몰랐던 부분 하나 하나 너무 잘 설명해주셨어요ㅠㅠ

    덕분에 정말 많이 배우고 갑니다!

    0
  • 로그인을 하시면 답변을 등록할 수 있습니다.