Js再起之精华一点点
js的精华其实可以压缩成一点点.
三位一体: 数组, 集合, 函数
这三个其实是同一个东西
//函数, 他其实是特殊的function集合
var square = function(number) { //一般都用这个定义.
return number * number;
};
//集合, 看到了吗? 他仅仅是没有声明为function而已
var animal = { //大括号方式定义集合.
type: "Invertebrates", // 属性
displayType : function() { console.log(this.type); }
}
// 数组, 他其实就是有默认序号的集合.
var arr = ['red', 'green', 'blue'];
arr.foo = "hello";
//下面的数组, 每个元素都是一个函数.
var af = [
function(string) { // do something
},
sf=function(string) { console.log('second'); },
]
af[1]('oo');
af["length"]; // 2 可以直接用中括号访问属性.
animal['displayType']();
//下面这句就通不过了, 因为[中括号]不支持键值对的这种方式声明.
var appp=[0:333, 1:5555];
//.和[]是一样的东西
var obj = {
key1: value1,
key2: value2
};
//Using dot notation:
obj.key3 = "value3";
//Using square bracket notation: 这里key可以是个变量. 这就是js牛的地方.
obj["key3"] = "value3";
//遍历
// for in 都可以用, 列举所有的key.
for (let i in xxx) { //会列出非整数索引.
console.log(i); // 这里显示key.
}
// foreach, 这个只支持数组, 因此, 要把键值对的key作为数组拿出来才行.
Object.keys(obj).forEach(function(key) {
console.log(key, obj[key]);
});
进步一丢丢: 推导式和胖箭头
// 推导式:
var numbers = [1, 2, 3, 21, 22, 30];
var doubledEvens = [i * 2 for (i of numbers) if (i % 2 === 0)];
console.log(doubledEvens); // logs 4,44,60
// 胖箭头:
numbers.forEach((color)=>{console.log(color);});
基于prototype的设计真的很functional
//这样就成功了, 这个递归很有趣, 函数名x并不是用来递归的名字量, 递归的名字量相反了是变量s.
Number.prototype.s = function x() {
var n=this.valueOf(); //主意这个this指的不是function x, 指的是调用者:number
if ((n < 2)) return 1;
else return (n * (n-1).s()); //所以这里对于函数的调用应该继续使用number.s()方式, 不能使用x()方式的原因是, 这里隐式传入了调用者number作为参数, 如果用x()方式, 就米有调用者了, 没有调用者, 就没有参数了(this就指到运行环境的window了).
} ;
(5).s();
//去掉递归, 可以看这个简单的例子.
Number.prototype.r = function() {
return Math.round(this.valueOf());
};
(5.5).r(); //第一种形式
5..r(); //第二种形式, 不能有小数点了.
5.5["r"](); //第三种当做数组属性处理的形式.
//针对array更简单了.
var colors = ['red', 'green', 'blue'];
Array.prototype.s = function x() {
this.forEach(function(color) {
console.log(color);
});
}
colors.s();
不得不承认, 闭包是js的精华之一
//最简单例子
function makeFunc() {
let name = "Mozilla";
function displayName() {
console.log(`name = ${name}`);
}
return displayName;
}
let myFunc = makeFunc();
myFunc();
//此处myfunc由函数displayname和他所处的环境构成.
//更有趣的例子
function makeAdder(x) {
return function(y) {
return x + y;
};
}
var add5 = makeAdder(5);
var add10 = makeAdder(10);
console.log(add5(2)); // 7
console.log(add10(2)); // 12
//更复杂的例子, return的是一个集合(有时候也翻译为对象), 他包含多个函数.
var Counter = (function() {
var privateCounter = 0;
function changeBy(val) {
privateCounter += val;
}
return {
increment: function() {
changeBy(1);
},
decrement: function() {
changeBy(-1);
},
value: function() {
return privateCounter;
}
}
})();
console.log(Counter.value()); /* logs 0 */
Counter.increment();
Counter.increment();
console.log(Counter.value()); /* logs 2 */
Counter.decrement();
console.log(Counter.value()); /* logs 1 */
此处参考: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures
let可以减少闭包的使用
function showHelp(help) {
document.getElementById('help').innerHTML = help;
}
function setupHelp() {
var helpText = [
{'id': 'email', 'help': 'Your e-mail address'},
{'id': 'name', 'help': 'Your full name'},
{'id': 'age', 'help': 'Your age (you must be over 16)'}
];
for (var i = 0; i < helpText.length; i++) {
let item = helpText[i];
//let在for循环的块里面, 每次循环中他的值都不同, 并且形成作用域.
//如果用var, 那么作用域在function setuphelp上面, 就导致了下面showhelp里面的参数item都是最后一个.
document.getElementById(item.id).onfocus = function() {
showHelp(item.help);
}
}
}
setupHelp();
//这个代码要看一会儿了. 建议有疑问去看mozilla的原文
var
声明一个变量,可选择将其初始化为一个值。
let
声明一个块作用域的局部变量(block scope local variable),可选择将其初始化为一个值。这个就是配合闭包用的.
const
声明一个只读的常量。
随便乱创建闭包是不合适的, 因为他有性能开销, 包括cpu开销和内存开销.
链式调用也是一个精华部分
虽然传统上, 我们可以通过命名函数来解决括号嵌套, 但是, 那样会导致调用代码分散. 难于从整体上把握代码的流转.
//直接声明最优写法, 优点是剥开了最大的括号. 降低了大括号的嵌套
var test = {}
test.someFunc=function () {
console.log('someFunc111')
return test
}
test.someOtherFunc=function () {
console.log('someOtherFunc222')
return test;
}
test.someFunc().someOtherFunc();
结论, 除非是要搞内置类型(才用prototype), 否则正常字面量声明是最简洁明了的.
字面量, 表达式, 初始化
//确实简洁, 大方, 美观, 符合直观感受, 我的建议是, 除了字面量之外, 不要用其他方式.
//这三个单词在js中含义差不多: 初始化器Initializer 字面量literal 表达式expressions
不论是数组
var a= [1,2]
对象
var o={1:1}
还是正则
var r=/xx/
函数
var f=function(){}
简洁
this.name = name || "";
回调函数 = 依赖注入
//回调可以说是js中最优雅的部分. 单进程, 单线程, 异步. 其他语言都掉在各种多进程, 多线程的沟里面, js没有. 逆潮流而上, 真英雄.
function doSomething(callback) {
// Call the callback
callback('stuff', 'goes', 'here');
}
//异步回调才是精华, 不要直接执行那个回调函数.
function doSomething(callback) {
// 异步回调 传递参数是个技术活,
//1. (闭包可以解决, 匿名函数也行)这两个都是参数作用域上想办法,
//2. settimeout, 从第三个参数也可以传,
//3. 字符串传入也行但是不推荐, 开销大eval, 并且还不一定能执行大小括号要转变, 而且参数多了写法还有疑问.
setTimeout(callback,0, 参数1, 参数2, 参数3....);
}
promise = 异步链式回调
//很不爽, 要用promise, 需要先创建Pormise对象, 如果这个对象是返回值. 那么那他就可以链式了.
new Promise( function(resolve, reject) {...} /* executor */ );
resolve和reject分别是两个函数. 对应于匿名函数执行状态(成功/失败).
//灰常灰常不确定, 这个是否是精华, 也可能是糟粕.