函数式编程 && 命令式编程
函数式编程:把具体的操作过程“封装”到一个函数中,我们无需关注内部是如何处理的(How),只需要关注处理的结果(What)即可;
// 如果是依次迭代数组每一项,则函数式编程更加的方便。
let arr = [10,20,30,40]
arr.forEach((item,index)=>{
console.log(`item-->`, item);
})
命令式编程:具体如何去处理,是由自己实现及掌控的,关注How的过程!
let arr = [10,20,30,40]
for(let i=0;i<arr.length;i++){
console.log(arr[i],i);
}
操作灵活,可以自主把控处理的每一个步骤。
对于一些复杂的处理逻辑,还是要使用命令式编程,自己去管控操作的步骤。
// 但是对于一些复杂的处理逻辑,还是要使用命令式编程,自己去管控操作的步骤
//隔一项打印一次-函数式编程-每一项都会被遍历到,但非条件要求,就不执行打印的操作。
let arr = [10,20,30,40]
arr.forEach((item, index) => {
if (index % 2 === 0) {
console.log(item)
}
})
//隔一项打印一次-函数式编程-可以只遍历需要进行打印的项。
let arr = [10,20,30,40]
for (let i = 0; i < arr.length; i += 2) {
console.log(arr[i])
}
处理性能一般比函数式编程式要好。
总结:处理的数据量“较多”的情况下,使用命令式编程来提高性能!操作逻辑较为复杂,需要自己灵活把控处理步骤的情况下,也使用命令式编程!其余情况,优先推荐函数式编程!
// 需求:循环5次。
new Array(5).fill(null).forEach((item, index) => {
console.log(`index-->`, index);
});
匿名函数具名化。
特点:原本应该是匿名函数「例如:自执行函数、函数表达式、回调函数等」,但是我们会为其设置一个名字。
//这样创建函数,因为变量提升的机制,导致函数可以在`定义的代码`之前或之后执行都可以,逻辑不严谨。
fn()
function fn() {
console.log(`fn;`);
}
fn()
//基于函数表达式的方式创建函数,可以抵消变量提升的影响,函数只能在创建的代码后面执行!
fn(); //1函数式编程.js:44 Uncaught ReferenceError: Cannot access 'fn' before initialization;
const fn = function () {
console.log(`fn;`);
};
//匿名函数具名化:原本应该是一个匿名函数,但是现在我们给其设置了名字。
fn(); //1函数式编程.js:44 Uncaught ReferenceError: Cannot access 'fn' before initialization;
const fn = function () {
console.log(`fn;`);
};
arguments.callee指代函数本身
// 匿名函数的递归操作-非严格模式-arguments.callee:
let n = 12;
(function () {
if (n >= 15) {
return;
}
n++;
arguments.callee();//arguments.callee指代函数本身。
})();
console.log(n);
// 匿名函数的递归操作-严格模式-arguments.callee:
'use strict'
let n = 12;
(function () {
if (n >= 15) {
return;
}
n++;
arguments.callee();//arguments.callee指代函数本身,严格模式下会报错。//Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
})();
console.log(n);
// 匿名函数的递归操作-严格模式-可以使用匿名函数具名化指代匿名函数本身。
// 方便匿名函数实现递归
'use strict'
let n = 12;
(function fn() {
if (n >= 15) {
return;
}
n++;
fn();
})();
console.log(n);
即便具名化,函数也没有在外层作用域中声明,导致在外面依然是用不了的!
// 即便具名化,函数也没有在外层作用域中声明,导致在外面依然是用不了的!
(function fn(){
})()
console.log(fn);//Uncaught ReferenceError: fn is not defined;//即便具名化,函数也没有在外层作用域中声明「导致在外面依然是用不了的」
匿名函数具名化,可以在函数内部使用这个名字来指代匿名函数,代表当前函数本身!
// 匿名函数具名化,可以在函数内部使用这个名字来指代匿名函数,代表当前函数本身!
(function fn(){
console.log(fn);//可以在函数内部使用这个名字来指代匿名函数,代表当前函数本身!
})()
/* //这样创建函数,因为变量提升的机制,导致函数可以在`定义的代码`之前或之后执行都可以,逻辑不严谨。
fn()
function fn() {
console.log(`fn;`);
}
fn() */
/* //基于函数表达式的方式创建函数,可以抵消变量提升的影响,函数只能在创建的代码后面执行!
fn()//1函数式编程.js:44 Uncaught ReferenceError: Cannot access 'fn' before initialization;
const fn = function (){
console.log(`fn;`);
} */
/* //匿名函数具名化:原本应该是一个匿名函数,但是现在我们给其设置了名字。
fn()//1函数式编程.js:44 Uncaught ReferenceError: Cannot access 'fn' before initialization;
const fn = function (){
console.log(`fn;`);
} */
/* // 即便具名化,函数也没有在外层作用域中声明,导致在外面依然是用不了的!
(function fn(){
})()
console.log(fn);//Uncaught ReferenceError: fn is not defined; */
/* // 匿名函数具名化,可以在函数内部使用这个名字来指代匿名函数,代表当前函数本身!
(function fn(){
console.log(fn);//可以在函数内部使用这个名字来指代匿名函数,代表当前函数本身!
})() */
/* // 非严格模式:
let n = 12;
(function () {
if (n >= 15) {
return;
}
n++;
arguments.callee();//arguments.callee指代函数本身。
})();
console.log(n); */
/* // 严格模式:
'use strict'
let n = 12;
(function () {
if (n >= 15) {
return;
}
n++;
arguments.callee();//arguments.callee指代函数本身,严格模式下会报错。//Uncaught TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
})();
console.log(n); */
/* // 严格模式-可以使用匿名函数具名化指代匿名函数本身。
'use strict'
let n = 12;
(function fn() {
if (n >= 15) {
return;
}
n++;
fn();
})();
console.log(n); */
/* // 不允许直接修改函数名对应的值,fn表示匿名函数本身。
(function fn() {
fn=10;
console.log(fn);//fn依旧是匿名函数本身。//不允许直接修改函数名对应的值,fn表示匿名函数本身。
})(); */
/* //如果匿名函数中函数名被用其它方式声明,则会以其它声明的为主。
(function fn() {
let fn=10;
console.log(`fn-->`, fn);//10//如果被用其它方式声明,则会以其它声明的为主。
})(); */
typeof数据类型检测的底层机制
特点1:返回的结果是字符串,字符串中包含了对应的数据类型
typeof typeof typeof [1,2,3]
//"string"
特点2:按照计算机底层存储的二进制进行检测「效率高」
对象
;整数
;浮点数
;字符串
;布尔
;null
;undefined
;特点3:typeof null -> “object”
特点4:typeof 对象 -> “object” && typeof 函数 -> “function”
特点5:typeof 未被声明的变量 -> “undefined”
typeof在实战中的运用:
检测除null以外的原始值类型
笼统的校验是否为对象
const isObject = function isObject(value) {
if (value === null) {
return false;
}
return /^(object|function)$/.test(typeof value);
};
检测是否为函数 => if(typeof obj===“function”){…}
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_precedence#汇总表
const isFunction = function isFunction(value) {
return typeof value === `function`;
};
处理浏览器兼容「ES6+语法规范,都不兼容IE」
//需求:获取对象所有的私有属性-不兼容IE浏览器。
let obj = {
name: "obj",
age: 15,
[Symbol("AA")]: 100,
};
let keys = Reflect.ownKeys(obj);
console.log(keys);
//需求:获取对象所有的私有属性-兼容IE浏览器。
let obj = {
name: "obj",
age: 15,
[Symbol("AA")]: 100,
};
let keys = Object.getOwnPropertyNames(obj);
if (typeof Symbol !== "undefined") {
// 非IE浏览器。
keys = keys.concat(Object.getOwnPropertySymbols(obj));
}
console.log(keys);
所有的数据类型值,在计算机底层都是以 2进制 格式进行存储「undefined比较特殊 」
进制:
操作系统
JS中数据类型检测汇总
typeof 变量
对象变量 instanceof 构造函数
//instanceof
console.log([] instanceof Array);//true
console.log([] instanceof Object);//true
console.log(/0/ instanceof Array);//false
依次查找对象的原型链(proto),一直到 Object.prototype ,在此过程中,如果 构造函数.prototype 出现在了其原型链的某个环节,则说明 当前对象 是此构造函数的一个实例,检测结果就是true!
/*
//准。
let obj = {}
console.log(obj instanceof Array);//false */
// 不准。
let obj = {}
obj.__proto__=Array.prototype//Object.setPrototypeOf(obj,Array.prototype)
console.log(obj instanceof Array);//true;
constructor
// constructor
console.log([].constructor === Array);//true;
console.log([].constructor === Object);//false;//只有对象的原型链是直接指向Object.prototype原型的,则其constructor属性值才是Object。或者其本身所属类的原型对象上没有constructor,一层层往上查找,才找到了Object.constructor。一个对象的constructor为Object的,我们称之为标准普通对象或纯粹的对象。
Object.prototype.toString.call([value])
不仅仅 Object.prototype 上有 toString 方法,在 Number/String/Boolen/Array/Function… 的原型对象上,也有 toString 方法,只不过其它原型上的toString方法都是用来转换为字符串的,只有Object.prototype.toString是用来检测数据类型的
let obj = {ang:100}
obj.toString()
//obj先基于原型链,找到Object.pprototype.toString(),把toString()执行,方法中的this是obj。
把 Object.prototype 上的 toString 方法执行,让方法中的 this 指向要检测的数据值,这样就可以返回此数据值的数据类型 -> “[object ?]”
特点:精准且强大「唯一不足就是写起来麻烦一丢丢」
此办法虽然很不错,但是也不是所有的数据类型检测都使用这个办法,一般来讲:需要笼统的检测或者按照大的类别去检测,使用 typeof 会更方便,而需要很精准检测的时候,使用 toString 会更好!
// 检测是否是纯粹对象。
const toString = Object.prototype.toString;
const isPlainObject = function isPlainObject(obj) {
//先校验:如果基于toString.call()检测结果都不是`[object Object]`,则一定不是纯粹对象。
if (toString.call(obj) !== "[object Object]") {
return false;
}
// Object.create(null)返回的也是一个纯粹的对象。
let proto = Object.getPrototypeOf(obj);
if (!proto) {
return true;
}
let Ctor = "constructor" in obj && obj.constructor;
return Ctor === Object;
};
快捷方法:
http://外网IP:端口号
这样的地址访问我们的项目了!外网IP、内网IP(局域网IP)。
ipconfig -all
域名的分类
域名后缀的含义
http://124.23.16.8:80/index.html
访问到我们的代码。
《图解HTT》
这本电子书。前端性能优化方案:
按步骤来做: