Is it possible to define functions conditionally for different modern browsers, such as Safari?

What is the most effective method for conditionally defining functions in modern browsers?

I have noticed that Safari 12 (iOS 12.0.1 and macOS 10.14) does not correctly define conditional functions, while Chrome, Firefox, and Edge behave correctly. I am curious about the standard behavior for a JavaScript engine so that I can report this potential bug to Apple if necessary.

Context: We are implementing this approach to prevent Google Analytics (gtag.js) from loading unless a user consents to GDPR. The initialization code for Google's gtags.js contains a line

function gtag(){dataLayer.push(arguments);}
which causes issues in Safari.

Below is the code snippet, with a demo available at JS Fiddle

<html>
  <head>
    <title>Safari JS Engine Test</title>
    <script type="text/javascript">
      if (false) {
        function conditionalFunctionality() {
          alert("Performing conditional functionality");
        }
      }
      window.onload = function() {
        if (typeof conditionalFunctionality === "function") {
          alert("BAD. It's defined");
        } else {
          alert("GOOD. It's NOT defined");
        }
      }
    </script>
  </head>
  <body>
    <h1>Safari JS Engine Test</h1>
  </body>
</html>

Mugshots

https://i.sstatic.net/Y87Tfl.jpg https://i.sstatic.net/UdEIUl.png

Answer №1

It has been pointed out in the previous comments that function definitions may behave unexpectedly when not placed at the "top level." Take for example:

a()
function a() { console.log("here"); }

In this scenario, the console will log the message even though the function definition comes after its usage. This phenomenon is known as hoisting in Javascript, and you can find a detailed explanation here:

(thanks to pointy)

Different web browser versions handle hoisting differently, resulting in the inconsistency you may be experiencing. This is why using "strict" mode (i.e., including "use strict"; at the beginning of your code block) can modify this behavior.

Personally, when I want to achieve similar functionality, I prefer using "function expressions." This would look something like:

var conditionalFunctionality;
if (false) {
  conditionalFunctionality = function () {
    console.log("conditionally defined");
  }
}
if (conditionalFunctionality) {
  conditionalFunctionality();
}

This approach also offers the advantage of naturally handling falsy values without requiring checks like

typeof conditionalFunctionality === "function"
.

Answer №2

In response to Pointy's comment, it is not recommended to conditionally define functions but rather define the function for all browsers and execute code in the body conditionally based on the browser.

If you want to learn how to detect specific browsers, check out this informative post on stackoverflow: How to detect Safari, Chrome, IE, Firefox and Opera browser?

For example, you can create a function like this:

function f(...) {
    if (isSafari()) {
        // Add Safari-specific functionality
    else {
        // Add other functionality
    }
}

The isSafari function should be a wrapper around a browser check as demonstrated in the stackoverflow post linked above.

EDIT: If you need to base the execution on specific functionality rather than browsers, replace isSafari with a function that checks if the current browser supports the desired functionality instead of checking the browser type.

The provided link actually assesses the browser's capabilities to identify which browser is being used, so you can use that approach to address your problem effectively.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am looking to consolidate my array of objects into a single object with distinct keys

Hey there! I'm looking to showcase the expenses for each category throughout the months of the year. Here's an example: {Month: "January", Food: 610, foodColor: "#063951", Others: 121, othersColor: "#C13018", …} Fo ...

Refreshing Element in Django Using AJAX

My goal is to dynamically alter selection options on a page without requiring a full reload. The changes should be based on an id received from the dynamic value of an element on the same page. I've attempted to implement this using AJAX, but for some ...

Encountering syntax errors in GraphQL

Currently, I am in the process of working on the GraphQL Node tutorial and have reached step 7. Visit this link to view Step 7 While implementing the code in my datamodel.prisma file, I encountered several syntax errors: directive @id on FIELD_DEFINITIO ...

Having trouble retrieving user login information in Postman

I have encountered an issue while creating a REST API using Node js and expressJs. When attempting to create a user, I successfully implemented the following code: /** * save user data from the user model */ router.post("/users", async (req, res) => ...

Having trouble displaying toasts on my website using Angular Material design and $mdToast

Hello there, I am very new to AngularJS, and I have just started using the basic function Show() from $mdToast. Below is the complete code that I have written for this issue, and I would greatly appreciate any help you can provide. 'use strict&apos ...

How can I implement Before() and After() hooks within a hooks.js file for a Selenium and JavaScript project?

Within my Selenium JS / Cucumber framework, I have incorporated Before() & After() functions to handle the setup and tear down of my webdriver. To manage these functions, I decided to organize them in my customSteps.js file alongside other cucumber st ...

Guide on adding HTML to an array every third time for displaying

Is there a way to generate div elements every 3 times in a for loop without outputting them as HTML? Any suggestions on how to achieve this? render() { const squareItems = []; for (var i=0; i < 9; i++) { if ((i % 3) == 0){ ...

Evaluating Vue.js Watchers using Jasmine

I want to write a test for a VueJS watcher method, in order to verify if it's being called. The watcher method in my component is structured like this: watch: { value: (newValue, oldValue) => { if (newValue.Status === 'Completed') ...

Choosing an option in Vue using select, v-for loop, and v-model

How can I set a preselected option in a select element using v-model, v-for for options, and an object as the value? The options are elements with unique ids, and I want to preselect based on custom equality (e.g., matching the id field). Is there a way to ...

Exploring the challenges of implementing the Lob Node API wrapper within a MeteorJs project due to conflicts with the 'fs' module

I recently updated to the latest version of Meteor (1.13) which now supports NPM. I decided to add the Lob.com NPM to my project and started working on a letter function. However, I encountered the following error: Uncaught TypeError: fs.readdirSync is ...

Display the elements of a div at a reduced size of 25% from its original dimensions

I'm currently developing a JavaScript-based iOS simulator that allows users to view their created content on an iPhone and iPad. This involves using AJAX to load the content/page into the simulator, but one issue is that the simulator isn't life- ...

Tips for utilizing the Struts2 submit tag as a button without triggering form submission

I am currently utilizing the Struts2 framework in my application, and I have a button on my JSP page. Here is the code for the button: <s:submit type="button" name="btnSave" /> However, I want this button to act like a normal HTML button, meaning i ...

When conditionals are used to infer function parameters in TypeScript, they may end up with the type 'never'

Problem with Typescript Parameter Type Resolution: functionBuilder takes a parameter arg and returns an object with a function property based on the value of arg. If arg === 'a', the function expects a string parameter, otherwise it expects a nu ...

Opening a window using Javascript with a PHP Ajax response

I'm attempting to use echo in a controller to return the content below in an AJAX response: $url = url('/expert-profile-view')."/".$request->ticket_id."/".$key->user_id; $url = "<a onclick='window.open('$url','m ...

What is the best way to retrieve the value of a select tag in Vue JS?

Delving into Vue JS has presented me with a challenge. I'm aiming to retrieve the value of the selected option. But unfortunately, I'm stuck. Despite my efforts to scour Google for answers, I have come up empty-handed. Below is a snippet of m ...

Detect when a user's mouse is hovering over an iframe and escape the iframe accordingly

When the iframe window is visible, there are no issues. However, if the iframe window is set to 0px X 0px in order to hide it while still loading, consider redirecting the iframe or not displaying it at all. In case something is loaded within an iframe or ...

Tips for including parameters in an array of values when using getStaticPaths

I'm trying to retrieve the slug value that corresponds with each number in the getStaticPaths for my page structure: /read/[slug]/[number]. The code I have is as follows: export async function getStaticPaths() { const slugs = await client.fetch( ...

Exploring the Node.js Connector: Utilizing Collection.remove

I can't wrap my head around the meaning of this: w, {Number/String, > -1 || ‘majority’ || tag name} the write concern for the operation where < 1 is no acknowlegement of write and w >= 1, w = ‘majority’ or tag acknowledges the ...

What is the process for adding content to a textarea field?

Is there a way to dynamically update a textarea using PHP and trigger the refresh of the textarea? APPRECIATE IT Edit: The solution should be initiated by server-side PHP code ...

Incorporate conditional components into a React state object

I have a variable called myVar that holds an array of values. I am trying to selectively add elements to the array based on a specific condition. For example: If the condition is met: myVar = [1, 2, 3] Otherwise: myVar = [1, 2, 3, 4, 5] In both cases ...