나는 누군가를 불쾌하게하지는 않지만, 이런 종류의 일은 입니다. 정말로은 주목할 가치가 없습니다. IMHO. 거의 모든 브라우저의 속도 차이는 JS 엔진에 달려 있습니다. V8 엔진은 메모리 관리 기능이 뛰어납니다. 특히 이전의 IE JScript 엔진과 비교할 때 그렇습니다. FF 모두 반면, 내가 확인
var closure = (function()
{
var closureVar = 'foo',
someVar = 'bar',
returnObject = {publicProp: 'foobar'};
returnObject.getClosureVar = function()
{
return closureVar;
};
return returnObject;
}());
마지막 시간, 크롬 실제로 someVar
을 GC'ed, 그것은 (closure
에 의해 참조)를 인생의 반환 값에 의해 참조되지 않았기 때문에 :
는 다음 사항을 고려 Opera는 전체 기능 범위를 메모리에 유지했습니다.
이 스 니펫에서는 실제로 문제가되지 않지만 수천 줄의 코드로 구성된 모듈 패턴 (AFAIK, 거의 모든 코드가 사용됨)을 사용하여 작성된 라이브러리의 경우 은으로 변경 될 수 있습니다 .
어쨌든 현대 JS 엔진은 단지 "멍청한" 구문 분석 및 실행 이상의 것 이상입니다. 당신이 말했듯이 : JIT 컴파일이 진행되고 있지만 가능한 한 코드를 최적화하는 것과 관련된 많은 트릭이 있습니다. 당신이 게시 한 발췌 문장은 FF의 엔진이 이을 좋아하는 방식으로 작성되었습니다.
Chrome과 FF간에 가장 빠른 엔진을 가진 일종의 스피드 전투가 있음을 기억하는 것도 중요합니다. 지난 번 모질라의 Rhino 엔진이 구글의 V8을 능가한다고 말했을 때, 그것이 여전히 사실이라면 말은 할 수 없다 ... 그 이후로 구글과 모질라는 모두 엔진에서 작업 해왔다 ...
아래 line : 여러 브라우저 간의 속도 차이가 존재합니다. 아무도 그 점을 부정 할 수는 없지만 한 점의 차이점은 중요하지 않습니다. 단 한 번만 반복해서 쓰는 스크립트는 쓰지 않을 것입니다. 중요한 전반적인 성과입니다.
JS는 벤치 마크에서 까다로운 놈이기도합니다. 콘솔을 열고 재귀 적 기능을 작성한 다음 FF와 Chrome에서 100 번 실행합니다. 각 재귀에 걸리는 시간과 전체 실행 시간을 비교하십시오. 그런 다음 2 시간 정도 기다렸다가 다시 시도하십시오 ... 때때로 FF가 위에 올 수도 있지만 다른 경우에는 Chrome이 더 빠를 수도 있습니다.
var bench = (function()
{
var mark = {start: [new Date()],
end: [undefined]},
i = 0,
rec = function(n)
{
return +(n === 1) || rec(n%2 ? n*3+1 : n/2);
//^^ Unmaintainable, but fun code ^^\\
};
while(i++ < 100)
{//new date at start, call recursive function, new date at end of recursion
mark.start[i] = new Date();
rec(1000);
mark.end[i] = new Date();
}
mark.end[0] = new Date();//after 100 rec calls, first element of start array vs first of end array
return mark;
}());
을하지만 지금, 당신의 처음 질문 (들)에 돌아 가야 : :이 기능을 시도했습니다
첫째 : 당신은 확실히 말하자면, 비교하지 않습니다 제공하는 조각, jQuery의 $.extend
방법 : 실제 복제가 진행 중이며, 복제는 물론입니다. 순환 참조를 전혀 검사하지 않습니다.이 참조는 제가 조사한 대부분의 libs입니다. 순환 참조를 검사하면 전체 프로세스가 느려지지만 수시로 편리하게 사용할 수 있습니다 (아래 예제 1). 성능 차이의 일부는이 코드 이 단순히을 덜 적게 함으로 설명 할 수 있으므로 시간이 덜 필요합니다.
두 번째 : 생성자를 선언하면 (클래스는 JS에는 존재하지 않음) 인스턴스를 만드는 것은 사실 두 가지 다른 작업입니다 (생성자가 객체의 인스턴스를 생성한다고 선언하더라도 (정확히 Function
인스턴스) 당신이 당신의 생성자를 작성하는 방법은 을 큰 숫자 인과 같이 만들 수있다. 다시 말하지만, 이는 일반화 된 것이며 특정 엔진의 특정 유스 케이스에는 적용되지 않을 수있다. 예를 들어, V8은 해당 함수가 생성자의 일부인 경우에도 모든 인스턴스에 대해 단일 함수 객체 만들기 - 또는 그렇게 말합니다.
세 번째 : 생각할 수있는 것처럼 비정상적이지 않은 긴 프로토 타입 체인 이동 , 멀리에서 사실. JS가 함수 호출을 해결하거나 표현식을 해결하는 방식에 내재되어 있기 때문에 예제 2에서 3 개의 프로토 타입 체인을 지속적으로 탐색하고 있습니다 (예제 3 참조).
마지막으로, 아마도 JIT로 컴파일되었지만 다른 라이브러리가 JIT로 컴파일되지 않는다는 것은 스택되지 않는다고 말합니다. 그들은 다시는 그렇지 않을 수도 있습니다. 앞에서 말했듯이, 다른 엔진은 다른 작업에서 성능이 뛰어납니다 ... FF JIT는이 코드를 컴파일하고 다른 엔진은 그렇지 않습니다.
다른 라이브러리가 JIT 컴파일되지 않는 이유는 순환 참조, 딥 복제 기능, 종속성 (여러 가지 이유로 extend
메서드가 사용 된 이유)을 확인하는 주된 이유입니다.
예 1 :이 함수는 객체의 첫 번째 수준 클론
var shallowCloneCircular = function(obj)
{//clone object, check for circular references
function F(){};
var clone, prop;
F.prototype = obj;
clone = new F();
for (prop in obj)
{//only copy properties, inherent to instance, rely on prototype-chain for all others
if (obj.hasOwnProperty(prop))
{//the ternary deals with circular references
clone[prop] = obj[prop] === obj ? clone : obj[prop];//if property is reference to self, make clone reference clone, not the original object!
}
}
return clone;
};
는 원래의 객체 속성에 의해 참조되어있는 모든 오브젝트는 여전히 공유한다. 간단한 수정은 단순히 반복적으로 위의 함수를 호출하는 것입니다,하지만 당신은 모든 수준에서 순환 참조의 불쾌한 업무를 처리해야합니다 : 물론
var circulars = {foo: bar};
circulars.circ1 = circulars;//simple circular reference, we can deal with this
circulars.mess = {gotcha: circulars};//circulars.mess.gotcha ==> circular reference, too
circulars.messier = {messiest: circulars.mess};//oh dear, this is hell
, 이것은 가장 일반적인 아니다 첫 번째 선언, 이론적으로
function CleanConstructor()
{};
CleanConstructor.prototype.method1 = function()
{
//do stuff...
};
var foo = new CleanConstructor(),
bar = new CleanConstructor);
console.log(foo === bar);//false, we have two separate instances
console.log(foo.method1 === bar.method1);//true: the function-object, referenced by method1 has only been created once.
//as opposed to:
function MessyConstructor()
{
this.method1 = function()
{//do stuff
};
}
var foo = new MessyConstructor(),
bar = new MessyConstructor();
console.log(foo === bar);//false, as before
console.log(foo.method1 === bar.method1);//false! for each instance, a new function object is constructed, too: bad performance!
: 당신이 방어 코드를 작성하려는 경우 상황은, 그러나, 당신은 ... 많은 사람들이 미친 코드 모든 시간을 쓰기는 사실을 인정하는
예 2가 생성자는 입니다. 느림지저분한 방법보다: method1
이 참조하는 함수 객체는 단일 인스턴스가 만들어지기 전에 만들어집니다. 두 번째 예제에서는 생성자가 호출되는 경우를 제외하고 method1
을 만들지 않습니다. 그러나 단점은 거대한입니다. 첫 번째 예의 경우 new
키워드를 잊어 버리면 반환 값은 undefined
입니다. 두 번째 생성자는 new
키워드를 생략 할 때 전역 함수 객체를 만들고 물론 각 호출에 대해 새 함수 객체를 만듭니다. 당신은 ... 예 3
예를 우리에게 가져다 공회전 사실이다 생성자 (및 프로토 타입)가 3 :
var foo = [];//create an array - empty
console.log(foo[123]);//logs undefined.
좋아, 그래서 무대 뒤에서 무슨 일 : foo
은 개체을 참조하고, Array
의 인스턴스는 개체 프로토 타입 (그냥 시도 Object.getPrototypeOf(Array.prototype)
)을 상속받습니다.이 때문에, 배열 인스턴스가 어떤 객체와 거의 같은 방식으로 작동하므로 것을 추론하기 위하여 약자 즉
foo[123] ===> JS checks instance for property 123 (which is coerced to string BTW)
|| --> property not found @instance, check prototype (Array.prototype)
===========> Array.prototype.123 could not be found, check prototype
||
==========> Object.prototype.123: not found check prototype?
||
=======>prototype is null, return undefined
는, 당신이 설명과 같은 체인이 너무 억지 또는 드문 일이 아니다. 그것은 JS가 작동하는 방식입니다. 그래서 느린 것을 기대하는 것은 생각을하기 때문에 뇌가 튀어 오를 것으로 기대하는 것과 같습니다 : 예, 너무 많이 생각하면 마모가 될 수 있지만 휴식을 취해야 할 때만 알면됩니다. 프로토 타입 체인의 경우와 마찬가지로 : 위대한, 그냥 천천히 느껴진다. 예 ...
my.class.js의 속도를 높이는 한 가지 측면은 확장 기능이 'hasOwnProperty' 체크. --- 그러나 jsperf 테스트에서 빠른 실행 라이브러리의 차이는 초당 수백만 건의 연산을 수행한다는 사실을 고려할 때 최소한입니다. 그 많은 객체 인스턴스를 만들면 메모리 풋 프린트와 가비지 수집과 관련하여 이미 다른 문제가 발생했을 것입니다. – Blaise