javascript

Python 和 JavaScript 语法对比

Python 和 JavaScript 语法对比

命名

  1. 注意使用驼峰变量名,不要使用下划线变量名

字符串

格式化

JavaScript:

`hello ${name}`

Python:

f"hello {name}"

文件

打开文件:

JavaScript:

const fs = require(fs).promises;  // 使用 async/await 版本的 fs 模块

await fs.writeFile(filename, data);  // 写入文件

// 文件是否存在
try {
  await fs.stat(filename)
  exitst = true
} catch (e) {
  exists = false
}

Python:

with open(filename, w) as f:
      f.write(data)

  os.path.exists(filename)  # 文件是否存在

数组

切片:

JavaScript:

const arr1 = arr2.slice(3, 5);

Python:

arr1 = arr2[3:5]

html Node vs Element

  • Node vs Element

HTML Document consists of different node, element is one type of node.

  • NodeList vs HTMLCollection

NodeList is a collection of node, HTMLCollection is a collection of element.

  • HTMLCollection vs NodeList vs Array

HTMLCollection 和 NodeList 都是动态的,会随着 DOM 的变化而变化

Array 是静态的数据结构

浏览器用于替换 ajax/xhr 的 fetch api

fetch 是近年来浏览器实现的一个用于取代 xhr 的 API,相比于 xhr 来说更加简单易用安全且强大。主要区别有:

  • fetch 基于 promise,可以使用 await 直接调用;
  • fetch 对于 400 和 500 错误依然会正常返回而不会报错。只有在网络错误的时候才会抛出异常;
  • fetch 默认只会携带同一个域名下的 cookies,也就是 same-origin,默认更安全;
  • fetch 不接受跨域的 Set-Cookie。

基本用法

如果要在 node 中使用的话, 需要安装 isomophic-unfetch:

yarn add isomorphic-unfetch
import fetch from 'isomorphic-unfetch'

const response = await fetch("http://example.com/movies.json");
const myJson = await response.json(); // text() 返回纯文本
console.log(JSON.stringify(myJson));
  • response.ok 是否请求返回了 2XX 代码
  • response.status 返回的状态码,比如 200, 404 等
  • await response.blob() 返回二进制文件
  • await response.text() 返回文本文件
  • await response.json() 返回解析的 json

增加选项

try {
  // Default options are marked with *
  const response = await fetch(url, {
    method: "POST", // *GET, POST, PUT, DELETE, etc.
    mode: "cors", // no-cors, *cors, same-origin
    cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
    credentials: "same-origin", // include, *same-origin, omit
    headers: {
      "Content-Type": "application/json"
      // "Content-Type": "application/x-www-form-urlencoded",
    },
    redirect: "follow", // manual, *follow, error
    referrer: "no-referrer", // no-referrer, *client
    body: JSON.stringify(data) // body data type must match "Content-Type" header
  });
  console.log(await response.json());
} catch (error) {
  console.error(error);
}

携带 cookies

fetch 的 credentials 有三个选项:

  • omit 不携带任何 cookies
  • include 携带所有 cookies
  • same-origin 只有向当前网站的同源域名发送请求时才携带 cookies

其中 same-origin 是默认选项。

使用自定义 headers 和 request

const headers = new Headers();
headers.append("Content-Type", "text/plain");
headers.append("Content-Length", content.length.toString());
headers.append("X-Custom-Header", "ProcessThisImmediately");

// 另一种方法是直接使用字典
const headers = new Headers({
  "Content-Type": "text/plain",
})

const init = {
  method: "POST",
  headers: headers,
  mode: "cors",
  cache: "default",
}

const request = new Request("flowers.jpg", init);
const rsp = await fetch(request);

参考

  1. https://developer.mozilla.org/en-US/docs/Web/API/FetchAPI/UsingFetch
  2. https://stackoverflow.com/questions/34558264/fetch-api-with-cookie
  3. https://developer.mozilla.org/en-US/docs/Web/API/Request/credentials

JavaScript snippets

get parameter from url

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}

JavaScript 网页选择 API

basics

window.getSelection and document.getSelection all returns the Selection object, the selection object is almost useless.

window.getSelection.getRangeAt(0) returns a Range object. for history reasons, there is only one range in each selection.

rangeAncestor = range.commonAncestorContainer; commonAncestorContainer is the common ancestor of the range elements.

EcmaScript 6

using es6 with babel

debugging mode

<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel">
// Your ES6 code
</script>

production mode

babel script.js --out-file script-compiled.js

Yifei’s Notes

the main impovements of ES6 are loops and generators, let/const, arrow functions, class syntax small pieces are function arguments, destructuring

Looping

there are 3 ways to loop a sequence in ES5, but there are problems

ES5 Loops

// not concise
for (var index = 0; index < myArray.length; index++) {
    console.log(myArray[index]);
}

// no break or return
myArray.forEach(function (value) {
    console.log(value);
});

// for objects, not arrays
for (var index in myArray) {
    // don't actually do this
    console.log(myArray[index]);
}

Introducing ES6 Loops

// concise and correct
for (let value of myArray) {
    console.log(value);
}

// also works on strings, sets and maps
for (let chr of "") {
    alert(chr);
}

// make a set from an array of words
 var uniqueWords = new Set(words);
for (let word of uniqueWords) {
  console.log(word);
}

for (var [key, value] of phoneBookMap) {
    console.log(key + "'s phone number is: " + value);
}


// you can even make it work with objects
// dump an object's own enumerable properties to the console
for (var key of Object.keys(someObject)) { console.log(key + ": " + someObject[key]); }

Generator

Inside a generator-function, yield is a keyword, with syntax rather like return. The difference is that while a function (even a generator-function) can only return once, a generator-function can yield any number of times. The yield expression suspends execution of the generator so it can be resumed again later.

Generator functions are basically the pause-and-continue-able function. when you call a generator function, it returns an paused Generator object, which has a next() function, each time you call the next() function, a pair of yielded-value and status is returned.

In technical terms, each time a generator yields, its stack frame—the local variables, arguments, temporary values, and the current position of execution within the generator body—is removed from the stack. However, the Generator object keeps a reference to (or copy of) this stack frame, so that a later .next() call can reactivate it and continue execution.

function* fibs() {
  var a = 0;
  var b = 1;
  while (true) {
    yield a;
    [a, b] = [b, a + b];
  }
}


function* range(start, stop) { for (var i = start; i < stop; i++) yield i; }

// This should "ding" three times
for (var value of range(0, 3)) {
  alert("Ding! at floor #" + value);
}

This is possible because generators are iterators. All generators have a built-in implementation of .next() and Symbol.iterator.

Template Strings

Hello ${user.name}, welcome to our server for the ${times} times

Rest Parameters and Defaults

ES5 version

function containsAll(haystack) {
  for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
      return false;
  }
}
return true;
}

ES6 version

function containsAll(haystack, ...needles) {
  for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
      return false;
  }
}
return true;
}

ES6 supports default parameters, The default argument gets evaluated at call time, so unlike e.g. in Python, a new object is created each time the function is called.

Class

ES6 support static method, supuer, getter/setter, you can even subclass builtin types

class Circle {
    constructor(radius) {
        this.radius = radius;
        Circle.circlesMade++;
    };

    static draw(circle, canvas) {
        // Canvas drawing code
    };

    static get circlesMade() {
        return !this._count ? 0 : this._count;
    };
    static set circlesMade(val) {
        this._count = val;
    };

    area() {
        return Math.pow(this.radius, 2) * Math.PI;
    };

    get radius() {
        return this._radius;
    };
    set radius(radius) {
        if (!Number.isInteger(radius))
            throw new Error("Circle radius must be an integer.");
        this._radius = radius;
    };
}

Array

var [,,third] = ["foo", "bar", "baz"];
var [head, ...tail] = [1, 2, 3, 4];
console.log(tail);
// [2, 3, 4]


var robotA = { name: "Bender" };
var robotB = { name: "Flexo" };

var { name: nameA } = robotA;
var { name: nameB } = robotB;

console.log(nameA);
// "Bender"
console.log(nameB);
// "Flexo"

// this is a syntax sugar for variable and key share the same name
var { foo, bar } = { foo: "lorem", bar: "ipsum" };
console.log(foo);
// "lorem"
console.log(bar);
// "ipsum"

var [missing = true] = [];
console.log(missing);
// true

var { message: msg = "Something went wrong" } = {};
console.log(msg);
// "Something went wrong"

var { x = 3 } = {};
console.log(x);
// 3

// parameters
function removeBreakpoint({ url, line, column }) {
  // ...
}


// super works as expected, calling super constructor and access base properties

// you can even subclass builtin types

CommonJS

There is a special object called module.exports, when requireing, the value of module.exports is returned.

something like that…

var require = function(path) {
    // ...
    return module.exports;
};

ES6 export

use the export keyword

// lib.js
export function foo() {}
export class bar {}
// or
export {baz, foz};
export {foo as fart};

// use.js
import {foo, bar} from "lib.js";
import {foo as fart} from "lib.js"; // renaming
import {* as lib} from "lib.js"; // import everything and put in a object

ES6 import commonJS

most packages are written in commonJS, for using as ES6 modules:
import _ from "lodash" // which is
import {default as _} from "lodash" // which is
let _ = require("lodash");

you can also do module.exports in ES6
export default value;

jQuery and un-jQuery

jQuery

$el.append(htmlString)
$el.prepend(htmlString)

$newEl.insertBefore(queryString)
$newEl.insertAfter(queryString)

un-jQuery

DOM 操作

选择器可以使用 querySelector 和 querySelectorAll, 但是这两个的性能太差了,最好使用 getElementById, getElementsByTagName, getElementsByClassName

$el.val() 对应 el.value

获取 attr

$el.attr('id');
el.getAttribute('id);
el.setAttribute(attr, value)

parent and children

$el.children
$el.parent()
el.children
el.parentNode

设置 css

$el. css({color: '#000'});
el.style.color = '#000';
$el.css('color');
window.getComputedStyle(el)['color'];

特别地
$(el).hide(); // jQuery
el.style.display = ‘none’; // native
$(el).show(); // jQuery
el.style.dispaly = ”

设置 class

$el.addClass(className) // remove, has, toggle
el.classList.add(className) // remove, contains, toggle

设置 text
Get text
// jQuery
$el.text();
// Native
el.textContent;

Set text
// jQuery
$el.text(string);

// Native
el.textContent = string;

设置 html

Get HTML
// jQuery
$el.html();

// Native
el.innerHTML;
Set HTML
// jQuery
$el.html(htmlString);

// Native
el.innerHTML = htmlString;

inserting html fragment to document

Have a look at insertAdjacentHTML

var element = document.getElementById("one");
var newElement = '<div id="two">two</div>'
element.insertAdjacentHTML( 'afterend', newElement )
// new DOM structure: <div id="one">one</div><div id="two">two</div>
position is the position relative to the element you are inserting adjacent to:

beforebegin Before the element itself

afterbegin Just inside the element, before its first child

beforeend Just inside the element, after its last child

afterend After the element itself

事件

绑定事件
$el.on(eventName, eventHandler); // jQuery
el.addEventListener(eventName, eventHandler); // Native

解绑事件
$el.off(eventName, eventHandler); // jQuery
el.removeEventListener(eventName, eventHandler); // Native

触发事件
// 用户事件
$(el).trigger(‘custom-event’, {key1: ‘data’}); // jQuery
// Native, note that
const event = new CustomEvent(‘custom-event’, {detail: {key1: ‘data’}});
el.dispatchEvent(event);

// 原生事件
$(el).trigger(‘change’);
var ev = new Event(“look”, {“bubbles”:true, “cancelable”:false});
document.dispatchEvent(ev);

ajax

getJSON
jQuery
$.getJSON(‘/my/url’, function(data) {
});
IE9+
var request = new XMLHttpRequest();
request.open(‘GET’, ‘/my/url’, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var data = JSON.parse(request.responseText);
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();
Post
jQuery
$.ajax({
type: ‘POST’,
url: ‘/my/url’,
data: data
});
IE8+
var request = new XMLHttpRequest();
request.open(‘POST’, ‘/my/url’, true);
request.setRequestHeader(‘Content-Type’, ‘application/x-www-form-urlencoded; charset=UTF-8’);
request.send(data);
Request
jQuery
$.ajax({
type: ‘GET’,
url: ‘/my/url’,
success: function(resp) {
},
error: function() {
}
});
IE9+
var request = new XMLHttpRequest();
request.open(‘GET’, ‘/my/url’, true);
request.onload = function() {
if (request.status >= 200 && request.status < 400) {
// Success!
var resp = request.responseText;
} else {
// We reached our target server, but it returned an error
}
};
request.onerror = function() {
// There was a connection error of some sort
};
request.send();

DOM Ready

https://github.com/oneuijs/You-Dont-Need-jQuery/blob/master/README.zh-CN.md
http://youmightnotneedjquery.com/

JavaScript DOM API

document object

attributes of document object

document.title               // 设置文档标题等价于 HTML 的<title>标签
document.URL                 // 设置 URL 属性从而在同一窗口打开另一网页
document.fileCreatedDate     // 文件建立日期,只读属性
document.fileModifiedDate    // 文件修改日期,只读属性
document.fileSize            // 文件大小,只读属性
document.cookie              // 设置和读出 cookie
document.charset             // 设置字符集 简体中文:gb2312
document.body         // body 元素
document.location.hash/host/href/port          // location

methods of document object

getElementById() // 返回一个 Element
getElementsByName() // 根据 name 属性获得元素,返回一个 NodeList
getElementsByTagName() // 返回一个 HTMLCollection/NodeList(Webkit)
getElementsByClassName() // 返回一个 HTMLCollection
querySelector() // 返回一个符合的元素,性能很差
querySelectorAll() // 返回所有符合的元素组成的 NodeList, 性能很差
document.write()
document.createElement()

window object

functions in window object

setTimeout(func, milliseconds, parameters...)
setInterval(func, milliseconds, parameters...)

NOTE: javascript is asynchonous, even if you set 0 timeout, the function is just put into the execute queue, not invoked immediately.

window.location

location    setting location will cause the page to redirect to new page
location.href
location.protocol
location.host
location.hostname
location.port
location.pathname
location.search
location.hash
location.assign()    go to a new address
location.replace()   go to a new address and do not disturb the history
location.reload()   reload the page

window.history

history.back()
history.forward()
history.go(number)

window.screen

window.screen.width screen width, not the viewport width
window.screen.height screen height

alert, confirm and prompt

alert show a message
confirm return a bool by user action
prompt

Same Origin Policy

document.domain is the key to decide the origin of a script.

scripts under different subdomain can set the their document.domain to a same domain, and then then can share the same cookie or communicate

Cross-Origin Resource Sharing