[Wanted] Bytedance Massive Star /TCM team continues to recruit front-end engineers, see additional information below

The purpose of this article is to share some of the rarest and most outrageous features of JavaScript. Most of these features are the result of historical factors, as we all know, Eich only took 10 days to design and implement the first version of JS, and those 10 days left the Web with a lot of hidden holes in addition to a top scripting language…

Of course, I’ve only listed a few representative ones here, but there are a lot of old features that are not mentioned, such as changes to logical operators and so on. If you’re interested, you can read JavaScript 20 years or something else.

Reference: web.archive.org/web/2019032…

Function#arguments

If I were to ask you, what are the properties that are unique to a function? How many can you think of?

Call, apply, and.bind are all function methods. But what else?

Those of you who are smart might also think that functions have name and length attributes, which represent the name of the function and the length of the argument. In fact, in addition to that, functions have two special properties: arguments and Caller.

function a(foo) {
  a.arguments[0] / / 1
  a.caller == b // true
}
function b() {
  a(1)
}
b()
Copy the code

 

You’re probably already wondering: Arguments aren’t local variables within functions? In fact, arguments was an attribute of the function in the original design. This seems to make a lot of sense, given the speed of implementation, and the fact that it hangs directly on a function rather than implementing a special local variable. During function execution, the Arguments property is the collection of arguments for this execution; Outside of function execution, the arguments property is null. This practice still exists today.

In JavaScript 1.0, however, this introduced a very bizarre feature:

function a() {
  a.arguments == a // true
}
a()
Copy the code

Function and arguments attribute references are identical! I don’t know why, but it looks like a new Bug to implement A.decorations. Caller === A. caller.

It wasn’t until JavaScript 1.2 (released with SpiderMonkey, Navigator 4) that arguments became a special local variable and the Bug was eliminated.

 

Quick students may have tried this in their own console, but may find it inconsistent with what I said:

(() = > {}).arguments // It is null
Copy the code

This is because arrow functions do not have arguments local variables. As with this, the arguments attribute of the arrow function is a reference to an external object. However, for semantic consistency, you can’t call a function from which the arguments attribute is not its own. Therefore, calling the arguments attribute of the arrow function will always raise an error. It looks as if this function turns on strict mode.

Reference: cn.history.js.org/part-1.html…

Arguments

Having said arguments properties of functions, let’s talk about the Arguments object itself.

A few years ago, you might have often seen code like this:

var args = [].slice.call(arguments)
Copy the code

Even now, you can still see this in some browser script code. As you can see, the above code converts arguments to an array. Although there are performance issues with this usage, this actually says one thing: Arguments are not arrays. In fact, it is an instance of the Arguments function (note: since there was no concept of classes in early JS, it is called “functions” here).

So the question arises: Why is Arguments not an array?

 

As many of you might have guessed, arguments has a callee attribute, and we don’t usually see arrays with special attributes. If you feel the same way, try:

/a/g.exec('a')
Copy the code

Or for ES2015:

console.log` `
Copy the code

These examples prove that arguments are not special even for arrays.

 

Those of you familiar with language features may know that arguments objects have the “bidirectional binding” feature, which means:

function a(foo) {
  foo / / 1
  arguments[0] = 2
  foo / / 2
}
a(1)
Copy the code

(It’s worth noting that this feature was undefined behavior prior to ES3.)

This feature might still seem strange: even today, with propertyDescriptors and proxies, it seems difficult to modify a reference to a variable indirectly.

However, it may be easier to understand if you combine it with another feature. In JavaScript 1.1 (shipped with Navigator 3), arguments added a new feature:

function a(foo) {
  foo / / 1
  arguments.foo / / 1
  arguments.foo = 2
  foo / / 2
  arguments.arguments == arguments // true
}
a(1)
Copy the code

Does it look familiar? If you’ve used Vue, have you ever thought arguments would look like this in a template? Or, in fact, the above code has the equivalent semantics of the following code:

function a(foo) {
  with (arguments) {
    foo / / 1
    arguments.foo = 2
    foo / / 2
  }
}
a(1)
Copy the code

Incidentally, in JavaScript 1.0, instances of Object also have this functionality:

var a = new Object()
a.foo = 1
a[0] / / 1
Copy the code

So, that’s why arguments are not arrays but objects… However, no! An important issue is that just as Arguments supported this feature in JavaScript 1.1, Object just removed it, which at least shows that Eich still thinks arguments and objects are not the same thing.

 

The reason for this is simple: as mentioned earlier, the arguments attribute comes from version 1.0 of JavaScript, where arrays are not implemented yet! Although the Array function has been around since JavaScript 1.0, the only difference between it and Object is that the string displayed during debugging is [Object Array]. That’s right, no prototype methods, no length property, it’s just a normal object!

Array wasn’t fully implemented until JavaScript 1.1.

Reference: cn.history.js.org/part-1.html… Cn.history.js.org/part1.html#…

Array.of= = =

These two are put together because they are very similar, the only difference is when they were born.

First ===, we’re all familiar with JS having two sets of equivalence decisions: == and === (actually three, and [SameValue] (Object. Is, which at one point was almost the Python-like is keyword). The main difference is whether implicit type conversions are performed.

Back in the days of JavaScript 1.0 and 1.1, when Eich was the only JS developer and only had a set of methods for determining ==, Eich realized that the implicit conversion of == was a pitfall. Then in JavaScript 1.2, Eich and the new JS development team decided to change the behavior of == to something closer to what we see === today.

Unfortunately, IE 3 was released with JScript built in as an alternative implementation of JavaScript, which was at odds with Netscape’s JavaScript in this and many other areas. To avoid this, Netscape (naively) teamed up with Microsoft to form the JS language specification group, now known as TC39.

During the development of the ES3 standard, Katzenberger from Microsoft first discovered that changes to the language would cause damage to existing websites, the so-called Web Reality, and he pointed to the type judgment feature of ==. Eich accepted this and rolled back the change in JavaScript 1.3. TC39 then started to develop ES3 and gave the solution ===.

 

It’s worth mentioning that in JavaScript 1.0, Eich also implemented a feature that treats if (a == b) as if (a == b). You may wonder how practical Eich’s experience as a programmer is, but actually this feature comes from GCC. The reason we don’t know this feature exists is because JavaScript 1.3 followed ES3 and removed it.

Also, how did Katzenberger, a Microsoft engineer, know so much about Netscape’S JavaScript? Because this person led the JScript support for IE 3 and found a lot of problems with Navigator and JavaScript by decompiling Navigator. That was one of the reasons for TC39.

 

As for array. of, it may not be familiar to all of you. It comes from ES2015 and is used to construct an array of all parameters:

Array.of(1.2.3) / / [1, 2, 3]
Copy the code

You might say, why don’t I just use the Array constructor? As mentioned earlier, the Array constructor comes from JavaScript 1.1, where, for convenience (and to look more Like Java), when an Array accepts only one parameter, that parameter is used as the length of the Array. As you can see, this practice still exists today.

In many cases this behavior is a pit. Also in JavaScript 1.2, the Array constructor was modified to always construct an Array using parameters. It is then rolled back in JavaScript 1.3 for the above reasons.

Unlike ===, it was not until nearly 20 years later that ES2015 gave a new solution to this problem: array.of.

Reference: web.archive.org/web/1997063…

'use strict'

If ES2015 exemplified the balance between radical and conservative in THE JS language, ES5 exemplified conservatism, with only two syntax changes: Getter/Setter and strict schema.

Strict mode, which gives developers the ability to actively disable some language capabilities to lighten the interpreter load, is unprecedented in JS, although I think it may have been inspired by the strict mode of ActionScript 3, the earliest JS dialect. However, it also reflects how many pits JS has accumulated over the years.

Strict schema syntax is something you’ve probably seen before: add ‘use strict’ to the top of the script or function body. For those of you who are familiar with Web ecology, this is a good idea: string literals as new syntax, compatible with older interpreters and capable of new functionality.

 

At this point, some of you might raise a valuable objection: ‘use strict’ isn’t ‘grammar’, is it? At most a code id, right? There are two aspects:

  • Strict schema does not necessarily require this syntax. For example, strict mode is enabled by default for ESModule files.
  • For files that meet strict schema requirements, the string is completely free to add or delete.

But is the second really true? Now we can open the console and type:

(function (. args) { 'use strict'}) ()Copy the code

Why is it wrong? A grammatical error? Doesn’t the above code conform to strict mode?

 

In fact, it is precisely this conservative design that causes strict mode directives to fail to achieve perfect forward compatibility.

At the beginning of the strict schema syntax design, the ‘use Strict ‘directive supports both script scope and function scope in consideration of granularity. Script scope was fine, but function scope already had compatibility issues at the time:

function a(let) { 'use strict' }
Copy the code

In strict mode, reserved words such as let cannot be used as parameter and variable names for forward compatibility. But this is a difficult implementation for the interpreter, because it means that subsequent statements affect whether the preceding syntax is correct.

The implementation of the interpreter at that time was usually: when parsing a function, take extra function name and parameter name information, and then later recognize strict mode instructions to determine whether to report an error. After all, it doesn’t cost much just to store a few names.

But soon, some interpreters were implementing features like parameter defaults before ES2015.

function a(foo = function b() {}) { 'use strict' }
Copy the code

So the question is, in this case, does function B have to follow a strict pattern? There was no definitive conclusion at the time, but in the ES2015 specification, it was stipulated that this situation should also follow a strict pattern.

That’s barbie. It’s not even a matter of storage, it’s even a matter of implementation. SpiderMonkey’s implementation has been modified several times, and the final implementation is: parse normally first, and if ‘use Strict ‘is encountered, go back and parse again.

Now the pressure is on V8 (Trident? Need to think about it?) . V8 was discussed and the final result was…

Is……

 

In ES2016, it is stipulated that the ‘use strict’ directive is prohibited for functions that contain default values and remaining arguments (that is, functions that contain the new ES2015 syntax), which we see now.

After all, the goal is to keep the cost of the compiler down.

Reference: web.archive.org/web/2007081… (note: Crockford is also a profound impact on JS bosses: JSON’s creator and author of JS language essence,) bugzilla.mozilla.org/show_bug.cg…

About the comments

Quick question: how many comment formats does JS have?

When I was learning front end, I could always find a website called W3CSchool. Just now, I was googling [JS annotation] and it was still very high up. There are two types of single-line comment // and multi-line comment /**/.

But as some older front-end engineers might know, JS actually has another single-line comment, which starts with

 

The younger students are like, what? Isn’t this an HTML comment? Should it be a multi-line comment?
a couple. Don’t worry. This is how it happened:

 

JavaScript 1.0 came out with Navigator 2, and that’s when HTML started to have the

Eich is no ordinary man. He points out that developers can achieve compatibility with other browsers in this way:

<script>
<! -- alert('hello') -->
</script>
Copy the code

Older browsers then treat the contents of the script as HTML comments and do not display them.

 

But now there’s a new problem:
are not JS syntax. Eich says that as long as JS supports
, just add a // before it.

<script>
<! -- alert('hello') // -->
</script>
Copy the code

This way, the above code will be correctly parsed whether the browser supports

However, this syntax has never been considered part of the JS language, because JS has always considered itself a separate language, independent of HTML, even though this usage is already widely used.

It wasn’t until ES2015 that JS finally woke up to the reality and began to formalize some widely used “features” into the standard. In addition to the __proto__ attribute seen on the front end, there is the

Reference: www.w3school.com.cn/js/js_comme…

About the DOM

document.all

Consider how to construct a value that meets the following conditions:

let a = ?

typeof a // 'undefined'
Boolean(a) // false

a instanceof Object // true
Copy the code

For the first two you would expect undefined, but for the third… Is that possible? That means a is an object, but its type is undefined? Is this really JS?

 

It’s back to the days of Navigator versus IE. At the time, IE quickly launched IE 4 to compete with Navigator, which had orthodox JavaScript. Although ES3 has defined the JS language specification, the DOM is free to add functionality. So IE implemented a super convenient API: document.all.

The value of document.all is an HTMLAllCollection, which means:

  • It contains all the elements in the page
  • It changes dynamically as the page structure changes
  • You can usedocument.all.fooaccess#fooElement, you can also use itdocument.all.namedItem('foo')access[name='foo']The element

Junior front-end engineer direct call easy to use, online code arranged:

document.all.foo.style.color = 'red'
Copy the code

Senior front-end engineers are more cautious: I don’t use code that isn’t perfectly compatible, but I can use it to determine the environment:

if (typeof document.all ! = ='undefined') {
  alert('It is IE! ')}Copy the code

IE then released 5 and 6, and eventually killed Navigator. During this time, there was a browser that took advantage of the chaos and its name was Opera. Opera standard IE implements Document. all to support websites written by junior front-end engineers.

But there was a problem, this time the site written by a senior front end engineer didn’t work on Opera. Opera says there’s really nothing I can do about it this time, and ultimately Opera still can’t compete with IE.

 

Until Navigator finally changed the Firefox vest to resurrect. As a Developer of Firefox, Eich says we want to take back what’s ours! So Firefox also implements document.all, but clever Eich has a Hard Code here: We support document.all, but:

typeof document.all // 'undefined'
Boolean(document.all) // false
Copy the code

Firefox is thus perfectly compatible with websites written by junior and senior front-end engineers without breaking the existing network.

 

Safari soon joined the fray. Safari takes a page from Firefox and implements Document.all in Webkit in the same way. This directly affects Chrome, which uses Webkit, and its JS engine V8.

The browser wars are starting again with Chrome. Opera, with its last stubbornness, changes typeof Document. all to ‘undefined’. All browsers have finally decided to fight IE together and have successfully written this behavior into the HTML5 specification.

 

At the end of the story is IE. For compatibility with Chrome’s features, IE 11 also changes typeof Document. all to ‘undefined’.

Soon, ES2015 was released. As mentioned earlier, the JS specification finally recognized the reality by specifying that a value in the language can have an internal property called [IsHTMLDDA]. If it does, the Typeof operator returns ‘undefined’ and the ToBoolean value returns false.

Who says DOM can’t affect JS in reverse?

Reference: html.spec.whatwg.org/multipage/c… Tc39. Es/ecma262 / # se…

The global variable

Experienced students reading the previous section might wonder: Don’t we already have a way to access ids globally? Why document. All?

In case you don’t understand, the feature looks like this:

<div id="foo"></div>

<script>
window.foo // [object HTMLDivElement]
</script>
Copy the code

As you can see, an element with an ID attribute becomes an attribute of the Window object directly, which means it becomes a global variable. And as you can imagine right now, this feature, it was originally implemented in IE as well. As in the previous story, Opera copied IE, Firefox copied IE, Safari copied Firefox, Chrome inherited Safari and eventually became the standard… But is that the end of it?

 

Unlike document.all, global variables contain not only elements with an ID attribute, but also possibly a name attribute: The Embed Form Frame Frameset iframe IMG Object element with the name attribute also becomes a global variable.

Before you say that, maybe now you’re in the habit of asking: Why?

 

Both TC39 and W3C were created for the sake of unification itself, in this case Navigator and IE.

Doesn’t seem like a connection, does it? In fact, the id attribute was introduced by Internet Explorer. Before that, Navigator used the name attribute. But names are not unique and lack a direct connection to the stylesheet, so the W3C marks non-form element names (that is, the ones mentioned above) as deprecated, but remain in the specification.

Navigator could not accept this result until its demise. Internet Explorer, the great competitor that had been accommodating it, chose to take the specification they had built together and carry it along in spirit, eventually bringing it into HTML5.

Reference: html.spec.whatwg.org/multipage/w…

[Wanted] Bytedance Mega Star /TCM team is looking for a front-end engineer

About us

Relying on the rich talent ecosystem and product capabilities of Douyin /TT, the huge Star Map front end team of Byte Commercialization effectively connects creators and advertisers, inspires the marketing value of high-quality creation, and grows from a small project to an independent business of the group in three years. We look forward to your joining us!

How to help creators realize better? _bilibili bilibili

For more details about the team/business, please refer to the front-end paradise or overtime hell? Tell me about my year in Byte.

If you are

  • Advocate freedom, and want to do excellent things with excellent people;

  • Love front-end, love technology, the pursuit of perfection;

  • Self-driven, responsible;

  • King of Glory players, the team everyone king section, come and join us on the score!

Welcome to join us, we have a large number of recruitment of front-end engineers, club/school recruitment/intern, ability level is not limited, work in Shanghai/Beijing/Hangzhou/Mountain View!

Look forward to the excellent you to join the big star map team!

Consulting with

If you want to know more about the business, the team and the position, you can add Cun Zhi wechat: Island205, email: [email protected], and TL direct communication!

Resume direct investment

Remember to note the directional big star map front end team oh!

Front-end Development Engineer (Shanghai) — Creativity and Ecology

job.toutiao.com/s/NSMLh2N

Star Map Platform front-end development engineer (Hangzhou) – Creativity and Ecology

job.toutiao.com/s/NSMYNmm

Frontend Engineer, TikTok Ads Creative & Ecosystem

job.toutiao.com/s/NS6KNHt

Frontend Engineer, TikTok Creator Marketplace (Los Angeles)

job.toutiao.com/s/NSMjkrH

Front-end Development Intern (Shanghai/permanent) – Creativity and Ecology

job.toutiao.com/s/NS65GKU

Front-end Development Intern (Hangzhou/permanent) – Creativity and Ecology

job.toutiao.com/s/NS6K9n2