Java Script

Описание: Наиболее перспективное направление развития компьютерных наук. Надо быть в теме!

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#25 dyvniy » Ср, 4 ноября 2015, 17:03:27

import in JS
http://stackoverflow.com/questions/950087/include ... ile-in-another-javascript-file
Спойлер
Include a JavaScript file in another JavaScript file?

up vote
2268
down vote
favorite
771
Is there something similar to @import in CSS in JavaScript that allows you to include a JavaScript file inside another JavaScript file?

javascript file import include
shareimprove this question
edited Nov 11 '14 at 18:54

Peter Mortensen
9,023106196
asked Jun 4 '09 at 11:59

Alec Smart
21.7k2696158
23
stackoverflow.com/questions/21294/… – Daniel A. White Jun 4 '09 at 12:01
11
@Daniel, I do not want to use an AJAX call. – Alec Smart Jun 4 '09 at 12:02
2
Nonetheless the answers are the same. – annakata Jun 4 '09 at 12:20
show 2 more comments
39 Answers
activeoldestvotes
1 2 next
up vote
2113
down vote
accepted
JavaScript has no import, include, or require. (Update 2015: it does now with ES6 modules) There are other ways for JavaScript to include external JavaScript contents, though.

Ajax Loading

Load an additional script with an Ajax call and then use eval. This is the most straightforward way, but it is limited to your domain because of the JavaScript sandbox security model. Using eval also opens the door to bugs and hacks.

jQuery Loading

The jQuery library provides loading functionality in one line:

$.getScript("my_lovely_script.js", function(){

alert("Script loaded but not necessarily executed.");

});
Dynamic Script Loading

Add a script tag with the script URL in the HTML. To avoid the overhead of jQuery, this is an ideal solution.

The script can even reside on a different server. Furthermore, the browser evaluates the code. The <script> tag can be injected into either the web page <head>, or inserted just before the closing </body> tag.

Both of these solutions are discussed and illustrated in JavaScript Madness: Dynamic Script Loading.

Detecting when the script has been executed

Now, there is a big issue you must know about. Doing that implies that you remotely load the code. Modern web browsers will load the file and keep executing your current script because they load everything asynchronously to improve performance. (This applies to both the jQuery method and the manual dynamic script loading method.)

It means that if you use these tricks directly, you won't be able to use your newly loaded code the next line after you asked it to be loaded, because it will be still loading.

For example: my_lovely_script.js contains MySuperObject:

var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);

var s = new MySuperObject();

Error : MySuperObject is undefined
Then you reload the page hitting F5. And it works! Confusing...

So what to do about it ?

Well, you can use the hack the author suggests in the link I gave you. In summary, for people in a hurry, he uses en event to run a callback function when the script is loaded. So you can put all the code using the remote library in the callback function. For example:

function loadScript(url, callback)
{
// Adding the script tag to the head as suggested before
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;

// Then bind the event to the callback function.
// There are several events for cross browser compatibility.
script.onreadystatechange = callback;
script.onload = callback;

// Fire the loading
head.appendChild(script);
}
Then you write the code you want to use AFTER the script is loaded in a lambda function:

var myPrettyCode = function() {

// Here, do what ever you want
};
Then you run all that:

loadScript("my_lovely_script.js", myPrettyCode);
Note that the script may execute after the DOM has loaded, or before, depending on the browser and whether you included the line script.async = false;. There's a great article on Javascript loading in general which discusses this.

Source Code Merge

Another solution is to combine the two files into a single file. This can be used with minification to produce a single, minimally sized JavaScript file to include as normal.

shareimprove this answer
edited Oct 22 at 3:58

bfred.it
5,05132650
answered Jun 4 '09 at 12:13

e-satis
206k76218276
51
not all javascript files are executed in a browser. – Michael Paulukonis Jul 14 '10 at 17:42
62
Nope but somebody that uses something as advanced as Rhino or else wouldn't ask this question. – e-satis Jul 15 '10 at 3:53
99
Just to be complete, there is a third way: In certain solutions when you control both javascript files, you can just make 1 giant javascript file which combines the content of both files. – Toad Sep 7 '12 at 8:36
8
Shouldn't "document.createElement("my_lovely_script.js");" in the example be "document.createElement("script")" ? – Russell Silva Dec 14 '12 at 23:28
4
As a side note, if you use the jQuery one-liner, you will not be able to debug the code because its in VM and will not be visible. If you use the second method, you will have to load your scripts Synchronously, because the first callback will break asynchronous loads. $.when( loadscript('/some/file.js'), loadscript('/some/file2.js') ).done( /*second file is pending, fail.*/ ); – Talvi Watia Jun 7 '13 at 16:18
show 26 more comments
up vote
321
down vote
If anyone is looking for something more advanced, try out RequireJS. You'll get added benefits such as dependency management, better concurrency, and avoid duplication (that is, retrieving a script more than once).

You can write your JavaScript files in "modules" and then reference them as dependencies in other scripts. Or you can use RequireJS as a simple "go get this script" solution.

Example:

Define dependencies as modules:

some-dependency.js

define(['lib/dependency1', 'lib/dependency2'], function (d1, d2) {

//Your actual script goes here.
//The dependent scripts will be fetched if necessary.

return libraryObject; //For example, jQuery object
});
implementation.js is your "main" JavaScript file that depends on some-dependency.js

require(['some-dependency'], function(dependency) {

//Your script goes here
//some-dependency.js is fetched.
//Then your script is executed
});
Excerpt from the GitHub README:

RequireJS loads plain JavaScript files as well as more defined modules. It is optimized for in-browser use, including in a Web Worker, but it can be used in other JavaScript environments, like Rhino and Node. It implements the Asynchronous Module API.

RequireJS uses plain script tags to load modules/files, so it should allow for easy debugging. It can be used simply to load existing JavaScript files, so you can add it to your existing project without having to re-write your JavaScript files.

...
shareimprove this answer
edited Sep 28 '13 at 13:11

Peter Mortensen
9,023106196
answered Jun 7 '12 at 20:55

John Strickler
13.1k33055
6
+1 for citing the right way to do it :-) It would be even better if you included an example! – Sean Vieira Jan 2 '13 at 2:15
6
@Sean per your suggestion - I added a short example – John Strickler Jan 2 '13 at 15:15
25
@aaaidan - perhaps because it was added 3 years after the question was asked... – MattDMo Jun 1 '13 at 17:46
1
@aaaidan: MattDmo's reason plus it relies on an external library which in return rely on the accepted answer. – David Mulder Mar 20 '14 at 21:28
show 4 more comments
up vote
84
down vote
There actually is a way to load a JavaScript file not asynchronously, so you could use the functions included in your newly loaded file right after loading it, and I think it works in all browsers.

You need to use jQuery.append() on the <head> element of your page, that is:

$("head").append('<script type="text/javascript" src="' + script + '"></script>');
However, this method also has a problem: if an error happens in the imported JavaScript file, Firebug (and also Firefox Error Console and Chrome Developer Tools as well) will report its place incorrectly, which is a big problem if you use Firebug to track JavaScript errors down a lot (I do). Firebug simply doesn't know about the newly loaded file for some reason, so if an error occurs in that file, it reports that it occurred in your main HTML file, and you will have trouble finding out the real reason for the error.

But if that is not a problem for you, then this method should work.

I have actually written a jQuery plugin called $.import_js() which uses this method:

(function($)
{
/*
* $.import_js() helper (for JavaScript importing within JavaScript code).
*/
var import_js_imported = [];

$.extend(true,
{
import_js : function(script)
{
var found = false;
for (var i = 0; i < import_js_imported.length; i++)
if (import_js_imported[i] == script) {
found = true;
break;
}

if (found == false) {
$("head").append('<script type="text/javascript" src="' + script + '"></script>');
import_js_imported.push(script);
}
}
});

})(jQuery);
So all you would need to do to import JavaScript is:

$.import_js('/path_to_project/scripts/somefunctions.js');
I also made a simple test for this at http://www.kipras.com/dev/import_js_test/.

It includes a main.js file in the main HTML and then the script in main.js uses $.import_js() to import an additional file called included.js, which defines this function:

function hello()
{
alert("Hello world!");
}
And right after including included.js, the hello() function is called, and you get the alert.

(This answer is in response to e-satis' comment).

shareimprove this answer
edited Jun 7 at 20:33

gsamaras
10k162344
answered Apr 28 '11 at 15:25

Kipras
1,00977
5
@juanpastas - use jQuery.getScript, that way you don't have to worry about writing the plugin... – MattDMo Jun 1 '13 at 17:44
show 3 more comments
up vote
75
down vote
Another way, that in my opinion is much cleaner, is to make a synchronous Ajax request instead of using a <script> tag. Which is also how Node.js handles includes.

Here's an example using jQuery:

function require(script) {
$.ajax({
url: script,
dataType: "script",
async: false, // <-- This is the key
success: function () {
// all good...
},
error: function () {
throw new Error("Could not load script " + script);
}
});
}
You can then use it in your code as you'd usually use an include:

require("/scripts/subscript.js");
And be able to call a function from the required script in the next line:

subscript.doSomethingCool();
shareimprove this answer
edited Sep 28 '13 at 12:55

Peter Mortensen
9,023106196
answered Sep 8 '11 at 18:22

Ariel
2,9961221
1
Good solution, the head include is async unfortunately, the ajax solution works. – Matteo Conta Nov 25 '11 at 9:21
12
As someone else mentioned, requirejs.org does this and also has a pre-compiler that puts js files together so they load faster. You may want to check it out. – Ariel Jan 9 '12 at 6:57
2
Found I could do debug it by adding this directive at the bottom of the file for Chrome : //@ sourceURL=view_index.js – toddv Apr 11 '13 at 0:02
7
unfortunatelly, async:false is now deprecated in jQuery. Might break in the future, so i'd avoid. – sqram Oct 17 '13 at 1:45
2
@katsh We are not using jqXHR objects here. Your quote doesn't seem to back up your previous comment stating that async: false supposedly is deprecated. It is not! As your quote states, only the jqXHR related stuff is. – Zero3 Apr 27 at 16:50
show 9 more comments
up vote
43
down vote
There is a good news for you. Very soon you will be able to load JavaScript code easily. It will become a standard way of importing modules of JavaScript code and will be part of core JavaScript itself.

You simply have to write import cond from 'cond.js'; to load a macro named cond from a file cond.js.

So you don't have to rely upon any JavaScript framework nor do you have to explicitly make Ajax calls.

Refer to:

Static module resolution

Module loaders

shareimprove this answer
edited Oct 19 '14 at 18:05

Peter Mortensen
9,023106196
answered Jul 3 '12 at 13:32

Imdad
3,4971739
4
require/import on the jsfile has been way too long in the coming. (IMO). – rwheadon Apr 10 '13 at 16:12
9
more than a year later - still doesn't exist. =/ – sqram Oct 17 '13 at 1:47
2
@rwheadon yeah seems appalling that this isnt part of the language! How js people get anything done is beyond me! Im new to it and this seems the worst (of many) bits of madness – Jonny Leeds Feb 7 '14 at 12:04
show 4 more comments
up vote
26
down vote
It is possible to dynamically generate a JavaScript tag and append it to HTML document from inside other JavaScript code. This will load targeted JavaScript file.

function includeJs(jsFilePath) {
var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);
}

includeJs("/path/to/some/file.js");
shareimprove this answer
edited Sep 28 '13 at 12:44

Peter Mortensen
9,023106196
answered Jun 4 '09 at 12:02

Svitlana Maksymchuk
1,9321811
1
@e-satis - Actually, this is an advantage, a sync script would be blocking. Horses for courses, but 9 times in 10 you want the non-blocking option. – annakata Jun 4 '09 at 12:15
1
@e-satis asynchronous is good because it wont freeze your page. Use callback to be notified when it's done js.onload = callback; – Vitim.us Aug 23 '13 at 15:40
show 10 more comments
up vote
20
down vote
Maybe you can use this function that I found on this page How do I include a JavaScript file in a JavaScript file?:

function include(filename)
{
var head = document.getElementsByTagName('head')[0];

var script = document.createElement('script');
script.src = filename;
script.type = 'text/javascript';

head.appendChild(script)
}
shareimprove this answer
edited Nov 15 '14 at 17:01

ajeet lakhani
902417
answered Jun 4 '09 at 12:04

Arnaud Gouder
5491418
1
Should be useful to add script.onload = callback; – Vitim.us Aug 23 '13 at 15:37
show 4 more comments
up vote
13
down vote
Here is a synchronous version without jQuery:

function myRequire( url ) {
var ajax = new XMLHttpRequest();
ajax.open( 'GET', url, false ); // <-- the 'false' makes it synchronous
ajax.onreadystatechange = function () {
var script = ajax.response || ajax.responseText;
if (ajax.readyState === 4) {
switch( ajax.status) {
case 200:
eval.apply( window, [script] );
console.log("script loaded: ", url);
break;
default:
console.log("ERROR: script not loaded: ", url);
}
}
};
ajax.send(null);
}
Note that to get this working cross-domain, the server will need to set allow-origin header in its response.

shareimprove this answer
edited Jun 18 at 14:44

Flimm
17.8k85263
answered Dec 11 '13 at 11:54

heinob
3,10021634
1
@heinob : What can I do to get it working for cross-domain? (loading script from http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js) – user2284570 Sep 14 '14 at 2:20
show 5 more comments
up vote
10
down vote
You can also assemble your scripts using PHP:

File main.js.php:

<?php
header('Content-type:text/javascript; charset=utf-8');
include_once("foo.js.php");
include_once("bar.js.php");
?>

// Main JavaScript code goes here
shareimprove this answer
edited Sep 28 '13 at 12:50

Peter Mortensen
9,023106196
answered Dec 27 '10 at 21:03

Calmarius
3,80164386
13
Sounds like the point is to keep this all in javascript in the front end – Ariel Sep 8 '11 at 18:23
1
Thanks for reminding this. You can also have PHP write <script> tags in your HTML header, so that the js files you need (and only those) will be loaded. – Rolf Dec 18 '13 at 12:38
add a comment
up vote
10
down vote
I just wrote this JavaScript code (using Prototype for DOM manipulation):

var require = (function () {
var _required = {};
return (function (url, callback) {
if (typeof url == 'object') {
// We've (hopefully) got an array: time to chain!
if (url.length > 1) {
// Load the nth file as soon as everything up to the
// n-1th one is done.
require(url.slice(0,url.length-1), function () {
require(url[url.length-1], callback);
});
} else if (url.length == 1) {
require(url[0], callback);
}
return;
}
if (typeof _required[url] == 'undefined') {
// Haven't loaded this URL yet; gogogo!
_required[url] = [];

var script = new Element('script', {src:url, type:'text/javascript'});
script.observe('load', function () {
console.log("script " + url + " loaded.");
_required[url].each(function (cb) {
cb.call(); // TODO: does this execute in the right context?
});
_required[url] = true;
});

$$('head')[0].insert(script);
} else if (typeof _required[url] == 'boolean') {
// We already loaded the thing, so go ahead.
if (callback) { callback.call(); }
return;
}

if (callback) { _required[url].push(callback); }
});
})();
Usage:

<script src="prototype.js"></script>
<script src="require.js"></script>
<script>
require(['foo.js','bar.js'], function () {
/* Use foo.js and bar.js here */
});
</script>
Gist: http://gist.github.com/284442.

shareimprove this answer
edited Jun 7 at 20:34

gsamaras
10k162344
answered Jan 23 '10 at 5:20

nornagon
5,710114770
5
jrburke wrote this as RequireJS. Github: requirejs.org/docs/requirements.html – Mike Caron Sep 14 '11 at 17:14
show 1 more comment
up vote
9
down vote
This is perhaps the biggest weakness of JavaScript in my opinion. It's caused me no end of problems over the years with dependency tracing. Anyhow, it does appear that the only practical solution is to use script includes in the HTML file and thus horribly making your JavaScript code dependent upon the user including the source you need and making reuse unfriendly.

Sorry if this comes across as a lecture ;) It's a bad habit of mine, but I want to make a point.

The problem comes back to the same as everything else with the web, the history of JavaScript. It really wasn't designed to be used in the widespread manner it's used in today. Netscape made a language that would allow you to control a few things, but they didn't envisage its widespread use for so many things as it is put to now and for one reason or another it's expanded from there, without addressing some of the fundamental weaknesses of he original strategy.

It's not alone of course. HTML wasn't designed for the modern webpage; it was designed to be a way of expressing the logic of a document, so that readers (browsers in the modern world) could display this in an applicable form that was within the capabilities of the system, and it took years for a solution (other than the hacks of MS and Netscape) to come along. CSS solves this problem, but it was a long time coming and even longer to get people to use it rather than the established BAD techniques. It happened though, praise be.

Hopefully JavaScript (especially now it's part of the standard) will develop to take on board the concept of proper modularity (as well as some other things) as every other (extant) programming language in the world does and this stupidity will go away. Until then you just have to not like it and lump it, I'm afraid.

shareimprove this answer
edited Oct 19 '14 at 18:00

Peter Mortensen
9,023106196
answered May 24 '12 at 9:51

Stephen Whipp
9112
1
"it's part of the standard" :D Good comments though. – Almo Jun 5 '12 at 14:45
1
ecmascript 6 seems like a real programming language. until then, we need to bear with it. – allenhwkim Feb 23 '13 at 18:24
add a comment
up vote
9
down vote
Most of solutions shown here imply dynamical loading. I was searching instead for a compiler which assemble all the depended files into a single output file. The same as Less/Sass preprocessors deal with the CSS @import at-rule. Since I didn't find anything decent of this sort, I wrote a simple tool solving the issue.

So here is the compiler, https://github.com/dsheiko/jsic, which replaces $import("file-path") with the requested file content securely. Here is the corresponding Grunt plugin: https://github.com/dsheiko/grunt-jsic.

On the jQuery master branch, they simply concatenate atomic source files into a single one starting with intro.js and ending with outtro.js. That doesn't suits me as it provides no flexibility on the source code design. Check out how it works with jsic:

src/main.js

var foo = $import("./Form/Input/Tel");
src/Form/Input/Tel.js

function() {
return {
prop: "",
method: function(){}
}
}
Now we can run the compiler:

node jsic.js src/main.js build/mail.js
And get the combined file

build/main.js

var foo = function() {
return {
prop: "",
method: function(){}
}
};
shareimprove this answer
edited Oct 19 '14 at 18:13

Peter Mortensen
9,023106196
answered Jul 13 '13 at 21:44

Dmitry Sheiko
29127
1
Since this post I came up with much better solution - CommonJS module compiler - github.com/dsheiko/cjsc So you can simply write CommonJs or NodeJs modules and access each other yet keeping them in isolated scopes. The benefits: No need of multiple HTTP requests that affect performance You don't need manually wrapping you module code - it is responsibility of the compiler (so better source code readability) You don't need any external libraries It is compatible with UMD- and NodeJs modules (e.g. you can address jQuery, Backbone as modules without touching their code) – Dmitry Sheiko Mar 7 '14 at 16:07
add a comment
up vote
9
down vote
import is in ECMAScript 6

Syntax

import name from "module-name";
import { member } from "module-name";
import { member as alias } from "module-name";
import { member1 , member2 } from "module-name";
import { member1 , member2 as alias2 , [...] } from "module-name";
import name , { member [ , [...] ] } from "module-name";
import "module-name" as name;
shareimprove this answer
answered Apr 17 at 1:56

draupnie
10016
2
You can now write ES6 code and compile it with Babel.js (babeljs.io) to whatever your preferred current module system is (CommonJS/AMD/UMD): babeljs.io/docs/usage/modules – cillosis Jun 12 at 20:35
show 1 more comment
up vote
8
down vote
Or rather than including at run time, use a script to concatenate prior to upload.

I use Sprockets (I don't know if there are others). You build your JavaScript code in separate files and include comments that are processed by the Sprockets engine as includes. For development you can include files sequentially, then for production to merge them...

See also:

Introducing Sprockets: JavaScript dependency management and concatenation
shareimprove this answer
edited Oct 19 '14 at 18:02

Peter Mortensen
9,023106196
answered Jun 7 '12 at 20:48

JMawer
8911
show 1 more comment
up vote
7
down vote
This should do:

xhr = new XMLHttpRequest();
xhr.open("GET", "/soap/ajax/11.0/connection.js", false);
xhr.send();
eval(xhr.responseText);
shareimprove this answer
edited Nov 2 '14 at 13:50

Peter Mortensen
9,023106196
answered Mar 24 '13 at 19:32

tggagne
786812
4
the eval is what's wrong with it. From Crockford, "eval is evil. The eval function is the most misused feature of JavaScript. Avoid it. eval has aliases. Do not use the Function constructor. Do not pass strings to setTimeout or setInterval." If you haven't read his "JavaScript: The Good Parts" then go out and do it right now. You will not regret it. – MattDMo Jun 1 '13 at 17:56
5
@MattDMo "Someone said it was bad" isn't really an argument. – Casey Sep 3 '14 at 19:05
3
@emodendroket I take it you're not aware of who Douglas Crockford is. – MattDMo Sep 3 '14 at 19:24
4
@MattDMo I'm fully aware of who he is, but he's a human being, not a god. – Casey Sep 3 '14 at 19:52
1
@tggagne : What can I do to get it working for cross-domain? (loading script from http://web.archive.org/web/20140905044059/http://www.howtocreate.co.uk/operaStu‌​ff/userjs/aagmfunctions.js) – user2284570 Sep 14 '14 at 2:18
show 1 more comment
up vote
6
down vote
If you want in pure JavaScript, you can use document.write.

document.write('<script src="myscript.js" type="text/javascript"></script>');
If you use the jQuery library, you can use the $.getScript method.

$.getScript("another_script.js");
shareimprove this answer
answered Nov 13 '13 at 9:18

Venu immadi
824414
1
wouldn't document.write remove everything else? – Eisa Adil Jan 14 '14 at 0:53
2
This should not be community wiki. Document.write :( – Nick Sep 6 '14 at 0:27
add a comment
up vote
5
down vote
var js = document.createElement("script");

js.type = "text/javascript";
js.src = jsFilePath;

document.body.appendChild(js);
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#26 dyvniy » Чт, 5 ноября 2015, 19:05:18

clone
http://stackoverflow.com/questions/728360/most-el ... y-to-clone-a-javascript-object

Код: Выделить всё

function clone(obj) {
    if (
null == obj || "object" != typeof obj) return obj;
    var 
copy obj.constructor();
    for (var 
attr in obj) {
        if (
obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
    }
    return 
copy;
}

var 
d1 = new Date();

/* Wait for 5 seconds. */
var start = (new Date()).getTime();
while ((new 
Date()).getTime() - start 5000);


var 
d2 = clone(d1);
alert("d1 = " d1.toString() + "\nd2 = " d2.toString()); 

Спойлер
Most elegant way to clone a JavaScript object

up vote
1006
down vote
favorite
381
I have an object x. I'd like to copy it as object y, such that changes to y do not modify x.

What's the most elegant way of doing this in JavaScript?

Edit: I realize that copying objects derived from built-in JavaScript objects will result in extra, unwanted properties. This isn't a problem, since I'm copying one of my own, literal-constructed objects.

javascript object clone
shareimprove this question
edited Mar 26 '13 at 13:14

community wiki
mindeavor
21
See this question: stackoverflow.com/questions/122102/… – Niyaz Jun 21 '11 at 10:13
75
For JSON, I use mObj=JSON.parse(JSON.stringify(jsonObject)); – Lord Loh. Feb 2 '13 at 10:09
6
lol i never knew objects were not copied but passed by reference. – Muhammad Umer Aug 5 '13 at 3:37
18
@MuhammadUmer - I guess it's lucky you found out now before it bit you on the tucchus! – Slomojo Aug 6 '13 at 6:59
12
I really don't get why no one suggests Object.create(o), it does everything the author asks? – froginvasion Aug 8 '14 at 15:23
show 8 more comments
38 Answers
activeoldestvotes
1 2 next
up vote
698
down vote
accepted
To do this for any object in JavaScript will not be simple or straightforward. You will run into the problem of erroneously picking up attributes from the object's prototype that should be left in the prototype and not copied to the new instance. If, for instance, you are adding a clone method to Object.prototype, as some answers depict, you will need to explicitly skip that attribute. But what if there are other additional methods added to Object.prototype, or other intermediate prototypes, that you don't know about? In that case, you will copy attributes you shouldn't, so you need to detect unforeseen, non-local attributes with the hasOwnProperty method.

In addition to non-enumerable attributes, you'll encounter a tougher problem when you try to copy objects that have hidden properties. For example, prototype is a hidden property of a function. Also, an object's prototype is referenced with the attribute __proto__, which is also hidden, and will not be copied by a for/in loop iterating over the source object's attributes. I think __proto__ might be specific to Firefox's JavaScript interpreter and it may be something different in other browsers, but you get the picture. Not everything is enumerable. You can copy a hidden attribute if you know its name, but I don't know of any way to discover it automatically.

Yet another snag in the quest for an elegant solution is the problem of setting up the prototype inheritance correctly. If your source object's prototype is Object, then simply creating a new general object with {} will work, but if the source's prototype is some descendant of Object, then you are going to be missing the additional members from that prototype which you skipped using the hasOwnProperty filter, or which were in the prototype, but weren't enumerable in the first place. One solution might be to call the source object's constructor property to get the initial copy object and then copy over the attributes, but then you still will not get non-enumerable attributes. For example, a Date object stores its data as a hidden member:

function clone(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = obj[attr];
}
return copy;
}

var d1 = new Date();

/* Wait for 5 seconds. */
var start = (new Date()).getTime();
while ((new Date()).getTime() - start < 5000);


var d2 = clone(d1);
alert("d1 = " + d1.toString() + "\nd2 = " + d2.toString());
The date string for d1 will be 5 seconds behind that of d2. A way to make one Date the same as another is by calling the setTime method, but that is specific to the Date class. I don't think there is a bullet-proof general solution to this problem, though I would be happy to be wrong!

When I had to implement general deep copying I ended up compromising by assuming that I would only need to copy a plain Object, Array, Date, String, Number, or Boolean. The last 3 types are immutable, so I could perform a shallow copy and not worry about it changing. I further assumed that any elements contained in Object or Array would also be one of the 6 simple types in that list. This can be accomplished with code like the following:

function clone(obj) {
var copy;

// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;

// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}

// Handle Array
if (obj instanceof Array) {
copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = clone(obj[i]);
}
return copy;
}

// Handle Object
if (obj instanceof Object) {
copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = clone(obj[attr]);
}
return copy;
}

throw new Error("Unable to copy obj! Its type isn't supported.");
}
The above function will work adequately for the 6 simple types I mentioned, as long as the data in the objects and arrays form a tree structure. That is, there isn't more than one reference to the same data in the object. For example:

// This would be cloneable:
var tree = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"right" : null,
"data" : 8
};

// This would kind-of work, but you would get 2 copies of the
// inner node instead of 2 references to the same copy
var directedAcylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
directedAcyclicGraph["right"] = directedAcyclicGraph["left"];

// Cloning this would cause a stack overflow due to infinite recursion:
var cylicGraph = {
"left" : { "left" : null, "right" : null, "data" : 3 },
"data" : 8
};
cylicGraph["right"] = cylicGraph;
It will not be able to handle any JavaScript object, but it may be sufficient for many purposes as long as you don't assume that it will just work for anything you throw at it.

shareimprove this answer
edited Oct 6 at 11:20

community wiki
8 revs, 5 users 89%
A. Levy
2
@javierfp: I think it is reachable. The instanceof operator works by checking the objects prototype chain (according to the Mozilla Javascript reference: developer.mozilla.org/en/JavaScript/Reference/Operators/Special/…). I suppose that someone could modify the prototype chain to no longer include Object. That would be unusual, but would cause the error to be thrown. – A. Levy Jan 21 '11 at 21:44
5
almost worked fine in a nodejs - just had to change the line for (var i = 0, var len = obj.length; i < len; ++i) { to for (var i = 0; i < obj.length; ++i) { – Trindaz Mar 28 '12 at 0:08
4
For future googlers: same deep copy, passing references recursively instead of using 'return' statements at gist.github.com/2234277 – Trindaz Mar 29 '12 at 6:48
1
Missing opening bracket in the "Wait for 5 seconds" while loop. – marcv Sep 8 '13 at 10:01
3
In the first snippet, are you sure it shouldn't be var cpy = new obj.constructor()? – cyon Nov 29 '14 at 3:29
show 16 more comments
up vote
395
down vote
With jQuery, you can shallow copy with:

var copiedObject = jQuery.extend({}, originalObject)
subsequent changes to the copiedObject will not affect the originalObject, and vice versa.

Or to make a deep copy:

var copiedObject = jQuery.extend(true, {}, originalObject)
shareimprove this answer
edited Sep 14 at 17:24

community wiki
4 revs, 4 users 42%
Pascal
147
or even: var copiedObject = jQuery.extend({},originalObject); – Grant McLean May 8 '11 at 2:11
68
Also useful to specify true as the first param for deep copy: jQuery.extend(true, {}, originalObject); – Will Shaver Jun 21 '11 at 0:19
5
Yes, I found this link helpful (same solution as Pascal) stackoverflow.com/questions/122102/… – Garry English Nov 16 '11 at 16:31
show 4 more comments
up vote
213
down vote
If you do not use functions within your object, a very simple one liner can be the following:

var cloneOfA = JSON.parse(JSON.stringify(a));
This works for all kind of objects containing objects, arrays, strings, booleans and numbers.

See also this article about the structured clone algorythm of browsers which is used when posting messages to and from a worker. It also contains a function for deep cloning.

shareimprove this answer
edited Jun 17 at 19:32

community wiki
8 revs
heinob
17
Note that this can only be used for testing. Firstly, it's far from optimal in terms of time and memory consumption. Secondly, not all browsers have this methods. – Nux Aug 12 '13 at 18:56
2
You could always include JSON2.js or JSON3.js. You would need them for your app anyway. But I do agree this might not be the best solution, since JSON.stringify does not include inherited properties. – Tim Hong Feb 13 '14 at 6:44
1
Doesn't work for functions though. – Harold May 1 '14 at 20:15
7
@Nux, Why not optimal in terms of time and memory? MiJyn says: "The reason why this method is slower than shallow copying (on a deep object) is that this method, by definition, deep copies. But since JSON is implemented in native code (in most browsers), this will be considerably faster than using any other javascript-based deep copying solution, and may sometimes be faster than a javascript-based shallow copying technique (see: jsperf.com/cloning-an-object/79)." stackoverflow.com/questions/122102/… – BeauCielBleu May 14 '14 at 15:27
5
I just want to add an update to this for Oct. 2014. Chrome 37+ is faster with JSON.parse(JSON.stringify(oldObject)); The benefit of using this is that it's very easy for a javascript engine to see and optimize into something better if it wants. – mirhagk Oct 7 '14 at 21:08
show 10 more comments
up vote
75
down vote
There are many answers, but none that mentions Object.create from ECMAScript 5, which admittedly does not give you an exact copy, but sets the source as the prototype of the new object.

Thus, this is not an exact answer to the question, but it is a one-line solution and thus elegant. And it works best for 2 cases:

Where such inheritance is useful (duh!)
Where the source object won't be modified, thus making the relation between the 2 objects a non issue.
Example:

var foo = { a : 1 };
var bar = Object.create(foo);
foo.a; // 1
bar.a; // 1
foo.a = 2;
bar.a; // 2 - prototype changed
bar.a = 3;
foo.a; // Still 2, since setting bar.a makes it an "own" property
Why do I consider this solution to be superior? It's native, thus no looping, no recursion. However, older browsers will need a polyfill.

shareimprove this answer
answered Mar 19 '12 at 15:17

community wiki
itpastorn
26
This is prototypal inheritance, not cloning. These are completely different things. The new object doesn't have any of it's own properties, it just points to the prototype's properties. The point of cloning is to create a fresh new object that doesn't reference any properties in another object. – d13 Jan 16 '14 at 16:18
1
I agree with you completely. I do agree as well that this is not cloning as might be 'intended'. But come on people, embrace the nature of JavaScript instead of trying to find obscure solutions that are not standardized. Sure, you don't like prototypes and they are all "blah" to you, but they are in fact very useful if you know what you're doing. – froginvasion Aug 8 '14 at 15:26
1
@RobG:This article explains the difference between referencing and cloning: en.wikipedia.org/wiki/Cloning_(programming). Object.create points to the parent's properties through references.That means if the parent's property values change, the child's will also change. This has some surprising side-effects with nested arrays and objects that could lead to hard-to-find bugs in your code if you're not aware of them: jsbin.com/EKivInO/2. A cloned object is a completely new, independent object that has the same properties and values as the parent, but isn't connected to the parent. – d13 Dec 2 '14 at 14:08
show 8 more comments
up vote
43
down vote
If you're okay with a shallow copy, the underscore.js library has a clone method.

y = _.clone(x);
or you can extend it like

copiedObject = _.extend({},originalObject);
shareimprove this answer
edited Jan 19 at 18:47

community wiki
2 revs, 2 users 50%
dule
14
And lodash has a cloneDeep – dule Jun 4 '13 at 0:11
2
Thanks. Using this technique on a Meteor server. – Turbo Apr 1 at 4:30
add a comment
up vote
17
down vote
A.Levy's answer is almost complete, here is my little contribution: there is a way how to handle recursive references, see this line

if(this[attr]==this) copy[attr] = copy;

If the object is XML DOM element, we must use cloneNode instead

if(this.cloneNode) return this.cloneNode(true);

Inspired by A.Levy's exhaustive study and Calvin's prototyping approach, I offer this solution:

Object.prototype.clone = function() {
if(this.cloneNode) return this.cloneNode(true);
var copy = this instanceof Array ? [] : {};
for(var attr in this) {
if(typeof this[attr] == "function" || this[attr]==null || !this[attr].clone)
copy[attr] = this[attr];
else if(this[attr]==this) copy[attr] = copy;
else copy[attr] = this[attr].clone();
}
return copy;
}

Date.prototype.clone = function() {
var copy = new Date();
copy.setTime(this.getTime());
return copy;
}

Number.prototype.clone =
Boolean.prototype.clone =
String.prototype.clone = function() {
return this;
}
See also Andy Burke's note in the answers.

shareimprove this answer
edited Dec 2 '12 at 20:49

community wiki
Jan Turoň
2
Date.prototype.clone = function() {return new Date(+this)}; – RobG Dec 2 '14 at 12:20
show 1 more comment
up vote
17
down vote
There are several issues with most solutions on the internet. So I decided to make a follow-up, which includes, why the accepted answer shouldn't be accepted.

starting situation

I want to deep-copy a Javascript Object with all of its children and their children and so on. But since I'm not kind of a normal developer, my Object has normal properties, circular structures and even nested objects.

So let's create a circular structure and a nested object first.

function Circ() {
this.me = this;
}

function Nested(y) {
this.y = y;
}
Let's bring everything together in an Object named a.

var a = {
x: 'a',
circ: new Circ(),
nested: new Nested('a')
};
Next we want to copy a into a variable named b and mutate it.

var b = a;

b.x = 'b';
b.nested.y = 'b';
You know what happened here, because if not you wouldn't even landed on this great question.

console.log(a, b);

a --> Object {
x: "b",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}

b --> Object {
x: "b",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}
Now let's find a solution.

JSON

The first attempt I tried was using JSON.

var b = JSON.parse( JSON.stringify( a ) );

b.x = 'b';
b.nested.y = 'b';
Don't waste too much time on it, you'll get TypeError: Converting circular structure to JSON.

Recursive copy (the accepted "answer")

Let's have a look at the accepted answer.

function cloneSO(obj) {
// Handle the 3 simple types, and null or undefined
if (null == obj || "object" != typeof obj) return obj;

// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}

// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0, len = obj.length; i < len; i++) {
copy[i] = cloneSO(obj[i]);
}
return copy;
}

// Handle Object
if (obj instanceof Object) {
var copy = {};
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = cloneSO(obj[attr]);
}
return copy;
}

throw new Error("Unable to copy obj! Its type isn't supported.");
}
Looks good, heh? It's a recursive copy of the object and handles other types as well, like Date, but that wasn't a requirement.

var b = cloneSO(a);

b.x = 'b';
b.nested.y = 'b';
Recursion and circular structures doesn't work well together... RangeError: Maximum call stack size exceeded

native solution

After arguing with my co-worker, my boss asked us what happend, and he found a simple solution after some googling. It's called Object.create.

var b = Object.create(a);

b.x = 'b';
b.nested.y = 'b';
This solution was added to Javascript some time ago and even handles circular structure.

console.log(a, b);

a --> Object {
x: "a",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}

b --> Object {
x: "b",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}
... and you see, it didn't work with the nested structure inside.

polyfill for the native solution

There's a polyfill for Object.create in older browser just like the IE 8. It's something like recommended by Mozilla, and of course it's not perfect and results in the same problem as the native solution.

function F() {};
function clonePF(o) {
F.prototype = o;
return new F();
}

var b = clonePF(a);

b.x = 'b';
b.nested.y = 'b';
I've put F outside the scope so we can have a look at what instanceof tells us.

console.log(a, b);

a --> Object {
x: "a",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}

b --> F {
x: "b",
circ: Circ {
me: Circ { ... }
},
nested: Nested {
y: "b"
}
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> true
Same problem as the native solution, but a little bit worse output.

the better (but not perfect) solution

When digging around, I found a similiar question (In Javascript, when performing a deep copy, how do I avoid a cycle, due to a property being "this"?) to this one, but with a way better solution.

function cloneDR(o) {
const gdcc = "__getDeepCircularCopy__";
if (o !== Object(o)) {
return o; // primitive value
}

var set = gdcc in o,
cache = o[gdcc],
result;
if (set && typeof cache == "function") {
return cache();
}
// else
o[gdcc] = function() { return result; }; // overwrite
if (o instanceof Array) {
result = [];
for (var i=0; i<o.length; i++) {
result[i] = cloneDR(o[i]);
}
} else {
result = {};
for (var prop in o)
if (prop != gdcc)
result[prop] = cloneDR(o[prop]);
else if (set)
result[prop] = cloneDR(cache);
}
if (set) {
o[gdcc] = cache; // reset
} else {
delete o[gdcc]; // unset again
}
return result;
}

var b = cloneDR(a);

b.x = 'b';
b.nested.y = 'b';
And let's have a look at the output...

console.log(a, b);

a --> Object {
x: "a",
circ: Object {
me: Object { ... }
},
nested: Object {
y: "a"
}
}

b --> Object {
x: "b",
circ: Object {
me: Object { ... }
},
nested: Object {
y: "b"
}
}

console.log(typeof a, typeof b);

a --> object
b --> object

console.log(a instanceof Object, b instanceof Object);

a --> true
b --> true

console.log(a instanceof F, b instanceof F);

a --> false
b --> false
The requirements are matched, but there are still some smaller issues, including changing the instance of nested andcirc to Object.

The structure of trees that share a leaf won't be copied, they will become two independent leafes:
[Object] [Object]
/ \ / \
/ \ / \
|/_ _\| |/_ _\|
[Object] [Object] ===> [Object] [Object]
\ / | |
\ / | |
_\| |/_ \|/ \|/
[Object] [Object] [Object]
conclusion

The last solution using recursion and a cache, may not be the best, but it's a real deep-copy of the object. It handles simple properties, circular structures and nested object, but it will mess up the instance of them while cloning.

http://jsfiddle.net/einfallstoll/N4mr2/

shareimprove this answer
edited Jul 9 '14 at 8:48

community wiki
2 revs
Fabio Poloni
1
so the conlcusion is to avoid that problem :) – mikus Oct 23 '14 at 11:39
show 1 more comment
up vote
14
down vote
One particular "un-elegant" solution is to use JSON encoding to make deep copies of objects that do not have member methods. The methodology is to JSON encode your target object, then by decoding it, you get the copy you are looking for. You can decode as many times as you want to make as many copies as you need.

Of course, functions do not belong in JSON, so this only works for objects without member methods.

This methodology was perfect for my use case, since I'm storing JSON blobs in a key-value store, and when they are exposed as objects in a JavaScript API, each object actually contains a copy of the original state of the object so we can calculate the delta after the caller has mutated the exposed object.

shareimprove this answer
answered Oct 29 '09 at 20:24

community wiki
Kris Walker
3
Functions are not part of the JSON spec becuase they are not a secure (or smart) way to transfer data, which is what JSON was made for. I know the native JSON encoder in Firefox simply ignores functions passed to it, but I'm not sure about the behavior of others. – Kris Walker Oct 30 '09 at 10:27
26
There's nothing more inelegant than the use of the word unelegant. – Kevin Laity Jan 26 '12 at 20:18
1
@mark: { 'foo': function() { return 1; } } is a literal-constructed object. – abarnert Aug 14 '12 at 1:58
show 3 more comments
up vote
13
down vote
In ECMAScript 6 there is Object.assign method, which copies values of all enumerable own properties from one object to another. For example:

var x = {myProp: "value"};
var y = Object.assign({}, x);
shareimprove this answer
edited Jun 29 at 18:59

community wiki
2 revs, 2 users 91%
Vitalii Fedorenko
add a comment
up vote
12
down vote
For those using AngularJS, there is also direct method for cloning or extending of the objects in this library.

var destination = angular.copy(source);
or

angular.copy(source, destination);
More in angular.copy documentation...

shareimprove this answer
answered Sep 3 '14 at 19:08

community wiki
Lukas Jelinek
1
This is a deep copy FYI. – zamnuts Sep 19 '14 at 10:27
add a comment
up vote
11
down vote
Here is a function you can use.

function clone(obj) {
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = new obj.constructor();
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
shareimprove this answer
edited Feb 23 '12 at 20:04

community wiki
picardo
5
This answer is pretty close, but not quite correct. If you try cloning a Date object, you will not get the same date because the call to the Date constructor function initializes the new Date with the current date/time. That value isn't enumerable and won't be copied by the for/in loop. – A. Levy Apr 8 '09 at 4:21
show 2 more comments
up vote
11
down vote
You can clone an object and remove any reference from the previous one using a single line of code. Simply do:

var obj1 = { text: 'moo1' };
var obj2 = Object.create(obj1); // Creates a new clone without references

obj2.text = 'moo2'; // Only updates obj2's text property

console.log(obj1, obj2); // Outputs: obj1: {text:'moo1'}, obj2: {text:'moo2'}
For browsers / engines that do not currently support Object.create you can use this polyfill:

// Polyfill Object.create if it does not exist
if (!Object.create) {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
shareimprove this answer
edited Sep 16 '12 at 5:27

community wiki
Rob Evans
1
+1 Object.create(...) seems definitely the way to go. – René Nyffenegger Jun 30 '14 at 14:49
4
This is creating obj2 with a obj1 as it's prototype. It only works because you are shadowing the text member in obj2. You are not making a copy, just deferring to the prototype chain when a member is not found on obj2. – Nick Desaulniers Oct 31 '14 at 21:25
show 4 more comments
up vote
9
down vote
From this article: How to copy arrays and objects in Javascript by Brian Huisman:

Object.prototype.clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (var i in this) {
if (i == 'clone') continue;
if (this[i] && typeof this[i] == "object") {
newObj[i] = this[i].clone();
} else newObj[i] = this[i]
} return newObj;
};
shareimprove this answer
edited Sep 22 '12 at 22:06

community wiki
Calvin
3
This is close, but doesn't work for any object. Try cloning a Date object with this. Not all properties are enumerable, so they will not all show up in the for/in loop. – A. Levy Apr 8 '09 at 4:17
2
@iPadDeveloper2011 The code above had a bug in it where it created a global variable called 'i' '(for i in this)', rather than '(for var i in this)'. I have enough karma to edit and it and fix it so I did. – mikemaccana Sep 22 '12 at 22:09
1
@Calvin: this should be created an a non-enumerable property, otherwise 'clone' will appear in 'for' loops. – mikemaccana Oct 1 '12 at 10:54
1
why isn't var copiedObj = Object.create(obj); a great way as well? – Dany Apr 12 '14 at 20:16
show 1 more comment
up vote
5
down vote
Jan Turoň's answer above is very close, and may be the best to use in a browser due to compatibility issues, but it will potentially cause some strange enumeration issues. For instance, executing:

for ( var i in someArray ) { ... }
Will assign the clone() method to i after iterating through the elements of the array. Here's an adaptation that avoids the enumeration and works with node.js:

Object.defineProperty( Object.prototype, "clone", {
value: function() {
if ( this.cloneNode )
{
return this.cloneNode( true );
}

var copy = this instanceof Array ? [] : {};
for( var attr in this )
{
if ( typeof this[ attr ] == "function" || this[ attr ] == null || !this[ attr ].clone )
{
copy[ attr ] = this[ attr ];
}
else if ( this[ attr ] == this )
{
copy[ attr ] = copy;
}
else
{
copy[ attr ] = this[ attr ].clone();
}
}
return copy;
}
});

Object.defineProperty( Date.prototype, "clone", {
value: function() {
var copy = new Date();
copy.setTime( this.getTime() );
return copy;
}
});

Object.defineProperty( Number.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( Boolean.prototype, "clone", { value: function() { return this; } } );
Object.defineProperty( String.prototype, "clone", { value: function() { return this; } } );
This avoids making the clone() method enumerable because defineProperty() defaults enumerable to false.

shareimprove this answer
answered Mar 30 '12 at 6:03

community wiki
Andy Burke
add a comment
up vote
4
down vote
Using Lodash:

var y = _.clone(x, true);
shareimprove this answer
answered Dec 13 '12 at 0:05

community wiki
VaZaA
show 2 more comments
up vote
3
down vote
function clone(src, deep) {

var toString = Object.prototype.toString;
if(!src && typeof src != "object"){
//any non-object ( Boolean, String, Number ), null, undefined, NaN
return src;
}

//Honor native/custom clone methods
if(src.clone && toString.call(src.clone) == "[object Function]"){
return src.clone(deep);
}

//DOM Elements
if(src.nodeType && toString.call(src.cloneNode) == "[object Function]"){
return src.cloneNode(deep);
}

//Date
if(toString.call(src) == "[object Date]"){
return new Date(src.getTime());
}

//RegExp
if(toString.call(src) == "[object RegExp]"){
return new RegExp(src);
}

//Function
if(toString.call(src) == "[object Function]"){
//Wrap in another method to make sure == is not true;
//Note: Huge performance issue due to closures, comment this :)
return (function(){
src.apply(this, arguments);
});

}

var ret, index;
//Array
if(toString.call(src) == "[object Array]"){
//[].slice(0) would soft clone
ret = src.slice();
if(deep){
index = ret.length;
while(index--){
ret[index] = clone(ret[index], true);
}
}
}
//Object
else {
ret = src.constructor ? new src.constructor() : {};
for (var prop in src) {
ret[prop] = deep
? clone(src[prop], true)
: src[prop];
}
}

return ret;
};
shareimprove this answer
edited Jul 31 '12 at 20:53

community wiki
user1547016
1
if(!src && typeof src != "object"){. I think that should be || not &&. – MikeM Apr 8 '13 at 9:34
show 2 more comments
up vote
3
down vote
Since mindeavor stated that the object to be cloned is a 'literal-constructed' object, a solution might be to simply generate the object multiple times rather than cloning an instance of the object:

function createMyObject()
{
var myObject =
{
...
};
return myObject;
}

var myObjectInstance1 = createMyObject();
var myObjectInstance2 = createMyObject();
shareimprove this answer
answered Nov 28 '12 at 18:48

community wiki
Bert Regelink
add a comment
up vote
2
down vote
If there are no circular dependencies in your object, I suggest using one of the other answers or jQuery's copy methods, as they all seem quite effective.

If there are circular dependencies (i.e., two sub-objects link to each other), you are kind of screwed as there is (from a theoretical perspective) no way to solve this issue elegantly.

shareimprove this answer
answered Apr 8 '09 at 3:16

community wiki
Daniel Lew
2
Actually, Python's object serialization handles circular references by keeping track of nodes in the object graph that it has already processed. You could use that approach to implement a robust copy routine. It would be a little more work though! – A. Levy May 20 '10 at 18:21
add a comment
up vote
2
down vote
Using Prototype framework:

var y = Object.clone(x);
Considering clone implementation:

...
Object.extend = function(destination, source) {
for (var property in source)
destination[property] = source[property];
return destination;
};
...
clone: function(object) {
return Object.extend({ }, object);
}
...
shareimprove this answer
answered Apr 8 '09 at 3:20

community wiki
Sepehr Lajevardi
12
this Date object is killing all answers! – Sepehr Lajevardi Apr 10 '09 at 22:37
show 1 more comment
up vote
2
down vote
You can use functional closure to gain all the benefits of a deep copy, without a deep copy. It's a very different paradigm, but works well. Instead of trying to copy an existing object, just use a function to instantiate a new object when you need one.

First, create an function that returns an object

function template() {
return {
values: [1, 2, 3],
nest: {x: {a: "a", b: "b"}, y: 100}
};
}
Then create a simple shallow copy function

function copy(a, b) {
Object.keys(b).forEach(function(key) {
a[key] = b[key];
});
}
Create a new object, and copy the template's properties onto it

var newObject = {};
copy(newObject, template());
But the above copy step is not necessary. All you need to do is this:

var newObject = template();
Now that you have a new object, test to see what its properties are:

console.log(Object.keys(newObject));
This displays:

["values", "nest"]
Yes, those are the newObject's own properties, not references to properties on another object. Let's just check:

console.log(newObject.nest.x.b);
This displays:

"b"
The newObject has acquired all of the template object's properties, but is free of any dependency chain.

http://jsbin.com/ISUTIpoC/1/edit?js,console

I added this example to encourage some debate, so please add some comments :)

shareimprove this answer
edited Jan 20 '14 at 22:00

community wiki
2 revs
d13
show 1 more comment
up vote
2
down vote
I've written my own implementation. Not sure if it counts as a better solution:

/*
a function for deep cloning objects that contains other nested objects and circular structures.
objects are stored in a 3D array, according to their length (number of properties) and their depth in the original object.
index (z)
|
|
|
|
|
| depth (x)
|_ _ _ _ _ _ _ _ _ _ _ _
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/_/_/_/
/_/_/_/_/_/_/...../
/................./
/..... /
/ /
/------------------
object length (y) /
*/


function deepClone(obj) {
var i = -1, //depth of the current object relative to the passed 'obj'
j = 0; //number of the object's properties
var arr = new Array(); //3D array to store the references to objects
return clone(obj, arr, i, j);
}

function clone(obj, arr, i ,j){
if (typeof obj !== "object") {
return obj;
}

var result = Object.create(Object.getPrototypeOf(obj)); //inherit the prototype of the original object
if(result instanceof Array){
result.length = Object.keys(obj).length;
}

i++; //depth is increased because we entered an object here
j = Object.keys(obj).length; //native method to get the number of properties in 'obj'
arr[i] = new Array(); //this is the x-axis, each index here is the depth
arr[i][j] = new Array(); //this is the y-axis, each index is the length of the object (aka number of props)
//start the depth at current and go down, cyclic structures won't form on depths more than the current one
for(var depth = i; depth >= 0; depth--){
//loop only if the array at this depth and length already have elements
if(arr[depth][j]){
for(var index = 0; index < arr[depth][j].length; index++){
if(obj === arr[depth][j][index]){
return obj;
}
}
}
}

arr[i][j].push(obj); //store the object in the array at the current depth and length
for (var prop in obj) {
result[prop] = clone(obj[prop], arr, i, j);
}

return result;
}
shareimprove this answer
answered Nov 12 '14 at 1:25

community wiki
yazjisuhail
add a comment
up vote
1
down vote
I just wanted to add to all the Object.create solutions in this post, that this does not work in the desired way with nodejs.

In Firefox the result of

var a = {"test":"test"};
var b = Object.create(a);
console.log(b);´
is

{test:"test"}.

In nodejs it is

{}
shareimprove this answer
answered Jun 3 '12 at 9:29

community wiki
heinob
1
@d13 while your argument is valid, note that there is no standardized way in JavaScript to clone an object. This is prototypical inheritance, but it can be used as clones nevertheless if you understand the concepts. – froginvasion Aug 8 '14 at 15:28
show 4 more comments
up vote
1
down vote
This is an adaptation of A. Levy's code to also handle the cloning of functions and multiple/cyclic references - what this means is that if two properties in the tree which is cloned are references of the same object, the cloned object tree will have these properties point to one and the same clone of the referenced object. This also solves the case of cyclic dependencies which, if left unhandled, leads to an infinite loop. The complexity of the algorithm is O(n)

function clone(obj){
var clonedObjectsArray = [];
var originalObjectsArray = []; //used to remove the unique ids when finished
var next_objid = 0;

function objectId(obj) {
if (obj == null) return null;
if (obj.__obj_id == undefined){
obj.__obj_id = next_objid++;
originalObjectsArray[obj.__obj_id] = obj;
}
return obj.__obj_id;
}

function cloneRecursive(obj) {
if (null == obj || typeof obj == "string" || typeof obj == "number" || typeof obj == "boolean") return obj;

// Handle Date
if (obj instanceof Date) {
var copy = new Date();
copy.setTime(obj.getTime());
return copy;
}

// Handle Array
if (obj instanceof Array) {
var copy = [];
for (var i = 0; i < obj.length; ++i) {
copy[i] = cloneRecursive(obj[i]);
}
return copy;
}

// Handle Object
if (obj instanceof Object) {
if (clonedObjectsArray[objectId(obj)] != undefined)
return clonedObjectsArray[objectId(obj)];

var copy;
if (obj instanceof Function)//Handle Function
copy = function(){return obj.apply(this, arguments);};
else
copy = {};

clonedObjectsArray[objectId(obj)] = copy;

for (var attr in obj)
if (attr != "__obj_id" && obj.hasOwnProperty(attr))
copy[attr] = cloneRecursive(obj[attr]);

return copy;
}


throw new Error("Unable to copy obj! Its type isn't supported.");
}
var cloneObj = cloneRecursive(obj);



//remove the unique ids
for (var i = 0; i < originalObjectsArray.length; i++)
{
delete originalObjectsArray[i].__obj_id;
};

return cloneObj;
}
Some quick tests

var auxobj = {
prop1 : "prop1 aux val",
prop2 : ["prop2 item1", "prop2 item2"]
};

var obj = new Object();
obj.prop1 = "prop1_value";
obj.prop2 = [auxobj, auxobj, "some extra val", undefined];
obj.nr = 3465;
obj.bool = true;

obj.f1 = function (){
this.prop1 = "prop1 val changed by f1";
};

objclone = clone(obj);

//some tests i've made
console.log("test number, boolean and string cloning: " + (objclone.prop1 == obj.prop1 && objclone.nr == obj.nr && objclone.bool == obj.bool));

objclone.f1();
console.log("test function cloning 1: " + (objclone.prop1 == 'prop1 val changed by f1'));
objclone.f1.prop = 'some prop';
console.log("test function cloning 2: " + (obj.f1.prop == undefined));

objclone.prop2[0].prop1 = "prop1 aux val NEW";
console.log("test multiple references cloning 1: " + (objclone.prop2[1].prop1 == objclone.prop2[0].prop1));
console.log("test multiple references cloning 2: " + (objclone.prop2[1].prop1 != obj.prop2[0].prop1));
shareimprove this answer
edited Jul 16 '12 at 9:23

community wiki
Radu Simionescu
add a comment
up vote
1
down vote
One thing is certain... there is no elegant way. My contribution here is this link http://oranlooney.com/deep-copy-javascript/

I think this library is the most comprehensive and elegant solution. It is particularly focused on the prototype chain of the cloned objects. It includes a mechanism to easy describe custom cloning behavior for particular classes. The author explains that most of the time the default cloning mechanism which is provided works fine.

It also clones functions and handles cycles or multiple references.

I have recently suggested the author a solution to optimize the mechanism which handles cycles, from O(n^2) to O(n).

shareimprove this answer
edited Jul 16 '12 at 9:28

community wiki
Radu Simionescu
add a comment
up vote
1
down vote
Consult http://www.w3.org/html/wg/drafts/html/master/infr ... afe-passing-of-structured-data for the W3C's "Safe passing of structured data" algorithm, intended to be implemented by browsers for passing data to eg web workers. However, it has some limitations, in that it does not handle functions. See https://developer.mozilla.org/en-US/docs/DOM/The_structured_clone_algorithm for more information, including an alternative algorithm in JS which gets you part of the way there.

shareimprove this answer
answered Apr 16 '13 at 2:56

community wiki
torazaburo
show 1 more comment
up vote
1
down vote
Interested in cloning simple objects :

JSON.parse(JSON.stringify(json_original));

Source : How to copy JavaScript object to new variable NOT by reference?

shareimprove this answer
answered Aug 27 at 9:20

community wiki
Mohammed Akdim
add a comment
up vote
0
down vote
I came to this page due to the same question but I'm neither using JQuery and none of the clone-Methods worked for my own objects.

I'm aware my answer isn't related too strong to this question because it's a different approach. Instead of using clone-functions I use a create function. It worked for me for the following (unfortunately restricting) purposes:

I use mostly JSP-generated Javascript
I know in the beginning which Object must be generated (In my case it's Information from a Database which gets fetched once and needs to be deployed more often in the JS.
First I defined my Objects like this:

var obj= new Object();
obj.Type='Row';
obj.ID=1;
obj.Value='Blah blah';
Now I moved everything like:

function getObjSelektor(id_nummer,selected){
var obj = document.createElement("select");
obj.setAttribute("id","Selektor_"+id_nummer);
obj.setAttribute("name","Selektor");
obj.setAttribute("size","1");

var obj_opt_1 = document.createElement("option");
obj_opt_1.setAttribute("value","1");
if(1==selected)
posopval_opt_1.setAttribute("selected","selected");
obj_opt_1.innerHTML="Blah blah";
obj.appendChild(obj_opt_1);

var obj_opt_2 = document.createElement("option");
obj_opt_2.setAttribute("value","2");
if(2==selected)
obj_opt_2.setAttribute("selected","selected");
obj_opt_2.innerHTML="2nd Row";
obj.appendChild(obj_opt_2);

...

return obj;
}
And call the function in the regular code:

myDiv.getObjSelektor(getObjSelektor(anotherObject.ID));
As said this is a different approach which solved my issue for my purposes.

shareimprove this answer
answered Sep 7 '13 at 14:23

community wiki
Qohelet
add a comment
up vote
0
down vote
If you got an Object with Functions you can do it with JSONfn, see http://www.eslinstructor.net/jsonfn/.

var obj= {
name:'Marvin',
getName : function(){
return this.name;
}
}
var cobj = JSONfn.parse(JSONfn.stringify(obj));
shareimprove this answer
answered Sep 25 '13 at 6:48

community wiki
basis
add a comment
up vote
0
down vote
//
// creates 'clone' method on context object
//
// var
// clon = Object.clone( anyValue );
//
!((function (propertyName, definition) {
this[propertyName] = definition();
}).call(
Object,
"clone",
function () {
function isfn(fn) {
return typeof fn === "function";
}

function isobj(o) {
return o === Object(o);
}

function isarray(o) {
return Object.prototype.toString.call(o) === "[object Array]";
}

function fnclon(fn) {
return function () {
fn.apply(this, arguments);
};
}

function owns(obj, p) {
return obj.hasOwnProperty(p);
}

function isemptyobj(obj) {
for (var p in obj) {
return false;
}
return true;
}

function isObject(o) {
return Object.prototype.toString.call(o) === "[object Object]";
}
return function (input) {
if (isfn(input)) {
return fnclon(input);
} else if (isobj(input)) {
var cloned = {};
for (var p in input) {
owns(Object.prototype, p)
|| (
isfn(input[p])
&& ( cloned[p] = function () { return input[p].apply(input, arguments); } )
|| ( cloned[p] = input[p] )
);
}
if (isarray(input)) {
cloned.length = input.length;
"concat every filter forEach indexOf join lastIndexOf map pop push reduce reduceRight reverse shift slice some sort splice toLocaleString toString unshift"
.split(" ")
.forEach(
function (methodName) {
isfn( Array.prototype[methodName] )
&& (
cloned[methodName] =
function () {
return Array.prototype[methodName].apply(cloned, arguments);
}
);
}
);
}
return isemptyobj(cloned)
? (
isObject(input)
? cloned
: input
)
: cloned;
} else {
return input;
}
};
}
));
//
shareimprove this answer
edited Sep 27 '13 at 7:09

community wiki
25 revs, 3 users 83%
Nikola Vukovic
1
Why would this answer be better than any of the other ones? – BLaZuRE Jul 27 '13 at 20:51
show 3 more comments
up vote
0
down vote
The problem with copying an object that, eventually, may point at itself, can be solved with a simple check. Add this check, every time there is a copy action. It may be slow, but it should work.

I use a toType() function to return the object type, explicitly. I also have my own copyObj() function, which is rather similar in logic, which answers all three Object(), Array(), and Date() cases.

I run it in NodeJS.

NOT TESTED, YET.

// Returns true, if one of the parent's children is the target.
// This is useful, for avoiding copyObj() through an infinite loop!
function isChild(target, parent) {
if (toType(parent) == '[object Object]') {
for (var name in parent) {
var curProperty = parent[name];

// Direct child.
if (curProperty = target) return true;

// Check if target is a child of this property, and so on, recursively.
if (toType(curProperty) == '[object Object]' || toType(curProperty) == '[object Array]') {
if (isChild(target, curProperty)) return true;
}
}
} else if (toType(parent) == '[object Array]') {
for (var i=0; i < parent.length; i++) {
var curItem = parent[i];

// Direct child.
if (curItem = target) return true;

// Check if target is a child of this property, and so on, recursively.
if (toType(curItem) == '[object Object]' || toType(curItem) == '[object Array]') {
if (isChild(target, curItem)) return true;
}
}
}

return false; // Not the target.
}
shareimprove this answer
answered Feb 9 '14 at 10:16

community wiki
Phuein
add a comment
1 2 next
protected by acdcjunior Apr 5 '14 at 12:41

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#27 dyvniy » Пт, 13 ноября 2015, 13:44:25

write tests
http://stackoverflow.com/questions/300855/javascript-unit-test-tools-for-tdd
Спойлер
Karma or Protractor

Karma is a JavaScript test-runner built with Node.js, and meant for unit testing.

Protractor is for end-to-end testing, and uses Selenium Web Driver to drive tests.

Both have been made by the Angular team. You can use any assertion-library you want with either.

Screencast: Karma Getting started

related:

Should I be using Protractor or Karma for my end-to-end testing?
Can Protractor and Karma be used together?
pros:

Uses node.js, so compatible with Win/OS X/Linux
Run tests from browser or headless with PhantomJS
Run on multiple clients at once
Option to launch, capture, and automatically shutdown browsers
Option to run server/clients on development computer or separately
Run tests from command line (can be integrated in ant/maven)
Write tests xUnit or BDD style
Supports multiple JavaScript test frameworks
Auto-run tests on save
Proxies requests cross-domain
Possible to customize:
Extend it to wrap other test-frameworks (Jasmine, Mocha, QUnit built-in)
Your own assertions/refutes
Reporters
Browser Launchers
Plugin for WebStorm
Supported by Netbeans IDE
cons:

Does not supports NodeJS testing
No plugin for Eclipse (yet)
No history of previous test results
Buster.js

A JavaScript test-runner built with Node.js. Very modular and flexible. It comes with it's own assertion library, but you can add your own if you like. The assertions library is decoupled, so you can also use it with other test-runners. Instead of using assert(!...) or expect(...).not..., it uses refute(...) which is a nice twist imho.

A browser JavaScript testing toolkit. It does browser testing with browser automation (think JsTestDriver), qunit style static html page testing, testing in headless browsers (phantomjs, jsdom, ...), and more. Take a look at the overview!

A Node.js testing toolkit. You get the same test case library, assertion library, etc. This is also great for hybrid browser and Node.js code. Write your test case with Buster.JS and run it both in Node.js and in a real browser.
Screencast: Buster.js Getting started (2:45)

pros:

Uses node.js, so compatible with Win/OS X/Linux
Run tests from browser or headless with PhantomJS (soon)
Run on multiple clients at once
Supports NodeJS testing
Don't need to run server/clients on development computer (no need for IE)
Run tests from command line (can be integrated in ant/maven)
Write tests xUnit or BDD style
Supports multiple JavaScript test frameworks
Defer tests instead of commenting them out
SinonJS built in
Auto-run tests on save
Proxies requests cross-domain
Possible to customize:
Extend it to wrap other test-frameworks (JsTestDriver built in)
Your own assertions/refutes
Reporters (xunit XML, traditional dots, specification, tap, teamcity and more built in)
Customize/replace the HTML that is used to run the browser-tests
TextMate and Emacs integration
cons:

Stil in beta, so can be buggy
No plugin for Eclipse/IntelliJ (yet)
Doesn't group results by os/browser/version like TestSwarm *. It does however print out the browser name and version in the test results.
No history of previous test results like TestSwarm *
Doesn't fully work on windows as of May 2014
* TestSwarm is also a Continuous Integration server, while you need a separate CI server for Buster.js. It does however output xUnit XML reports, so it should be easy to integrate with Hudson, Bamboo or other CI servers.

TestSwarm

John Resig (jQuery) has created a tool for distributed JavaScript testing, TestSwarm. Mainly for open source JavaScript projects, but TestSwarm is open source, so you can set up a server yourself for corporate testing. Although this might require that you to do some modifications.

pros:

Continuous integration server for JavaScript
Supports all major browsers/operating systems
Run on multiple clients at once
Don't need to run server/clients on development computer (no need for IE)
Automatic run tests on all clients when you commit something (or whenever you modify the script to run the tests)
Show history of test results pr commit
Supports multiple JavaScript test frameworks
Have test results for OS and browser versions
Crowdsource to test in a multitude of browsers
cons:

Can not break your build through ant/maven
Don't notice the test fail before commit
No IDEplug-in
http://ejohn.org/blog/javascript-testing-does-not-scale/

TestSwarm architecture:

alt text

BrowserSwarm

BrowserSwarm is a project from appendTo, Sauce Labs and the Internet Explorer team. It is essentially a hosted forked version of TestSwarm.

In addition to all the advantages to TestSwarm, BrowserSwarm already has all the browsers connected to the swarm and ready to test your code, therefore not requiring you to add clients yourself or maintaining installations of browsers. Time is also saved from the hassle of setting up and configuring TestSwarm.

Jasmine

Jasmine

This is a client-side test-runner that might interest developers familiar with Ruby or Ruby on Rails. The syntax is based on RSpec that's used for testing in Rails projects.

Jasmine is a behavior-driven development framework for testing your JavaScript code. It does not depend on any other JavaScript frameworks. It does not require a DOM.
If you have experience with this test-runner, please contribute with more info :)

Project home: http://jasmine.github.io/

QUnit

QUnit focuses on testing JavaScript in the browser, while providing as much convenience to the developer as possible. Blurb from the site:

QUnit is a powerful, easy-to-use JavaScript unit test suite. It's used by the jQuery, jQuery UI and jQuery Mobile projects and is capable of testing any generic JavaScript code
QUnit shares some history with TestSwarm (above):

QUnit was originally developed by John Resig as part of jQuery. In 2008 it got its own home, name and API documentation, allowing others to use it for their unit testing as well. At the time it still dependended on jQuery. A rewrite in 2009 fixed that, now QUnit runs completelty standalone. QUnit's assertion methods follow the CommonJS Unit Testing specification, which was to some degree influenced by QUnit.
Project home: http://qunitjs.com/

Sinon

Another great tool is sinon.js by Christian Johansen, the author of Test-Driven JavaScript Development. Best described by himself:

Standalone test spies, stubs and mocks for JavaScript. No dependencies, works with any unit testing framework.
Intern

The Intern Web site provides a direct feature comparison to the other testing frameworks on this list. It offers more features out of the box than any other JavaScript-based testing system.

mocha.js

I'm totally unqualified to comment on mocha.js's features, strengths, and weaknesses, but it was just recommended to me by someone I trust in the JS community.

List of features, as reported by its web site:

browser support
simple async support, including promises
test coverage reporting
string diff support
javascript API for running tests
proper exit status for CI support etc
auto-detects and disables coloring for non-ttys
maps uncaught exceptions to the correct test case
async test timeout support
test-specific timeouts
growl notification support
reports test durations
highlights slow tests
file watcher support
global variable leak detection
optionally run tests that match a regexp
auto-exit to prevent "hanging" with an active loop
easily meta-generate suites & test-cases
mocha.opts file support
clickable suite titles to filter test execution
node debugger support
detects multiple calls to done()
use any assertion library you want
extensible reporting, bundled with 9+ reporters
extensible test DSLs or "interfaces"
before, after, before each, after each hooks
arbitrary transpiler support (coffee-script etc)
TextMate bundle
yolpo

yolpo

Yolpo is a tool to visualize the execution of javascript. Javascript API developers are encouraged to write their use cases to show and tell their api. Such use cases forms the basis of regression tests.
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#28 dyvniy » Чт, 19 ноября 2015, 17:38:38

Музыка в цикле
http://habrahabr.ru/post/148202/

Код: Выделить всё

<audio src="sound.mp3" autoplay loop></audio>

Спойлер
Освоение HTML5 тега audio перевод
HTML*
С появлением достаточно быстрого соединения с сетью Интернет, Flash был единственным инструментом для воспроизведения звуков на веб-сайтах. Но HTML5 в корне изменит способ воспроизведения звуков в Интернет. В этой статье я хочу подробно рассказать Вам о том, как использовать тег <audio> на ваших сайтах.


Используем <audio> для вставки звукового файлу на страницу
Ниже приведен простейший пример использования тега <audio>, он загружает mp3 файл и воспроизводит его. Обратите внимание на атрибут autopaly, который используется для автоматического воспроизведения звука. Тем не менее Вам не следует автоматически воспроизводить звуки а сайте, ведь это надоедает пользователям.
<audio src="sound.mp3" autoplay></audio>


Воспроизведение звука в цикле
Хотите зациклить звук? Атрибут loop поможет Вам это сделать. Но опять же, не стоит злоупотреблять автозапуском и воспроизведением в цикле, если не хотите, чтобы пользователь преждевременно покинул сайт.
<audio src="sound.mp3" autoplay loop></audio>


Отображение элементов управления
Вместо того, чтобы играть звуки автоматически, что, безусловно, плохая практика, вы должны позволить отображать в браузере некоторые элементы управления, такие как громкость и кнопки воспроизведение (пауза). Это сделать легко, просто добавив атрибут controls.
<audio src="sound.mp3" controls></audio>


Различные форматы файлов
Тег <audio> поддерживается большинством современных браузеров, но проблема в том, что разные браузеры поддерживают разные форматы файлов. Safari, например, может проигрывать MP3, а Firefox не может, и играет OGG-файлы вместо этого. Решение этой проблемы заключается в использовании обоих форматов, чтобы каждый посетитель мог услышать звук, независимо от того, какой браузер он использует.
<audio controls>
<source src="sound.ogg">
<source src="sound.mp3">
</audio>


Указываем MIME-тип файлов
При использовании различных форматов файлов, хорошей практикой есть указывание MIME-типа для каждого файла, чтобы помочь браузеру локализировать поддерживаемый им файл. Это легко можно сделать используя атрибут type.
<audio controls>
<source src="sound.ogg" type="audio/ogg" >
<source src="sound.mp3" type="audio/mp3" >
</audio>


Для старых браузеров
А что, если посетитель использует IE6 или какой-то другой доисторический браузер, который не поддерживает тег <audio>? Все легко: ниже приведён код, который будет отображать сообщение для браузеров, которые не поддерживают тег <audio>.
<audio controls>
<source src="sound.ogg" type="audio/ogg" >
<source src="sound.mp3" type="audio/mp3" >
Ваш браузер не пожжерживает тег audio!
</audio>


Буферизация файлов
При воспроизведении файлов большого размера может использоваться буферизация файлов. Для этого вы можете использовать атрибут preload. Он может принимать 3 значения:
none — если вы не хотите использовать буфер файлов;
auto — если вы хотите, чтобы браузер беферизировал файл целиком;
metadata — для загрузки лишь служебной информации (продолжительность звучания и др.).


Управление воспроизведением через JavaScript
Управлять HTML5 аудио-проигрывателем через JavaScript очень легко. Следующий пример показывает, как с использованием JavaScript можно построить свои базовые элементы управления аудио-плеером:
<audio id="player" src="sound.mp3"></audio>
<div>
<button onclick="document.getElementById('player').play()">Воспроизведение</button>
<button onclick="document.getElementById('player').pause()">Пауза</button>
<button onclick="document.getElementById('player').volume+=0.1">Громкость +</button>
<button onclick="document.getElementById('player').volume-=0.1">Громкость -</button>
</div>


Вот и всё на сегодня.
Надеюсь, что эта статья помогла Вам понять базовые возможности HTML5 тега <audio>.
html5, audio, тег audio
+9

72,1к

256

Перевод: Jean-Baptiste Jung

Максим Ткачук @makzimko карма9,0 рейтинг0,0

Похожие публикации
+79
HTML5: старые теги нового назначения 10,7к 113 108
+107
Визуализация аудио в HTML5 10,9к 192 29
+54
HTML5 Audio и Game Development: баги браузеров, проблемы и их решения, идеи 5,0к 93 84
Самое читаемое
Сейчас Неделя Месяц
Хакеры изобрели новую схему воровства денег, украв 250 млн. рублей 61
Параллельная разработка настолки и компьютерной игры: как всё встало с ног на голову в разных версиях 2
Нечто «крадет» место на диске? 12
Rutube 2009-2015: история нашего железа 11
Как вести секретную переписку в мире, где за вами постоянно следят: методы Эдварда Сноудена. Часть 1 16
«Красная карточка»: что скрывается за предупреждением о вредоносном ПО? 11
Мой опыт миграции на PHP 7 31
Gradle: 5 полезностей для разработчика 0
Как устроена видеоаналитика 2
Flytouch 2/Superpad III и попытка сэкономить байты в ядре Линукс 0
Комментарии (19)

+3 Ualde21 июля 2012 в 12:10#
Используем audio для вставки звукового файлу на сторінку

Для незнающих украинских — имеется в виду «на страницу»?

И «файл wtkbrjv» — файл целиком :)
+10 itdevelop21 июля 2012 в 12:16#
Да уже море просто ресурсов, где рассказывается про тег . Неужели столь простая информация до сих пор требует обсуждения?
+3 LaFut21 июля 2012 в 12:26#
Тем более пользоваться им нормально до сих пор нельзя.
+1 xPaw21 июля 2012 в 14:53#↵↑
Почему нет?
+2 LaFut21 июля 2012 в 15:17#↵↑
А оно не работает нормально. Пробовали и огребли кучу проблем. Реально нет простого способа его использования чтобы работало у большинства пользователей. Чего стоит зависание сафари в одной из версий, постоянные падения после выхода 19 хрома.
0 dima_smol23 июля 2012 в 17:13#↵↑
и как минимум гимморой с флеш-прокладкой или залитием одинаковых ogg и mp3 дорожек для разных файлов
+15 hOtRush21 июля 2012 в 12:58#
весьма познавательная статья. столько полезной, а главное труднодоступной информации
+1 olexandr1721 июля 2012 в 13:00#
Обратите внимание на атрибут autoload, который используется для автоматического воспроизведения звука. Тем не менее Вам не следует автоматически воспроизводить звуки а сайте, ведь это надоедает пользователям.




так autoload или autoplay?
0 art_tk21 июля 2012 в 15:42#
А как сделать остановку загрузки кнопку «Стоп», вместо «Паузы»?
0 ShpuntiK22 июля 2012 в 12:02#↵↑
audio.currentTime = 0;
0 ShpuntiK22 июля 2012 в 12:03#↵↑
и начнёт сначала играть, ну если надо остановить будет не просто сначала нажать, но и остановить то так:
audio.currentTime = 0;
audio.pause();
–1 chico23 июля 2012 в 15:40#↵↑
лучше наоборот
+5 nicothin21 июля 2012 в 15:43#
Последние несколько месяцев на Хабре наблюдаю множество статей, с информацией для самых маленьких. Информация, конечно, полезная, но доступная и малоактуальная (к сожалению).
Может, стоит для таких статей организовать что-то вроде раздела «ХабраДетский сад» и переносить туда подобные статьи голосованием (при переносе убирать с главной и из rss)?
0 medved1321 июля 2012 в 19:17#
>Safari, например, может проигрывать MP3, а Firefox не может, и играет OGG-файлы вместо этого.

Ну вот опять начинается. Каждый браузер реализует свое, а фронтэндеры в итоге мучаются и держат на своей машине целый зоопарк.
0 Fr0stb1te22 июля 2012 в 08:14#↵↑
На мелких файлах это не то чтобы катастрофа. Я, например, рекодирую все, что мне попадает, в vorbis, и отдаю оригинал и vorbis как fallback. Вроде у всех работает.
А за то, что не все могут реализовать все возможные форматы, винить нужно не производителей браузеров, а патенты на алгоритмы и тех, кто хочет за использование декодеров бабло.
+1 spmbt22 июля 2012 в 10:17#
С появлением достаточно быстрого соединения с сетью Интернет, Flash был единственным инструментом для воспроизведения звуков на веб-сайтах.
Никого не насторожило, что с 1-й строчки идёт неправда? Издревле альтернативами флешу были теги object и embed, которые работали напрямую с звуковыми файлами, сильно зависели от настроек ОС и установленных кодеков, но всегда были независимы от флеша. И никогда не исчезали из браузеров.

Так вот, почему бы, даже если и перевод, не поправить автора сочинения? Как обычно, в скобках «прим. перев.». Зачем вообще переводить автора, не полностью разбирающегося в теме? Лучше взять правильную часть, проверить, если надо, и написать своими словами. Тем более, что в комментах уже пишут, что и данные теги работают с глюками, поэтому не могут быть решением.
+1 ShpuntiK22 июля 2012 в 12:07#
Возможно, я уже начитался кучи всего по и мне кажется эта информация просто убогой бесполезной, детской… Если в гугле набрать , то выдаст кучу ответов, где написано то же самое что и в этой статье… тогда — зачем переводить было?

Вот это лучше бы перевели, если так сильно хотелось что-то сделать.
0 spmbt24 июля 2012 в 18:39#
Все легко: ниже приведён код, который будет отображать сообщение для браузеров, которые не поддерживают тег audio.
Всё не так легко: есть флеш, который нормально работает в этих браузерах. Так вот, туда надо вставить флеш или его инициализацию.
habrahabr.ru/post/148368/ Тут подробнее.
0 Audiophile 3 октября 2012 в 01:13#
У сервера неправильно прописан MIME тип для ogg (application/octet-stream), из-за этого Firefox не играет (в отличие от Оперы и Хрома). Может автор знает, как это исправить? Отредактировать .htaccess невозможно.

Пробовал указывать тип в тегах — не помогает.
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#29 dyvniy » Чт, 3 августа 2017, 16:13:51

AdBlock способы блокировки и её обхода
https://geektimes.ru/post/265374/
Спойлер
Обход блокировок adblock, и блокировка обхода блокировки recovery mode
IT-компании, Софт, Браузеры
В статье рассматривается один из эффективных методов противодействию adblock, и обход этого метода. Этот круг вечен – но, похоже, рекламщики вырвались вперёд!



Как-то раз на одном сайте администрация вежливо попросила пользователей добавить сайт в исключения адблока. Я, как сознательный пользователь, это сделал – но появившаяся реклама через какое-то время стала совсем не похожа на допустимую рекламу, и я включил адблок снова. К моему удивлению, реклама не исчезла – и я стал разбираться, в чём тут дело.

1. Обход adblock со стороны разработчиков:

Способ обхода adblock, который применили разработчики сайта, оказался очень эффективным: они помещали рекламу в div со случайным переменным классом, который менялся при каждой перезагрузке страницы. Также были убраны все атрибуты, по которым можно было идентифицировать div или рекламу внутри: никаких постоянных id элементов, изображение рекламы подгружается с хостинга, на котором хранятся полезные картинки. Вышестоящий div содержит много полезной информации, так что его тоже не заблокируешь.

Случайный переменный класс для рекламного элемента – именно за этим, как мне кажется, будущее интернет-рекламы. По крайней мере, при огромной аудитории сайта – в стандартных подписках адблока эта реклама не блокируется до сих пор.

2. Блокировка рекламы пользователем, в обход обхода adblock:

Пришлось создать правило, исключающее вложенные полезные элементы. В описании создания фильтров для adblock нигде про это не рассказывается, поэтому незнакомые с CSS люди вряд ли смогут это сделать. Может, моя статья им в этом поможет.

Для вложенных элементов в adblock используется следующая конструкция:
div.внешний_класс > div.внутренний_класс


Для исключения элементов по какому-то атрибуту используется конструкция not:
div:not(.полезный_класс)


Таким образом, искомое правило выглядит так:
имя_сайта##div.sidebar_right > div:not(.block)

Это позволяет заблокировать все вложенные в sidebar_right элементы, за исключением тех, которые имеют класс block. Задача была решена – что дальше?

3. Обход такой хитрой блокировки со стороны разработчиков:

Обойти такую блокировку можно, модифицировав движок сайта. Например, если и вышестоящий контейнер, и вложенные полезные div тоже будут иметь переменные имена классов, в адблоке просто не будет механизмов для их идентифицирования. Так что, повторюсь – именно за таким подходом я вижу будущее рекламы, в то время как всё больше пользователей устанавливают фильтры, а адблок начинает рекламировать самого себя.

И, напоследок – ещё один эффективный способ для web-мастеров: можно просто добавлять ненавязчивую рекламу, тогда пользователи намного лояльнее начнут относиться к ней.
Спойлер
var ad = document.querySelector(`body > div:nth-child(2) > div:nth-child(6) > div:nth-child(3)`);
ad.parentNode.removeChild(ad);
caveeagle 6 ноября 2015 в 19:42 +1
Да, спасибо за подсказку, хороший вариант!

Хотя, тоже обходится «на раз» модификацией движка — добавлением случайного числа промежуточных элементов. Причем, похоже, скоро массово появятся всякие такие плагины для сайтов — по обходу адблока и других резателей рекламы.
Flash_X 6 ноября 2015 в 19:59 0
во первых это, с большой вероятностью сломает вёрстку. во вторых, что-то вроде этого:
Array.prototype.slice.call(document.querySelectorAll('div')).forEach((e)=> e.childNodes.length?0:e.parentNode.removeChild(e));
// snippet #1
caveeagle 6 ноября 2015 в 20:05 0
Обходится ненулевым содержимым, например невидимым пикселем. Для вёрстки — div высотой пару пикселей.

И да: адблок, которым пользуются большинство, на такое не способен (насколько я знаю)

Flash_X 6 ноября 2015 в 21:07 0
если будет не нулевое содержимое, то это содержимое нужно будет как то скрывать, а значит либо появится признак у промежуточных элементов (например стиль display:none), либо будет общее для всех них правило. в любом случае это тупиковый вариант.
caveeagle 6 ноября 2015 в 21:18 0
Да, но этот признак скроет «фальшивые» элементы. А как быть с самой рекламой? Конечно, можно написать скрипт: сначала скрыть фальшивые элементы, а потом скрыть элементы по их номеру. Но увы, адблок этого не умеет.

Да и написание столь сложных правил — подходит для гиков, каждый день заходящих на один и тот же сайт, и разбирающихся в CSS. А если когда таких сайтов станет много? =)
dtestyk 6 ноября 2015 в 21:26 +2
Скрытие — не панацея, сайт может регулярно проверять, добавлены ли элементы в dom, показаны ли элементы, загружен ли в них контент, и что самое печальное, если нет — отсылать данные о подобном на сервер, где ситуацию проанализируют и внесут соответствующие правки.
NetBUG 7 ноября 2015 в 02:33 0
Опять появятся кнопки прекращения выполнения скриптов.
Для экономии батарей устройств, в том числе.
Mad__Max 7 ноября 2015 в 04:00 +1
А потом посетитель сайта сильно удивляется (и справедливо злится) почему это загрузка всего 1й простой странички съедает несколько Мб интернет трафика, занимает несколько сотен Мб оперативной памяти браузером и грузит половину ядра процессора, хотя вроде ничего на ней даже не делаешь.

Хотя скорее всего к этому и идем…
dtestyk 7 ноября 2015 в 09:08 0
Врядли, подобные проверки требуют интернет трафика, много оперативной памяти. А маленькая задача, запускаемая по таймеру практически не заметна для современных, в том числе и мобильных процессоров.
Другое дело: невмеру продвинутый дизайн, непрактичная тяга к универсализации инструмента и cryptoUI: хитроумные полиморные вставки в DOM, переусложненные стили…
Хотя скорее всего к этому и идем…
Скорее, к этому идут сайты, а не пользователи:
многие интересные сайты — минималистичны: pinterest.com, agar.io, editpad.org, develop.re, craigslist.org, bash.im, arxiv.org, echojs.com, nplus1.ru, gostash.it, neurowareblog.blogspot.com
vrmzar 7 ноября 2015 в 16:32 0
Многие «интересные» сайты уже привели к тому, что пользователи вынужденны размещать текст и посты преимущественно текстового содержания в виде картинок.
Nicknnn 6 ноября 2015 в 20:02 +3
Вот примерно так можно убрать эти страшные лица в тонере справа.
для ublock
habrahabr.ru###layout > .inner > .column-wrapper:nth-of-type(2) > .sidebar_right > * > a
withkittens 7 ноября 2015 в 17:11 +2
Вот не совру: бувально пару дней назад у этих страшных лиц ещё были нормальные id:
habrahabr.ru##DIV[class="daily_best_posts"]
habrahabr.ru##A[id="print_tab"]
withkittens 7 ноября 2015 в 17:15 +3
На текущий момент вроде бы решилось вот так:
habrahabr.ru##div.sidebar_right > div:not(.block)
mtp 8 ноября 2015 в 03:43 0
А не проще там ссылку на bit.ly детектировать?
xRay 9 ноября 2015 в 16:13 0
Подскажите примерчик

Я пока так правило составил
###layout > .inner > .column-wrapper:nth-of-type(2) > .sidebar_right > * > a[rel="noreferrer"]
###layout > .inner > .column-wrapper:nth-of-type(2) > .sidebar_right > * > a[rel="noreferrer"]> img
withkittens 9 ноября 2015 в 18:01 0
У этих блоков не один «рекламный» признак, выбирайте любой.
olen 6 ноября 2015 в 20:03 (комментарий был изменён) 0
Также были убраны все атрибуты, по которым можно было идентифицировать div или рекламу внутри: никаких постоянных id элементов, изображение рекламы подгружается с хостинга, на котором хранятся полезные картинки

У рекламных баннеров все же есть существенное отличие от «полезных картинок»: по ним можно кликнуть (присутствует тэг «a»).
caveeagle 6 ноября 2015 в 20:07 0
Увы, там не картинки — а ссылки на разделы сайта и популярные посты, не хочется их терять.
olen 6 ноября 2015 в 20:16 (комментарий был изменён) +1
a > text — полезная ссылка
a > img — банер
forgotten 7 ноября 2015 в 08:37 +3
Ходят слухи, что JavaScript-ом можно обрабатывать клики по любым элементам.
DenimTornado 8 ноября 2015 в 21:26 0
Нет, сынок, это фантастика!
ankh1989 9 ноября 2015 в 00:39 0
Меньше верьте всяким непроверенным слухам :)
dtestyk 6 ноября 2015 в 20:37 0
Мне кажется у клиента есть преимущество, так как код исполняется на его стороне, в крайнем случае можно сделать для рекламы подходящую «песочницу» и вытаскивать только полезную информацию.
caveeagle 6 ноября 2015 в 21:00 0
Мне кажется, наоборт:
— Владелец сайта делает это один раз для своего сайта. Причем, если сайт приносит деньги от рекламы, то это можно поручить профессионалам.
— Пользователь должен настраивать фильтры для каждого сайта, что в условиях рандомных алгоритмов будет непросто. Причем, для этого он должен либо делать это сам, и разбиратсья в css (как сейчас).

К примеру, удаление рекламы для одного сайта до сих пор не работает в адблоке, несмотря на огромную аудиторию.
dtestyk 6 ноября 2015 в 21:15 +5
Тут может сработать краудсорсинг. Человек не будет искать настройки(или что там еще потребуется) для каждого сайта. Он решит задачу для одного конкретного. А затем обменяется решениями с другими.
NetBUG 7 ноября 2015 в 02:35 +1
AdBlock Plus — далеко не самый умный плагин для этой задачи. К примеру, в нём нельзя просто так ввести регулярное выражение для id/класса элемента, что было лет семь назад в старой Opera.
CyberCore 6 ноября 2015 в 20:57 +9
Нужен компромисс, я бы отключил ad block, если бы не было анимированных баннеров.
foxkeys 6 ноября 2015 в 21:08 (комментарий был изменён) +6
Да, я тоже не трогаю рекламу, пока она не моргает. Как только появляется анимация — немедленно выпиливаю нах...., эм, ну в общем, совсем выпиливаю.
Ocelot 6 ноября 2015 в 21:23 +2
Для лисы:

Анимированные гифки: плагин «Toggle Animated GIFs» можно настроить так, чтобы анимация воспроизводилась только по наведению курсора или по клику.
HTML5 video: пока не встречал в рекламе, но автоплей отключается параметром media.autoplay.enabled=false в about:config.
Flash: отключить его нахрен, флеш давно пора похоронить. Ну или сделать включаемым по запросу и разрешить только там, где он нужен.
caveeagle 6 ноября 2015 в 21:35 0
Собственно, все эти плагины у меня и стоят — Toggle и Flashblock. Просто рекламные картинки на одном сайте сами по себе стали несколько… вызывающими и отталкивающими, даже без анимации.
Vilgelm 6 ноября 2015 в 22:32 (комментарий был изменён) +1
Вот (впрочем, любой почти ucoz сайт) пример HTML5 видео в рекламе, еще и в виде попапа, который можно только через 30 секунд закрыть. Пока такое практикуется, AdBlock отключать нет смысла.
А вот AdSence или Директ даже полезным бывает иногда, эти сети блокировать как-то не тянет.
NetBUG 7 ноября 2015 в 02:36 0
В Facebook бы выпилить это видео.
amarao 8 ноября 2015 в 17:13 0
rbc в мобильной версии использует html5 видео с автозапуском. Мне кажется, они некую грань перешли уже.
sashabeep 9 ноября 2015 в 10:40 +2
Хоронили флеш — порвали три стандарта. Добро пожаловать в мир Canvas и всего такого, что вообще ничем не задетектишь
Часть баннеров вообще теперь делаю просто с помощью библиотечек слайдеров

И, кстатида, на одной из площадок, для которой постоянно делаю баннеры, увидев, как нереально тормозит что swiffy, что createJS нашли хак, как обойти автоматическую постановку флеша на паузу в хромиуме, потому что он не тормозит, как вся эта модная красота. Такие вот вести с полей.
caveeagle 6 ноября 2015 в 20:59 (комментарий был изменён) 0
del
dtestyk 6 ноября 2015 в 21:07 +3
Тема топика затрагивает самые основы философии программирования.
Потому что, подобное противостояние является одной из программистстских антиномий:
вирус — антивирус
анонимность — идентификация
seo оптимизация — поисковики
adBlock — реклама
автоматизация — captcha
Может кто знает еще какие?
Еще просматривается пользовательская антиномия:
информационная перегрузка — пузырь фильтров
Все они, в свою очередь, представители «дурной бесконечности» Гегеля.
В теории игр модель подобных отношений хорошо соответствует минимаксу.
caveeagle 6 ноября 2015 в 21:21 0
Ну, я о более «приземлённом» — о том, что начинается эра рекламы, которая не будет блокироваться стандартными средствами «из коробки». Будут либо «гиковские» средства с индивидуальной настройкой, требующие знания CSS, либо платные сложные решения, с постоянно меняющимися алгоритмами.
dtestyk 6 ноября 2015 в 21:33 0
начинается эра рекламы, которая не будет блокироваться стандартными средствами
Более того, рано или поздно начнет внедряться скрытая реклама, которая приблизительно соответствует стеганографии.
Ocelot 6 ноября 2015 в 21:35 +2
Как раз к этому моменту подоспеют нейросети, которые будут распознавать рекламу на уже отрендеренной странице.
ankh1989 7 ноября 2015 в 06:49 +1
Это было бы идеальным решением: нейросеть должна распознать все вырвиглазные элементы интерфейса и выпилить их (ну или сделать статичными и черно белыми, чтобы не отвлекали). Можно, конечно, будет обмануть эту нейросеть сделав рекламу спокойной расцветки, но тогда её и блокировать незачем.
caveeagle 6 ноября 2015 в 21:36 0
(с интересом) Это как? Интересно было бы услышать ответ — я не очень представляю себе такое.
KivApple 6 ноября 2015 в 21:42 +2
Думаю речь идёт о рекламных статьях, которые с точки зрения оформления никак не отличаются от полезного контента.
arkandos 6 ноября 2015 в 21:54 +4
Собственно, под этот критерий подходит немалая часть статей на ГТ.
Mad__Max 7 ноября 2015 в 04:05 0
Их уже полно, есть даже устоявшиеся профессии по их написанию и рекламые сети специализирующиеся на обмене такими всевдо-полезными статьями (вы размещаете у себя наши N статей, мы — ваши) как в свое баннерообменные сети.

Хотя на общем фоне (баннеров и рекламных ссылок и контекстной) пока меньшую часть и пока основной акцент на индексацию и позиции в поисковах, а обход рекламорезок вторичен.
Goodkat 6 ноября 2015 в 23:08 (комментарий был изменён) +1
Рекламу можно вставлять между абзацами полезного текста, между комментариями и т.п., вёрстку и css-классы генерировать уникальные для каждого просмотра, контент загружать программно уже после отображения рекламы, зашифрованным и распаковывать уже на клиенте с проверкой контрольных сумм получившегося дерева DOM — блокировщики типа AdBlock против такого пока бессильны. В Германии, кстати, одно популярное издательство так и делает — блокирует доступ к контенту, если установлен блокировщик рекламы; недавно отчитались о падении доли пользователей с блокировщиками и росте доходов от рекламы, а блокировщику рекламы через суд запретили блокировать блокировку блокировщиков :)

Думаю, будущее рекламщиков как раз за такими методами, а будущее блокировщиков — OCR+Crowdsourcing.

Парсер не дал вставить ссылки.
Запрет через суд: http://m.heise.de/newsticker/meldung/Axel-Springe ... egen-Adblock-Plus-2854649.html
dtestyk 7 ноября 2015 в 00:11 +1
блокировщику рекламы через суд запретили блокировать блокировку блокировщиков :)
То есть запретили Б3Р. Есть книга «Конфликтующие структуры», там вводится алгебра для подобной рекурсии.
Возможно, должен быть какой-то международный запрет на принятие подобных запретов: «право на бесконечную рекурсию».
Alexey2005 7 ноября 2015 в 21:24 +2
Начиная с определённого момента может стать проще не распутывать хитросплетения скриптов, а воткнуть блокировщик на выходе рендер-движка. Когда вся страница уже отрендерена в изображение, на нём распознавать всевозможной эвристикой области баннеров и их замазывать.
Greedz 6 ноября 2015 в 21:11 0
Как-то раз на одном сайте

А можно ссылку на этот сайт?
caveeagle 6 ноября 2015 в 21:22 0
Теги к посту Вам в помощь =)
Greedz 7 ноября 2015 в 00:24 0
Ах вот оно, что! Я то и не замечал, наши это быстро пофиксили.
Vendict 7 ноября 2015 в 15:36 0
Не охота начинать ещё одну ветку. В тему сайтов, только у меня общая их лента не работает без отключения сабжа?
Lertmind 6 ноября 2015 в 21:23 0
Я наверно что-то не понял, но чем не устраивает блокировка картинок через AdBlock? Около 7 штук заблокировал и больше не вижу рекламы с включённым AdBlock.
arkandos 6 ноября 2015 в 21:28 0
Во-первых, это похоже на борьбу с ветряными мельницами — каждый раз ручками блокировать новый адрес. Во-вторых, лишняя нагрузка на то, чтобы отфильтровать по списку — семь, конечно, немного, а если больше? В-третьих, перфекционизм — при блокировке лишь картинки остается пустое место от div'а, так что сайдбар смещается чуть вниз, а с вышеописанным правилом все выглядит кошерно.
Lertmind 6 ноября 2015 в 21:44 (комментарий был изменён) 0
Я как раз исходил из того, что их не много, поэтому проблема только в третьем доводе. Да, способ выше лучше, но на данный момент они оба нормально справляются с задачей, пока что-то не сломается.
arkandos 6 ноября 2015 в 21:48 0
Собственно, также и блокировал отдельные картинки до того, как появился этот пост. Как-то вечером взялся за это дело, но поскольку давно «не держал в руках» CSS, все свелось к идее остановить выполнение скрипта, который и творит все это безобразие с генерацией классов div'а.
caveeagle 6 ноября 2015 в 21:28 0
Блокирование конкретной картинки по URL? Не устраивает, что завтра появится восьмая картинка — рекламодатели меняются. Кроме того, скоро такой подход возьмут себе и другие сайты — картинок будет сильно много.
KivApple 6 ноября 2015 в 21:39 0
У меня была такая идея, но в благих целях. Если генерировать подобным образом (случайные id + в коде элементы находятся не в том порядке, в котором их разместит CSS) элементы формы, то можно, наверное, отсечь без всяких каптч большинство спамеров, а пользователь ничего и не заметит. Конечно, сломается автокомплит, но он нужен не везде.
caveeagle 6 ноября 2015 в 21:46 0
(задумался над реализацией) Вы отсылаете на сервер данные формы, причем поля формы имеют случайное имя. Сервер должен при этом знать, какое именно имя соответсвует нужному полю. Значит, на сервере надо хранить соответствие — а хранение на сервере таких вещей замедляет быстродействие, и вообще не очень оптимально. Правда, можно эти данные шифровать внутри самой формы, ключом с сервера… В общем, да — интересное решение!
Спасибо, возьму на заметку.
kloppspb 6 ноября 2015 в 22:46 0
В самом простом случае поля формы могут генерироваться по определённым правилам, например, в зависимости от UserAgent, IP посетителя, текущей даты (не перескочить через полночь...) etc Соответственно, обработчик формы их легко восстановит (например, email будет лежать в поле с именем md5( «email» + HTTP_USER_AGENT). Ну или что-то в этом роде.
Goodkat 7 ноября 2015 в 00:31 0
Зачем такие сложности-то?
Массив соответствия сгенерированных имён для полей много места не займёт, в сессии обычно и так много чего хранится, лишние сто байт погоды не сделают, а маппинг займёт намного меньше времени, чем пересылка данных формы по сети.
Но это сломает автозаполнение полей на стороне пользователя, а роботу обойти такую защиту не сложно — поля вы всё равно подписываете для пользователя.
kloppspb 7 ноября 2015 в 00:37 0
>в сессии обычно и так много чего хранится

В какой такой сессии?
dtestyk 6 ноября 2015 в 22:09 0
не в том порядке, в котором их разместит CSS
А document.elementFromPoint(x, y) это обманет?
KivApple 8 ноября 2015 в 17:09 0
Обычно комфортный для пользователя размер полей лежит в достаточно широких пределах. Если сделать правильный дизайн (чтобы он хорошо смотрелся с полями разных размеров), то можно делать размеры элементов формы чуть больше-чуть меньше случайным образом каждую загрузку страницы.
qw1 6 ноября 2015 в 22:02 +2
На одном сайте была реклама партнёров, картинки грузились с полезного сайта, div было сложно идентифицировать, но была уязвимость — ссылка вела к партнёрам. По этому признаку и заблокировал
##a[href^="http://some.domain/delivery/ck.php?"]
evocatus 6 ноября 2015 в 23:58 0
Можно пойти дальше: если картинка-ссылка ведёт на другой домен, уже можно блокировать.
qw1 7 ноября 2015 в 00:35 0
Может быть много ложных срабатываний, например на трекерах превьюшки скриншотов ведут на хостинг картинок, таблички рейтинга кинопоиска — на страницу фильма.

Но идея интересная, блокировать не список источников картинки для банера, а список таргетов, куда ведёт ссылка из картинки. Если домен в чёрном списке, например googleadservices.com, картинку скрывать.
Ocelot 7 ноября 2015 в 00:55 +1
Сделают ссылки на свой домен, откуда уже идет редирект на домен рекламодателя.
qw1 7 ноября 2015 в 12:55 (комментарий был изменён) 0
del (не в ту ветку)
Iv38 7 ноября 2015 в 05:07 0
Это может быть до 100% картинок на популярных сайтах. Например на этом сайте картинки к статьям на каком домене хранятся? Картинкохостинги, CDN, хотлинкинг, всё в бан? Или я не понял идею?
evocatus 7 ноября 2015 в 12:15 +1
Ну так это просто картинки, не ссылки.

Если хотят добавить в страницу картинку, пусть даже со стороннего хостинга — это один случай. Это либо просто img с прямой ссылкой, либо img с превьюшкой и ссылкой на страницу с полной версией. Это одни методы. Не припомню чтобы здесь редиректы использовали. Притом список самых популярных картинкохостингов можно добавить в белый список.

Если хотят вставить рекламу, это другой случай. Обычно прямых ссылок на картинку нет, потому что она каждый раз разная и загружается с стороннего хостинга. Также используются iframe, анимация и пр. Часто элемент с рекламой содержит немало JS. И HTML-структура обычно на порядок сложнее, чем у просто картинки, вставленной для дела, а не для рекламы. Редиректы — обычное дело.

Так вот — это 2 настолько отличающихся паттерна поведения, что их можно отловить, как мне кажется.
v0rtex 6 ноября 2015 в 22:11 +1
Немного оффтопа:
Как залочить рекламу в стоковом приложении YouTube на Android?
Adblock Plus не блокирует :(
А они уже внутри ролика вставлять начали.
Vilgelm 6 ноября 2015 в 22:36 0
AdFree отлично помогает.
А у кого-нибудь получалось смотреть видео на RuTube и подобных сайтах с включенным AdBlock в нормальном качестве? AntiAdBlock не спасает.
Iv38 7 ноября 2015 в 05:14 0
Я давно пытаюсь побороть рекламу на ютубе, но сейчас после установки этой штуки по ссылке произошло нечто, хм, подозрительное.
Начнем с положительного. Рекламы на ютубе я действительно пока не видел. Но через час после установки этого apk, конечно требующего рута, у меня угнали много лет не используемый AppleID, который привязан к тому же адресу электронной почты, что и гугл-аккаунт на планшете. Улики косвенные, но будьте осторожны.
Vilgelm 7 ноября 2015 в 13:26 (комментарий был изменён) 0
Скорее совпадение или устанавливали откуда-то не оттуда. Пользуюсь уже очень давно, еще со времен первого Galaxy, когда никаких других способов избавиться от рекламы кроме AdFree не было. При этом на телефона всегда установлен Webmoney, QIWI, клиент ИБ и так далее. Так вот, за все время использования ни одного «угона» не было.
Кстати, AdFree блокирует рекламу во всех приложениях и в браузере за одно. Работает просто: добавляет в hosts записи типа 127.0.0.1 adsite.com
ivan386 7 ноября 2015 в 00:05 (комментарий был изменён) 0
Я его просто отключил и смотрю в мобильном хроме без рекламмы.
Greedz 7 ноября 2015 в 00:30 0
Радикальный метод: Xposed + Youtube Adaway
Вообще забыл о рекламе в Youtube приложении.
xirahai 7 ноября 2015 в 19:00 (комментарий был изменён) 0
Вручную заменил hosts на двухметровой длины, еще установлена adaway (обычная). В Хроме на ютубе не наблюдаю рекламы.
Stiver 6 ноября 2015 в 22:34 0
Что-то не соображу, а обычный RequestPolicy не поможет? Очень небольшое количество сайтов загружает рекламу со своего хостинга, т.к. это дает возможность накруток (рекламодатели, соответственно, против). На хабре RequestPolicy режет все, кроме рекламных ссылок в верхней строке, ну так они и не мешают.
qw1 6 ноября 2015 в 23:49 0
Отличная штука, но статика, скрипты, css часто бывают на другом домене.
Нужна квалификация, чтобы понимать, как ей пользоваться, поэтому решение не для масс, и не вызывает бурных обсуждений.
Но даже с RP бывает нужен AdBlock для таких случаев.
SpiritOfVox 7 ноября 2015 в 00:35 +4
Самые первые блокировщики работали с размерами изображений.
caveeagle 7 ноября 2015 в 10:49 +1
Поэтому в гугле первый ответ на вопрос «Как обойти adblock»: "- Измените размер изображения на пару пикселей" =)
icelaba 7 ноября 2015 в 01:19 0
История идет по кругу — первые вирусы, антивирусы, полиморфные вирусы, антивирусы умеющие ловить полиморфные вирусы.
Не так уж и сложно написать полиморфную верстку учитывая что имя тега-класса позиция элемента, уровни вложенности всем этим можно играть без ущерба для верстки
Ocelot 7 ноября 2015 в 02:10 0
Значит, будет адблок с эвристикой?
caveeagle 7 ноября 2015 в 02:38 +2
И станет платный, по подписке. И будет штат специальных людей, разрабатывающих правила для блокировки.
Greedz 7 ноября 2015 в 20:24 0
Такое уже есть у конкурентов, сидят люди на зарплате и своевременно обновляют фильтры. Довольно оперативно реагируют на жалобы о пропущенной рекламе.
dtestyk 7 ноября 2015 в 02:47 +2
а что еще нету? парочку эвристик распознавания рекламы уже упомянули:
ad.*; ads.*; adv.*
размер изображения
следующий виток: эвристики распознавания антиблокировщика рекламы:
полиморфное поведение
обработка события DOMNodeRemoved
проверка style.display
наличие таймера
caveeagle 7 ноября 2015 в 11:01 0
Тссс… не подсказывайте им, нас читают те самые люди! =)
ankh1989 7 ноября 2015 в 07:10 +10
Когда на одном сайте появилось вырвиглазное мигающее нечто справа, причём это нечто явно не хотело чтоб его выпиливали (рандомные атрибуты), я просто выпилил sidebar-right — на нём всё равно ничего полезного нет. Подсказка как легко сделать трудновыпиливаемую рекламу: скрипт запускает таймер на 10-20 секунд, после чего создаёт прямо в document.body элемент верхнего уровня без всяких признаков отличия и с position:fixed, картинка (красная мигающая и противная — иначе зачем так заморачиваться) идёт в background-image, а ссылка — в addEventListener(«onclick», ...). Продвинутый юзер, увидев это, будет в бешенстве (я вот со злости весь правый сайдбар выпилил), но выпилить рекламу не сможет. Ещё рекомендую попробовать пойти дальше и сделать top-level баннеры которые надо нажать прежде чем они уйдут (без крестика, конечно) и желательно со звуком (всё создавать скриптом — никакой разметки). Наконец, можно обязать юзера смотреть рекламу: на входе показывать рекламу (видео), затем требовать ответить на вопросы по поводу просмотренной рекламы и лишь затем пускать на сайт (если отвечает неправильно, то заставлять смотреть видео в два раза большей длительности).
dtestyk 7 ноября 2015 в 09:15 +3
требовать ответить на вопросы по поводу просмотренной рекламы и лишь затем пускать на сайт
видео-капча :)
Anisotropic 7 ноября 2015 в 11:00 +4
Тоже выпилил весь правый сайтбар, достали яркие уродские морды.
caveeagle 7 ноября 2015 в 11:04 0
Увы, я не был готов пожертвовать подборкой «самое популярное».

А главное — из принципа не хочется жертвовать функциональностью сайта, если это явно не оговорено в пользовательском соглашении. Так что — решил включиться в эту бесконечную гонку блокировщиков и антиблокировщиков.
esc 7 ноября 2015 в 11:33 0
Можно просто проверять то, что реклама отображена и не вырезана по таймуту и если не отображена, выпиливать все из document.body. Это не даст включить блокирующее правило в список т.к. оно будет ломать сайт.
xirahai 7 ноября 2015 в 19:50 0
Если обязать юзера и задавать вопросы, или насиловать иными способами — тогда вопрос встанет о необходимости ему именно данного ресурса. Поэтому уйдут, пусть даже и в никуда. То есть образуется свободная и в то же время заинтересованная чем-то аудитория. Как следствие появятся более дружественные конкурентные ресурсы, куда все с удовольствием мигрируют.
qrasik 7 ноября 2015 в 10:49 +3
Вы зря боритесь с адблоком. В итоге он начнет вырезать не по месту размещения, а по содержимому. Согласитесь, создать тысячи не похожих друг на друга баннеров очень сложно.

Да и если посчитать ресурсы подконтрольные адблоку, то тот же фейсбук нервно курит в сторонке со своими датацентрами. В свое время, нейросети серьезно прорядили спамеров. Перенести этот опыт на рекламщиков мешало исключительно благосклонное к ним отношение.
caveeagle 7 ноября 2015 в 11:18 0
(задумался над идеей) С одной стороны — да, выглядит перспективно. С другой — есть ряд сложностей:

— Спамеров прорядили не просто нейросети. Их прорядили нейросети, созданные командой профессионалов, которые работали в крупных компаниях. Вспомните спам-фильтры, которые бесплатны, и работают на локальном компьютере? Они очень долго были неэффективны, да и сейчас та же ситуация, как мне кажется.
Спам фильтруется либо крупными игроками (гмейл, мейл-ру), либо платными антиспам-решениями, за которые пользователь платит деньги.

— В случае со спамом — он невыгоден крупным игрокам, и они готовы вложиться в борьбу с ним. В случае инет-рекламы, наоборот. Нет стороны, которая готова платить серьезные деньги для борьбы с этим явлением.

— Кроме того, вычислительные ресурсы: мейлы можно фильтровать по нескольку секунд, даже минут. Для инет-серфинга это не пойдёт. Для примера: спам в мгновенных сообщениях на стороне клиента не фильтруется вообще, не видел таких решений.

Так что тема интересная, но надо думать… и поисследовать инет-рекламу нейросетями — чем не тема для следующей статьи?
xirahai 7 ноября 2015 в 20:13 +1
Если начнется заметный отток аудитории из-за навязчивой рекламы — тогда возможно и крупные поменяют отношение. На днях бквально был свидетелем как коллега искал запчасть по разным сайтам. Открыл очередной, а там как замельтешит, да еще и с звуком. Копирует URL в буфер и быстро нажимает ctrl-w, даже не заглядывая в списки цен. Спросил зачем чс'сишь в hosts — на сайты мудаков принципиально больше раза не хожу. Выходит навечно потеряли покупателя. Подумываю может взять методу на вооружение)
SpiritOfVox 7 ноября 2015 в 20:22 0
Аудитории некуда течь. Допустим периодически у Юлмарта и его конкурентов есть кликабельный фон по краям. Это отвратительно, но им норм.
vp7 7 ноября 2015 в 16:48 (комментарий был изменён) 0
Несколько лет использую на FF связку AdblockPlus (с Element Hiding Helper) + Stylish, все фильтры настраиваю вручную.
Рекламы практически нигде нет. Даже youtube в ролики не вставляет рекламу, хотя для него настроку делал чёрт знает сколько времени назад.

Но самое интересное — поставил на другом компьютере adblock с авто-обновляемыми фильтрами и один известный сайт (см. теги к статье) сразу же стал ненавязчиво просить отключить адблок. Такое ощущение, что он использует нечто вроде honeypot'а для проверки активности стандартных правил адблока.

p.s. Давно жду появления сайтов, которые будут проверять факт отображения рекламы и блокировать показ содержимого сайта в случае, если рекламы нет. Вот тут бороться будет намного веселее.
withkittens 7 ноября 2015 в 17:25 +1
Давно жду появления сайтов, которые будут проверять факт отображения рекламы и блокировать показ содержимого сайта в случае, если рекламы нет.
Лично мне такие уже попадались. Потребность получить содержимое была разовой, поэтому пришлось временно адблок отключить :(
xirahai 7 ноября 2015 в 20:28 0
Настоящее «веселье» начнется когда выпустят закон об уголовной ответственности за отказ от просмотра рекламы.
dtestyk 7 ноября 2015 в 20:44 0
Полагаю, его принятие нарушало бы принципы когнитивной свободы.
Alexey2005 7 ноября 2015 в 21:40 0
Думаете, это кого-то остановит? Рекламщики уже сейчас вопят о недополученной прибыли и подают в суд на разработчиков AdBlock.
А что им помешает объявить сайт творческим продуктом, не подлежащим изменению, и придумать какие-нибудь лицензионные соглашения — мол, заходя на этот сайт вы обязуетесь просмотреть рекламу. Не нравится реклама — не ходите на сайт. И ваша свобода не нарушается, т.к. вы сами выбираете, смотреть ресурс с рекламой или не смотреть данный ресурс вообще.
Ещё и пропаганду врубят на полную мощность по типу правоторговцев. Мол, из-за негодяев, блокирующих рекламу, разоряется куча сайтовладельцев, которые не могут содержать свой ресурс. И честный человек просто обязан рекламу смотреть, раз он хочет и дальше ресурсом пользоваться.
xirahai 7 ноября 2015 в 23:50 0
Физические объекты типа магазинов и т.д хоть и являются частной собственностью — тем не менее подчиняются правилам публичной оферты. Поэтому не имеют права препятствовать свободному входу и выходу любого посетителя и что-либо навязывать. В кибер-пространстве подобная оферта должна предоставлять как минимум аналогичные возможности в любой момент покинуть сайт (закрыть вкладку) без продолжения демонстрации нежелательного посетителю контента.
Любой творческий продукт как музыка или видео — тоже допускают свободу в плане вкл/выкл когда угодно, регулировки громкости, яркости, и промотки при наличии тех. возможности. Поэтому адблок можно считать еще одним подобным регулятором в руках пользователя. Ведь даже при просмотре ТВ зритель не связан договором, запрещающим выключать звук или отходить от экрана на время рекламных пауз.
И уж тем более абсурдно вменять ответственность за благоденствие или разорение владельцев сайта. Это все равно что обвинять уходящих без покупки посетителей из магазина в разорении его владельца.
dtestyk 8 ноября 2015 в 04:48 0
заходя на этот сайт вы обязуетесь просмотреть рекламу
Можно поставить расширение, блокирующее все упоминания и ссылки на подобные сайты, как malware:
«несанкционированными» будут считаться действия программы, не одобренные явным образом пользователем этой программы
Если такой сайт и будет существовать, пользователь о нем не узнает.

Как крайний вариант — настраиваемое устройство, бьющее пользователя током, каждый раз, когда он обращает внимание на рекламу :)
kopch 7 ноября 2015 в 17:30 0
Надо добавить в addblock функцию отключения только анимированной рекламы.
resetnow 7 ноября 2015 в 17:36 0
Яндекс.почта доставляет рекламу в том же HTTP-запросе, в котором идет тело письма, список писем и т. д. Блок вставляется с абсолютным позиционированием с классами, похожими на те, что встречаются в списке писем. В принципе, не страшно, т. к. реклама текстовая. Только я один раз случайно кликнул по рекламе одежды для полных женщин и теперь мне всегда показывают рекламу одежды для полных женщин.
DragonRU 9 ноября 2015 в 23:55 +1
Меня вот интересует — а почему «переходить на темную сторону» могут только рекламщики? Как вам такое решение — вместо того, чтобы исключать назойливую рекламу из страницы, подтолкнуть поставщика рекламы разорвать все отношения с этим клиентом? То есть, запустить скрипт, имитирующий максимально наглую и тупую накрутку кликов на этот баннер. Подозреваю, что у сайтовладельца могут возникнуть проблемы с доказательством, что этот скрипт запустил не он.
esc 10 ноября 2015 в 01:25 0
Замахаетесь скрипты писать. Рекламщики уже закладывают довольно большой процент склика, если речь идет о назойливой рекламе. И кстати большенство «скриптов» и так отсекаются т.к. вебмастера тоже не гнушатся ими пользоваться.
Raegdan 12 ноября 2015 в 23:49 0
В адсенсе / яндекс-директе я ничего плохого не вижу (если он конечно не всплывает оверлеем поверх сайта), а с разноцветным мигающим говном, которое лезет изо всех дыр, могли бы очень неплохо бороться сами поисковики, если бы хотели. Просто делать таким сайтам SEO с отрицательным знаком и/или предупреждать, как это делают в отношении вирусов: «Этот сайт содержит назойливую рекламу». Итог:

1) поисковик в плюсе — минус конкурент его родной рекламной системы, плюс благодарность от пользователей
2) пользователи поисковика в плюсе за повышение информативности выдачи
3) баннерную сеть не жалко, потому что она занимается засиранием интернета, как любой спамер
4) вебмастера, который в погоне за прибылью решил, что сношать в глаза своих пользователей допустимо — тоже не жалко.
Sergey6661313 20 февраля 2016 в 18:43 0
Есть ещё кто живой?
Подскажите пожалуйста как мне заблокировать рекламу по тому КУДА она ведёт? Уж очень много рекламы последнее время появилось в виде обычной картинки на весь экран на заднем фоне.
qw1 20 февраля 2016 в 21:28 (комментарий был изменён) 0
Я часто именно такие правила и пишу, потому что пошла мода размещать банер у себя на сайте, но хоть по таргету ссылки можно выявить рекламу
Например:
##a[href^="http://ad.adriver.ru/cgi-bin/click.cgi?"]

Но с задним фоном зачастую по-другому всё, обычно там событие onClick и правилом AdBlock не срезать, только NoScript/GM
Sergey6661313 20 февраля 2016 в 21:51 0
Спасибо большое.
Изображение

dyvniy M
Автор темы, Администратор
Администратор
Аватара
dyvniy M
Автор темы, Администратор
Администратор
Возраст: 41
Репутация: 1
Лояльность: 1
Сообщения: 3579
Зарегистрирован: Ср, 10 октября 2012
С нами: 11 лет 5 месяцев
Профессия: Программист
Откуда: Россия, Москва
ICQ Сайт Skype ВКонтакте

#30 dyvniy » Пн, 9 апреля 2018, 18:37:47

ДжаваСкрипт на самом деле быстрый! )
Тормозит в ней ДОМ
https://habrahabr.ru/post/281879/
Спойлер
Почему JavaScript работает быстрее, чем С++?
JavaScript


Да, вы не ослышались. Глючный, тупой, тормознутый JavaScript работает быстрее, чем С++. Подождите тянуться к return userKarmaVote(), дайте мне возможность всё объяснить. Адвокат!

Есть три вида лжи

Есть такой проект под названием Benchmarks Game. Ребята написали программы (обход бинарных деревьев, n-body и т.д.) на всех популярных языках программирования и разработали методику измерения скорости и потребления памяти. Прежде чем читать дальше, просьба ознакомиться с методологией измерений.
Реализация каждого алгоритма подробно описана (например, nbody). Это open-source и если вы считаете, что какой-то алгоритм реализован не самым оптимальным способом, то можете предложить собственное решение.

Из всех интерпретируемых языков JavaScipt работает быстрее других. Он в пять раз быстрее, чем Python и Ruby (в том числе JRuby).



На сегодняшний день JavaScript — это самый быстрый интерпретируемый язык в мире.
Возвращаясь к C++. По алгоритму regexdna JavaScipt отрабатывает чуть быстрее, чем C++. При этом нагружает CPU в два раза меньше, хотя и потребляет в два раза больше памяти.
По другим алгоритмам JavaScript, естественно, отрабатывает медленнее C++, но учитывая что они изначально в разных весовых категориях (компилируемый язык со статической типизацией против интерпретируемого языка с динамической), разница не такая уж большая.

Почему JavaScript такой быстрый?

Интерпретаторы для Python/Ruby были написаны ограниченным числом людей. Эти люди, возможно, безумно талантливы, но на стадии разработки у них не было никакой конкуренции. Они конкурировали только с собой, со своими представлениями о скорости и качестве. Интерпретатор же для JS родился в конкурентной борьбе лучших умов мира. Mozilla разработала SpiderMonkey, Google разработал V8, Microsoft открыли Chakra. Все они работали в жесточайшей конкурентной борьбе.

Когда у команды NodeJS встал вопрос о выборе движка для JS, они просто посмотрели бенчмарки, увидели что V8 намного быстрее и выбрали его. Если завтра Chakra от Microsoft будет работать быстрее Google V8, то не будет никакой проблемы перейти на него.

Почему JavaScript такой медленный?

Как было сказано выше, JavaScript как язык — быстрый. Однако считается, что «нативное» предназначение JS — манипуляции с DOM. На самом деле это уже давно не так и JS успешно используется на сервере, в мобильных устройствах и даже в микроконтроллерах. Но речь не об этом. Речь о том, что когда вы с помощью JavaScript работаете с DOM, то тормозит не JS, а DOM. Есть много причин, почему DOM такой медленный, но я позволю себе сузить фокус только на одной причине. Проблема в самой спецификации HTML. В разделе 1.1.1 The DOM Structure Model есть следующий абзац:
…objects in the DOM are live; that is, changes to the underlying document structure are reflected in all relevant NodeList and NamedNodeMap objects…

Смысл в том, что объекты в дереве DOM — «живые». Это означает, что при любом изменении любой части DOM эти изменения отражаются в каждом объекте DOM.
Крупные кампании, такие как Flipboard, упорно боролись с лагами DOM. В итоге у них ничего не получилось и они смогли добиться 60 FPS только заменив DOM на Canvas. JavaScript никуда не делся, а лаги пропали. По этой же причине Netflix отказались от DOM на своих TV-приставках, а Реакту пришлось придумывать свой «виртуальный DOM».

Еще раз: JavaScript на клиенте не лагает. Лагает медленный DOM (точнее манипуляции с DOM). Не важно чем вы будете менять DOM — джава-скриптом или ассемблером. DOM все равно будет притормаживать. Именно из-за тормознутости DOM, JavaScript стал считаться медленным языком. Это историческая несправедливость и от нее давно пора избавиться.

WebAssembly

В этой связи у многих существуют неоправданные ожидания от прихода WebAssembly. Дескать, придет WebAssembly порядок наведет и мы наконец-то откажемся от «тормознутого» JS. Во-первых, даже после прихода WebAssembly работа с DOM останется за JavaScript. Да, какие-нибудь фреймворки (типа AngularJS) получат возможность перенести тяжелую логику на C/C++, но суммарный прирост от этого будет минимальным. Во-вторых, когда WebAssembly сможет напрямую манипулировать DOM'ом, минуя JS, прироста по скорости не будет, т.к. тормозит DOM, а не JS.

Хейт

Я понимаю, что скорость работы — не главный критерий оценки языка. Нужно учитывать потребление памяти, нагрузку на CPU и т.д. Я понимаю, что одно дело — скорость работы каких-то академических алгоритмов, а другое дело — скорость работы настоящего продакшн-приложения. Я понимаю, что кроме алгоритмов есть еще паттерны и подходы, и что ваш асинхронный ASP.NET может работать быстрее асинхронного NodeJS.

Однако JavaScript уже достаточно подвергся нападкам (заслуженным и незаслуженным) за свое «странное» поведение, за свое отношение к типам, к наследованию и т.д. Но вешать на него еще и ярлык тормознутости — это перебор. Остановитесь!
Изображение


Название раздела: Web на стороне клиента, Java Script
Описание: Наиболее перспективное направление развития компьютерных наук. Надо быть в теме!

Быстрый ответ


Введите код в точности так, как вы его видите. Регистр символов не имеет значения.
Код подтверждения
:) ;) :hihi: :P :hah: :haha: :angel: :( :st: :_( :cool: 8-| :beee: :ham: :rrr: :grr: :* :secret: :stupid: :music: Ещё смайлики…
   

Вернуться в «Web на стороне клиента, Java Script»

Кто сейчас на форуме (по активности за 15 минут)

Сейчас этот раздел просматривают: 5 гостей