web前端之零碎知识点、字符串、数组、基础知识

文章目录

  • 前言
  • 对象的构造函数和类
  • 向Number内置类的原型上扩展方法
  • 判断是否给实例设置属性name
  • Promise笔试题-02
  • prototype和__proto__的笔试题
  • JavaScript引用类型值值操和运算符优先级比较--笔试
  • 原型与原型链--笔试-05
  • 闭包--笔试-11
  • this--基础知识(指向)-07
  • 浅浅克隆和浅克隆(clone)--01
  • 深克隆(clone)--01
  • 作用域-笔试
  • this总结-06
  • 数据类型转换
  • ==(两等) 和 !(非) 的优先级比较
  • 访问器属性-13
  • 变量提升案例
  • 设计模式-观察者模式
  • 箭头函数概念
  • var、let和const的区别
  • 一维数组升为二维数组
  • promise的使用
  • 字符串去重(以逗号隔开的字符串)
  • 字符串去重
  • vue+transition-group实现拖动排序
  • 数组对象排序
  • 正则表达式实现简单模板数据填充
  • defineReactive函数,利用闭包封装Object.defineProperty()
  • JavaScript获取字符串(string)第一个字符
  • JavaScript递归实现数组扁平化(数组降维)
  • JavaScript中number和~~比较、API
  • JavaScript实现单词、字母排序
  • JavaScript实现分组排序单词、单词分组排序、不能实现中文首拼音排序
  • 待定


前言

每一个大标题,曾经都是一篇文章,此文章内容比较散乱。


对象的构造函数和类

创建对象

// 使用字面量创建对象
let starL = {Uname: '刘邦',Uage: 30
};
console.log(starL);// 使用构造函数创建对象
function Star(Uname, Uage) {this.Uname = Uname;this.Uage = Uage;
};
let starW = new Star('王之涣', 23); // 实例化对象
console.log(starW);

创建类

class Poet {// 类的共有属性放到 constructor 里面,// constructor 是构造器或者构造函数constructor(Uname, age) {this.Uname = Uname;this.age = age;};// 注意: 方法与方法之间不需要添加逗号humVerse(song) {console.log(this.Uname + '吟' + song);};
};
var PoetW = new Poet('王安石', 26);
console.log(PoetW);
PoetW.humVerse('元日');

向Number内置类的原型上扩展方法

编写plus和minus实现如下需求

// anonymous: 匿名函数的名称
// 闭包的作用是防止函数跟全局函数有冲突
// 函数自调方式
// ~ function() {}();
// (function() {})()
~ function anonymous(proto) {// 封装 plus 函数 和 minus 函数 共同部分// 使用函数表达式方式创建函数是为了保证函数提升和// 防止在创建函数前调用函数const checkNum = function checkNum(num) {// 强制转换为 Number 类型num = Number(num);// 如果 num 不是有效数字if (isNaN(num)) {// 给 num 赋值为 0num = 0;}// 返回 numreturn num;};// 函数表达式// 把匿名函数改为具名函数,在全局通过函数名无法访问此函数proto.plus = function plus(num) {// 在函数内部可以调用此函数// 调用方式 Number.prototype.plus()// 既不跟外部函数名字冲突// 又可以通过特殊方式调用// => this: 要操作的那个数字实例(对象) // => 返回 Number 类的实例,实现链式写法return this + checkNum(num);};proto.minus = function minus(num) {return this - checkNum(num);};
}(Number.prototype);let n = 10;
let m = n.plus(10).minus(5);
console.log(m); // => 15 (10+10-5)
// 向 Number 内置类(原型)上扩展方法
// 创建一个数据类型值:
// 1.字面量方式
// 2.构造函数方式
// 不论哪一种方式,创建出来的结果都是所属类的实例
// => 基本数据类型两种创建方式是不一样的: 字面量创建的是基本类型值,
// 构造函数方式创建的是引用类型值
// let x = 10; // 字面量方式
// let y = new Number(10); // 构造函数方式
// console.log(y.valueof() === x);
// => 对象结果的原始值是基本类型数字 10

判断是否给实例设置属性name

function C1(name) {// => name: undefined 没有给实例设置私有的属性nameif (name) this.name = name;
}function C2(name) {// => 给实例设置私有属性 name this.name = undefindthis.name = name;
}function C3(name) {// => 给实例设置私有属性 name this.name = undefind// 因为 name 的值为 undefined// 所以走 || 后面的代码this.name = name || 'join';
}C1.prototype.name = 'Tom';
C2.prototype.name = 'Tom';
C3.prototype.name = 'Tom';console.log((new C1().name) + (new C2().name) + (new C3().name));// new C1().name
// 没有传参 函数里面的 name 为 undefined
// 实例里面没有 name 找原型上的 'Tom'// new C2().name 
// 没有传参 函数里面的的 name 为 undefined
// 但是函数确实添加了 name 属性 只是值为 undefined 而已
// 所以找私有属性 name 的值为 undefined// new C3().name
// 没有传参 函数里面的 name 为 undefined
// 但是函数确实添加了 name 属性 只是值为 'join'
// 所以私有属性 name 的值为 'join'// 最终结果为 'Tomundefinedjoin'

Promise笔试题-02

console.log(1);
// 宏仁务 2
setTimeout(_ => {console.log(2);
}, 1000);async function fn() {console.log(3);// 宏仁务 3setTimeout(_ => {console.log(4);}, 20);// 结果为失败// 所以 微任务 1 // 报错永远不会执行return Promise.reject();
}async function run() {console.log(5);await fn();// 微任务 1console.log(6);
}
run();// 需要执行 150 MS 左右
for (let i = 0; i < 90000000; i++) {}// 宏仁务 4
setTimeout(_ => {console.log(7);// 立即执行new Promise(resolve => {console.log(8);// 微任务 5resolve();}).then(_ => {console.log(9);})
}, 0);console.log(10);// 1
// 5
// 3
// 10
// Uncaught (in promise) undefined
// 7
// 8
// 9
// 4
// 2

prototype和__proto__的笔试题

function Fn() {// 代码字符串// 谁 new 就是谁的私有属性this.x = 100;this.y = 200;this.getX = function() {console.log(this.x);};// 每个函数都有 prototype 对象// 所以 prototype 是一个堆 Fn.prototype// Fn.prototype 对象也带 __proto__ 属性// 这个对象上有 constructor// constructor 指向函数本身
};// 把 getX 挂载到 Fn 的原型对象上
// 生成一个新的堆内存
// 属于公共属性
Fn.prototype.getX = function() {console.log(this.x);
};// 把 getY 挂载到 Fn 的原型对象上
// 生成一个新的堆内存
// 属于公共属性
Fn.prototype.getY = function() {console.log(this.y);
};// 括号可加可不不加
// 都是创建类的实例
// 创建实例对象 f1 / f2 (堆)
// 同时创建 x: 100 y: 200  getX: function() { ... }
// 都是这个实例的私有属性
// 通过 this 创建的变量和对象都属于私有属性
// 实例都带 __proto__ 属性
// __proto__ 所属类的原型 prototype
// 通过原型链往上找都属于 实例(Fn.prototype) 的共有属性
let f1 = new Fn();
let f2 = new Fn;// Object内置类(堆)
// 有自己的 prototype 原型对象 
// prototype 指向 Object.prototype 原型对象
// 有自己的 __proto__ 属性
// 有自己的 constructor 属性
// constructor 指向 Object
// Object.prototype 的 __proto__ 指向的是 null// 实例指向的堆内存不同,如果自己私有就不会往原型类上查找
// 因为这个 getX 函数自己私有
// 所以两个实例的 getX 方法不相等
console.log(f1.getX === f2.getX); // false// 因为 getY 这个函数不是自己私有
// 所以往原型链上查找,结果相等
// 原因就是他们的 __proto__ 都指向 Fn.prototype 原型对象
console.log(f1.getY === f2.getY); // true// 通过原型链查找到的是公共的 getY 
// 类似于 f1.getY === f2.getY
console.log(f1.__proto__.getY === Fn.prototype.getY); // true// f1.__proto__.getX 找的是 Fn.prototype 公共属性
// f2.getX 因为自己私有
// 所以不相等
console.log(f1.__proto__.getX === f2.getX); // false// f1.getX 属于自己私有的属性
// Fn.prototype.getX 本身就是公共属性
// 所以不相等
console.log(f1.getX === Fn.prototype.getX); // false// f1 自己身上没有 constructor 
// 往原型对象上查找
// 又因为 constructor 指向 函数本身
// 所以结果就是 Fn 函数
console.log(f1.constructor); // Fn 函数// Fn.prototype 的 __proto__ 指向的是 Object.prototy 
// 因为 Object.prototy 的 constructor 指向 Object 本身
// 所以是结果 Object
console.log(Fn.prototype.__proto__.constructor); // ƒ Object() { [native code] }// f1.getX() 执行
// 并且 f1.getX 是属于自己私有
// 所以输出 100
// 函数执行前面有点
f1.getX(); // 100// f1.__proto__.getX(); 
// 直接查找的是原型对象上的 getX()
// 原型上的是 console.log(this.x);
// 因为 f1.__proto__.getX(); getX() 前面有点
// 所以 相当于 f1.__proto__.x
// f1.__proto__.x 直接跳过自己(f1 实例对象(堆))往原型对象上查找
// 此时原型对象上也没有,再往 Object.prototype 对象上查找
// Object 对象上也没有
// 最后得到的是 undefined
f1.__proto__.getX(); // undefined// 与 f1.getX(); 相同
f2.getY(); // 200// Fn.prototype.getY(); 
// 直接查找的是原型对象上的 getY()
// 原型上的是 console.log(this.y);
// 因为 Fn.prototype.getY(); getY() 前面有点
// 所以 相当于 Fn.prototype.y
// Fn.prototype.y 直接跳过自己(f2 实例对象(堆))往原型对象上查找
// 此时原型对象上也没有,再往 Object.prototype 对象上查找
// Object 对象上也没有
// 最后得到的是 undefined
Fn.prototype.getY(); // undefined

JavaScript引用类型值值操和运算符优先级比较–笔试

let a = { n : 1 };
let b = a;
a.x = a = { n: 2 };    
// 如果改为这样
// a = a.x = { n: 2 }; 
// 结果还是一样
// JavaScript 中点(.)比 等号 (=) 的优先级高console.log(a.x); // undefined
// a.x = a = { n: 2 }; 
// 这段代码可以写成这样子
// a.x = { n: 2 };
// a = { n: 2 };
// 因为 a 是引用类型数据。
// 所以当 a.x = { n: 2 };时引用值的地址改变;
// 此时全局的 let a = { n: 1, x: { n: 2 } };
// 接着又执行 a = { n: 2 };时 a 引用地址已经改变。
// 最后输出的结果就是 : undefinedconsole.log(b.x); // { n: 2 }
// 经过上面 a 的操作,
// 全局的 a 值已经变为 a = { n: 1, x: { n: 2 } };
// 而此时 b 引用的地址一直没有改变
// 所以输出结果为 { n: 2 }

原型与原型链–笔试-05

function A() {};A.prototype.n = 1;
var b = new A(); // b 实例对象已经建立原型连接
// 原型对象指向被改变,不会切断 b 实例对象的的指向
A.prototype = {n: 2,m: 3
};
var c = new A(); // c 实例对象将根据新的原型建立连接
console.log(b.n, b.m); // 1 undefined 这里拿到是改变 prototype 之前的堆数据
console.log(c.n, c.m); // 2 3 这里拿到是改变 prototype 之后的堆数据
// 此题生成了两个堆内存
// 并且两个堆内存都有自己的实例存储 => b c

闭包–笔试-11

function fun() { var n = 9; // js 中强行给一个未声明的变量赋值,// 程序不会报错// 并且会自动在全局创建此变量add = function() { n++;}; return function() { console.log(n); }; 
};// 把 fun() 执行的结果赋值给 fn 变量
var fn = fun();// 此处调用的是全局的 add 函数,
// 因为全局的 add 函数作用域链引用着 fun 函数作用域对象
// 所以修改的是 fun 里面变量的值
add();
fn(); // 10// 把 fun() 执行的结果赋值给 fn2 变量
// 注意:这里的 fn2 所引用的是 fun() 执行后的地址
// 所以 fn 和 fn2 变量使用的地址是不同,结果也不相同
var fn2 = fun();
fn2(); // 9
add();
add();
fn2(); // 11
fn(); // 10
add();
fn(); // 10

this–基础知识(指向)-07

var who = { userName: '杜牧', age: 36, fun: function() { // 此时无法确定 this 指向console.log(`我叫${ this.userName },今年${ this.age }岁。`);} 
};// this 指向 who 对象
who.fun(); // 我叫杜牧,今年36岁。var me = { userName: '李清照', age: 22 
};me.fun = who.fun;
// this 指向 me 对象
me.fun(); // 我叫李清照,今年22岁。var onWindow = who.fun;
// 前面没有 点(.) 
// this 指向 window
onWindow(); // 我叫undefined,今年undefined岁。

浅浅克隆和浅克隆(clone)–01

let oldObject = {name: '西施',age: 26,height: '163.30',obj: {city: '成都',street: '玉林路'},array: ['赵雷', '嬴政', '天明']
};    // 浅克隆 -- 只能处理一层数据结构的克隆
// 深克隆 -- 可处理超过一层或多层数据结构的克隆
function clone(oldObject) {let newObject = {};for (let key in oldObject) {newObject[key] = oldObject[key];};return newObject;
};// 浅浅克隆
// 引用同一个地址
let newData = oldObject;
console.log(oldObject === newData); // true// 浅克隆成功
console.log(oldObject == clone(oldObject)); // falselet cloneData = clone(oldObject);// 第一层可以克隆成功
cloneData.age = 30;
console.log('cloneData:', cloneData.age); // 30
console.log('oldObject:', oldObject.age); // 26// 第二层 对象
cloneData.obj.city = '杭州';
console.log('cloneData:', cloneData.obj.city); // 杭州
console.log('oldObject:', oldObject.obj.city); // 杭州// 第二层 数组
cloneData.array[1] = '荆轲';
console.log('cloneData:', cloneData.array[1]); // 荆轲
console.log('oldObject:', oldObject.array[1]); // 荆轲

深克隆(clone)–01

let oldObject = {name: '西施',age: 26,height: '163.30',score: null,friends: ['李白', '杜牧', '李商隐'],oldObj: {city: '广州',area: '越秀区',street: '明信路'}
};function clone(oldObject) {// 第一步:创建一个空对象let newObject = {};// 第二步:判断值是否为空// 如果给的值里面有 null 就直接返回 null// 如果不进行处理会输出 {} 空对象if (oldObject === null) {return null;}// 第三步:判断是否是数组// 如果是数组需要处理,// 如果不处理数组会转为类数组对象// { 0: "李白", 1: "杜牧", 2: "李商隐" }if ({}.toString.call(oldObject) === '[object Array]') {var newArray = [];// 数组克隆// 使用 splice() 方法实现// splice() 里面什么也没写,// 表示从数组第一项截取到末尾newArray = oldObject.slice();return newArray;}// 第四步:使用 for in 循环实现克隆for (let key in oldObject) {// 如果原对象属性值是原始类型,// 可以直接赋值// 原始类型值是直接复制副本if (typeof oldObject[key] !== 'object') {newObject[key] = oldObject[key];} else {// 当前属性不是原始类型值,// 再次调用(类似与递归) clone 函数,// 继续复制当前属性的值newObject[key] = clone(oldObject[key]);}}return newObject;
};// 如果是 false 说明克隆成功
console.log(oldObject === clone(oldObject)); // falselet cloneData = clone(oldObject);// 修改克隆后的第一层 age 的值
cloneData.age = 30;// 修改克隆后第二层 数组的值
cloneData.friends[2] = '杜甫';// 修改克隆后的二层 city 的值
cloneData.oldObj.city = '武汉';// 深克隆,第一层两个值的地址已经完全不一样了
console.log('oldObject:', oldObject.age); // 26
console.log('newObject:', cloneData.age); // 30// 深克隆,第二层 数组 两个值的地址已经完全不一样了
console.log('oldObject:', oldObject.friends[2]); // 李商隐
console.log('newObject:', cloneData.friends[2]); // 杜甫// 深克隆,第二层 对象 两个值的地址已经完全不一样了
console.log('oldObject:', oldObject.oldObj.city); // 广州
console.log('newObject:', cloneData.oldObj.city); // 武汉

作用域-笔试

var a = 0, b = 0;function A(a) {// A(1)执行// 1.A函数被重置为// function A(b) {// console.log(a + b++);// };// 2.执行打印console.log(a++),// 因为此时的a是形参,形参的值是传入的1,// 所以打印1,而且形参a执行了++,此时值为2A = function (b) {// A(2)调用情况// 这个a采用的是闭包中的a,而不是全局中的a,// 所以是2,b是形参也是2,所以打印的是4// b使用的是传入的形参而不是全局中的bconsole.log(a + b++);};// 调用函数A(1)的时候执行这一行代码,// 并且把函数重置console.log(a++);
};
A(1); 
// 1
A(2); 
// 4

this总结-06

1、函数是否是用new来调用?如果是则this绑定新创建的对。
2、函数是否通过call或者apply来硬绑定调用?如果是则this绑定的是指定的对象。
3、函数是否是被某个上下文对象调用?如果是则this绑定这个上下文对象。
4、如果以上都不是,则使用默认绑定,点前是谁就是谁,函数调用一般指向window比较多。


数据类型转换

在JavaScript中类型转换只有三种情况。
1、转换为布尔值,调用Boolean()方法。
2、转换为数字,调用Number()、parseInt()和parseFloat()方法。
3、转换为字符串,调用.toString()或者String()方法。


==(两等) 和 !(非) 的优先级比较

console.log([] == ![]); // true

1、!(非) 的优先级高于==(两等) ,右边[]是true,取返等于false。
2、一个引用类型和一个值去比较,会把引用类型转化成值类型。所以,[] => 0 。
3、最后0 == false的结果是true 。


访问器属性-13

let attribute = {id: 11,sname: '名字'
};// 给 attribute 对象添加两个属性:_age 和 age
// age 作为保镖保护 _age
// 第一步
Object.defineProperties(attribute, {// 先添加一个半隐藏的 _age_age: {// 值value: 26,// 可以改writable: true,// 半隐藏enumerable: false,// 双保险configurable: false,},// 再为 _age 添加一个保镖 -- 访问器属性age: {get: function() {return this._age;},set: function(value) {if (value >= 18 && value <= 65) {this._age = value;} else {throw Error('年龄必须介于18~65之间。');}},enumerable: true,configurable: false}
});console.log(attribute);
// {id: 11, sname: "名字", _age: 26}console.log(attribute.age);
// 26console.log(attribute._age);
// 26attribute.age = 27;
console.log(attribute.age);
// 27attribute.age = 16;
console.log(attribute.age);
// Uncaught Error: 年龄必须介于18~65之间。

变量提升案例

function funHoisting() {console.log(1);
};funHoisting(); // 2function funHoisting() {console.log(2);
};funHoisting(); // 2var funHoisting = 100;
// 在函数提升的时候 var fun 对程序没有任何影响,
// 等于没写
funHoisting();
// Uncaught TypeError: funHoisting is not a function

设计模式-观察者模式

// 有一家猎人工会,
// 其中每个猎人都具有发布任务(publish),
// 订阅任务(subscribe)的功能
// 他们都有一个订阅列表来记录谁订阅了自己
// 定义一个猎人类
// 包括姓名,级别,订阅列表function Hunter(name, level) {this.name = name;this.level = level;this.list = [];
};// 在Hunter原型上添加publish方法
Hunter.prototype.publish = function(money) {console.log(this.level + '猎人' + this.name + '寻求帮助');this.list.forEach(function(item, index) {item(money);});
};// 在Hunter原型上添加subscribe方法
Hunter.prototype.subscribe = function(targrt, fn) {console.log(this.level + '猎人' + this.name + '订阅了' + targrt.name);targrt.list.push(fn);
};// 猎人工会走来了几个猎人
let hunterMing = new Hunter('小明', '黄金');
let hunterJin = new Hunter('小金', '白银');
let hunterZhang = new Hunter('小张', '黄金');
let hunterPeter = new Hunter(' Peter ', '青铜');// Peter等级较低,
// 可能需要帮助,
// 所以小明,小金,小张都订阅了Peter
hunterMing.subscribe(hunterPeter, function(money) {console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能给予帮助'));
});hunterJin.subscribe(hunterPeter, function() {console.log('小金表示:给予帮助');
});hunterZhang.subscribe(hunterPeter, function() {console.log('小金表示:给予帮助');
});// Peter遇到困难,赏金198寻求帮助
hunterPeter.publish(198);

箭头函数概念

1、不需要使用 function 关键字来创建函数。
2、可以极大的简写函数。
3、当要求动态上下文的时候,不能使用箭头函数,也就是 this 的固定化。


var、let和const的区别

1、var声明的变量会挂载在window上,而let和const声明的变量不会。
2、var声明变量存在变量提升,let和const不存在变量提升。
3、let和const声明形成块作用域。
4、同一作用域下var可以声明同名变量,而let和const不可以。


一维数组升为二维数组

function arrTrans(num, arr) {// 参数 num : 决定二维数组的个数// 参数 arr : 源数组const iconsArr = [];arr.forEach((item, index) => {// floor() 向下取整const page = Math.floor(index / num);// 向数组 iconsArr 添加数组// 数组下标就是 pageif (!iconsArr[page]) iconsArr[page] = [];iconsArr[page].push(item);});return iconsArr;
}console.log(arrTrans(5, [1, 1, 2, 3, 4, 5, 6, 7, 8]));
// [[1, 1, 2, 3, 4], [5, 6, 7, 8]]

promise的使用

function func1() {return new Promise((resolve) => {setTimeout(() => {resolve("func1 1000");}, 1000);});
};function func2() {return new Promise((resolve) => {setTimeout(() => {resolve("func1 2000");}, 2000);});
};function func3() {return new Promise((resolve) => {setTimeout(() => {resolve("func1 3000");}, 3000);});
};func1().then((result) => {console.log(result);return func3();}).then((result) => {console.log(result);return func2();}).then((result) => {console.log(result);});

字符串去重(以逗号隔开的字符串)

function stringDuplicateRemoval(str) {let obj = {},arr = str.split(","),result = [],i = 0;for (let i = 0; i < arr.length; i++) obj[arr[i]] = 1;for (result[i++] in obj);return result;
}console.log(stringDuplicateRemoval('1,2,3,3'));
// [1,2,3]console.log(stringDuplicateRemoval('1,2,3,3').toString());
// '1,2,3'

字符串去重

function stringDuplicateRemoval(str) {let newStr = "";for (let i = 0; i < str.length; i++) {if (newStr.indexOf(str[i]) == -1) newStr += str[i];}return newStr;
}console.log(this.stringDuplicateRemoval("110120140"));
// 1024

vue+transition-group实现拖动排序

<transition-group id='app' name="drog" tag="ul"><div draggable="true" v-for="(item, index) in lists" @dragstart="dragStart($event, index)" @dragover="allowDrop" @drop="drop($event, index)" v-bind:key="item">{{item}}</div>
</transition-group>

new Vue({el: '#app',data: {lists: ['1: apple', '2: banana', '3: orange', '4: melon']},methods: {// 取消默认行为allowDrop(e){e.preventDefault();},// 开始拖动dragStart(e, index){let tar = e.target;e.dataTransfer.setData('Text', index);if (tar.tagName.toLowerCase() == 'li') {// console.log('drag start')// console.log('drag Index: ' + index)}},// 放置drop(e, index){this.allowDrop(e);// console.log('drop index: ' + index);//使用一个新数组重新排序后赋给原变量let arr = this.lists.concat([]),dragIndex = e.dataTransfer.getData('Text');temp = arr.splice(dragIndex, 1);arr.splice(index, 0, temp[0]);// console.log('sort');this.lists = arr;}}
});

数组对象排序

let arr = [{id: 1,weather:'晴'}, {id: 2,weather:'小雨'}, {id: 3,weather:'大雨'}, {id: 4,weather:'小雨'}, {id: 5,weather:'阴'}, {id: 6,weather:'雪'}
];function sortData(a, b) {return b.id - a.id;
}arr.sort(sortData);console.log(arr);

正则表达式实现简单模板数据填充

let templateStr = '<h1>我买了一棵{{thing}},花了{{money}}元,好{{mood}}</h1>';
let data = {thing: '白菜',money: 5,mood: '激动'
};// 最简单的模板引擎的实现机理,
// 利用的是正则表达式中的 replace() 方法。
// replace() 的第二个参数可以是一个函数,
// 这个函数提供捕获的东西的参数,就是$1
// 结合 data 对象,即可进行智能的替换
function render(templateStr, data) {return templateStr.replace(/\{\{(\w+)\}\}/g, function (findStr, $1) {return data[$1];});
}console.log(render(templateStr, data));
// <h1>我买了一棵白菜,花了5元,好激动</h1>

defineReactive函数,利用闭包封装Object.defineProperty()

function defineReactive(data, key, val) {Object.defineProperty(data, key, {// 可枚举enumerable: true,// 可以被配置,比如可以被 deleteconfigurable: true,// getter  get() { return val;},// setterset(newValue) {if (val === newValue) return false;val = newValue;}});
};
let obj = {};
defineReactive(obj, 'a', 10); // 设置 a 属性
console.log(obj.a); // 10 访问 a 的值
obj.a = 100; // 改变 a 的值
console.log(obj.a); // 100 访问改变后 a 的值

JavaScript获取字符串(string)第一个字符

let stringVal = "web半晨";
// 方式一
console.log(stringVal.charAt(0));
// 方式二
console.log(stringVal.substring(0, 1));
// 方式三
console.log(stringVal.substr(0, 1));

JavaScript递归实现数组扁平化(数组降维)

let recursionData = [{id: 1,name: "一级",children: [{id: 2,name: "二级-1",children: [{id: 7,name: "三级-1",children: [{id: 10,name: "四级-1",},],},{id: 8,name: "三级-2",},],},{id: 3,name: "二级-2",children: [{id: 5,name: "三级-3",},{id: 6,name: "三级-4",},],},{id: 4,name: "二级-3",children: [{id: 9,name: "三级-5",children: [{id: 11,name: "四级-2",},],},],},],},
],arr = [];function funRecursion(list) {for (let i in list) {arr.push({id: list[i].id,name: list[i].name,});if (list[i].children) funRecursion(list[i].children);}return arr;
}console.log(funRecursion(recursionData));
// [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]console.log(arr.map((item) => item.id).sort((a, b) => a - b));
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]

JavaScript中number和~~比较、API

function replaceNumber() {console.log(Number(null)); // 0console.log(~~null); // 0console.log("--------------------------------------------------------------");console.log(Number(undefined)); // NaNconsole.log(~~undefined); // 0console.log("--------------------------------------------------------------");console.log(Number(123)); // 123console.log(~~123); // 123console.log("--------------------------------------------------------------");console.log(Number("123")); // 123console.log(~~"123"); // 123console.log("--------------------------------------------------------------");console.log(Number("abc")); // NaNconsole.log(~~"abc"); // 0console.log("--------------------------------------------------------------");console.log(Number(NaN)); // NaNconsole.log(~~NaN); // 0
}replaceNumber();

JavaScript实现单词、字母排序

function alphabeticSorting(params) {return params.sort((a, b) => {let x = a.word,y = b.word;return x > y ? 1 : x < y ? -1 : 0;});
}let words = [{id: 1,word: "absolute",},{id: 2,word: "every",},{id: 3,word: "display",},{id: 4,word: "border",},{id: 5,word: "class",},{id: 6,word: "background",},{id: 7,word: "delete",},
];console.log(alphabeticSorting(words));

JavaScript实现分组排序单词、单词分组排序、不能实现中文首拼音排序

function groupSortWords(params) {let grouping = {},afterGrouping = [];params.forEach(item => {// 单词首字母转大写let capital = item.word.replace(/\b[a-zA-Z]+\b/g, items => {return items.charAt(0).toUpperCase();});// grouping[capital] 使用了对象不能有同一属性的原理// 相当于去重if (grouping[capital]) {grouping[capital].arr.push(item);} else {grouping[capital] = {groupingName: `${capital}`,arr: [item]}}});// 把对象变为数组for (const key in grouping) {if (Object.hasOwnProperty.call(grouping, key)) {const itemKye = grouping[key];afterGrouping.push(itemKye);}}// 外层数组排序afterGrouping = afterGrouping.sort((a, b) => {let x = a.groupingName,y = b.groupingName;return x > y ? 1 : x < y ? -1 : 0;});// 内层数组排序afterGrouping = afterGrouping.map(item => {item.arr = item.arr.sort((a, b) => {let x = a.word,y = b.word;return x > y ? 1 : x < y ? -1 : 0;});return item;})// 最终返回return afterGrouping;
}// 数据源
let words = [{id: 1652156,word: "absolute",},{id: 2365256,word: "every",},{id: 3156258,word: "display",},{id: 4695845,word: "border",},{id: 5125369,word: "class",},{id: 6985485,word: "background",},{id: 7156895,word: "delete",},{id: 8789651,word: "color",},{id: 9369529,word: "application",},{id: 1031562,word: "length",},
];// 调用函数
console.log(groupSortWords(words));

待定

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/149136.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

一键AI高清换脸——基于InsightFace、CodeFormer实现高清换脸与验证换脸后效果能否通过人脸比对、人脸识别算法

前言 1、项目简介 AI换脸是指利用基于深度学习和计算机视觉来替换或合成图像或视频中的人脸。可以将一个人的脸替换为另一个人的脸,或者将一个人的表情合成到另一个人的照片或视频中。算法常常被用在娱乐目上,例如在社交媒体上创建有趣的照片或视频,也有用于电影制作、特效…

Qt model/view 理解01

在 Qt 中对数据处理主要有两种方式&#xff1a;1&#xff09;直接对包含数据的的数据项 item 进行操作&#xff0c;这种方法简单、易操作&#xff0c;现实方式单一的缺点&#xff0c;特别是对于大数据或在不同位置重复出现的数据必须依次对其进行操作&#xff0c;如果现实方式改…

44 二叉搜索树中第K个小的元素

二叉搜索树中第K个小的元素 题解1 中序遍历题解2 AVL&#xff08;手撕平衡二叉树&#xff1a;谢谢力扣官方&#xff09; 给定一个二叉搜索树的根节点 root &#xff0c;和一个整数 k &#xff0c;请你设计一个算法查找其中第 k 个最小元素&#xff08;从 1 开始计数&#xf…

再来介绍另一个binlog文件解析的第三方工具my2sql

看腻了文字就来听听视频演示吧&#xff1a;https://www.bilibili.com/video/BV1rp4y1w74B/ github项目&#xff1a;https://github.com/liuhr/my2sql gitee链接&#xff1a;https://gitee.com/mirrors/my2sql my2sql go版MySQL binlog解析工具&#xff0c;通过解析MySQL bin…

Maven 中引用其他项目jar包出现BOOT-INF问题

问题 在B项目中引入A项目的类&#xff0c;但是发现怎么也引入不进来 A项目打包之后&#xff0c;想在B项目中引用jar 在B项目中发现类文件无法引用 参考网上进行清缓存等一系列操作都没有解决。 最后发现引用的jar包中包含BOOT-INF&#xff0c; 然后去A项目中查找&#xff…

基于回溯搜索优化的BP神经网络(分类应用) - 附代码

基于回溯搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于回溯搜索优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.回溯搜索优化BP神经网络3.1 BP神经网络参数设置3.2 回溯搜索算法应用 4.测试结果…

基于MFC和OpenCV实现人脸识别

基于MFC和OpenCV实现人脸识别 文章目录 基于MFC和OpenCV实现人脸识别1. 项目说明1. 创建项目2. 启动窗口3. 登录窗口-添加窗口、从启动窗口跳转4. 启动窗口-美化按钮5. 登录窗口-美化按钮、雪花视频6. 注册窗口-美化按钮、雪花视频、从启动窗口跳转7. 注册窗口-开启摄像头8. 注…

大恒IFrameData IImageData转bmp HObject Mat

大恒工业相机采集的帧数据转为其他8bit图像格式 C#转为bmp格式转为Halcon的HObject格式转为OpenCVSharp的Mat格式 回调采集图像的数据类型为IFrameData&#xff0c;单帧采集的数据类型为IImageData&#xff0c;两者的区别为IImageData类多了一个**Destroy()**方法 C# 转为bm…

C++标准模板(STL)- 类型支持 (定宽整数类型)(int8_t,int_fast8_t,int_least8_t,intmax_t,intptr_t)

定宽整数类型 类型 定义于头文件 <cstdint> int8_tint16_tint32_tint64_t (可选) 分别为宽度恰为 8、16、32 和 64 位的有符号整数类型 无填充位并对负值使用补码 &#xff08;仅若实现支持该类型才提供&#xff09; (typedef) int_fast8_tint_fast16_tint_fast32_tint…

第二章 线性表

线性表 线性表的基本概念线性表的顺序存储线性表顺序存储的类型定义线性表基本运算在顺序表上的实现顺序表实现算法的分析 线性表的链接存储单链表的类型定义线性表的基本运算在单链表上的实现 其他运算在单链表上的实现建表删除重复结点 其他链表循环链表双向循环链表 顺序实现…

如何将图片存到数据库(以mysql为例), 使用ORM Bee更加简单

如何将图片存到数据库 1. 创建数据库: 2. 生成Javabean public class ImageExam implements Serializable {private static final long serialVersionUID 1596686274309L;private Integer id;private String name; // private Blob image;private InputStream image; //将In…

【算法练习Day12】树的递归遍历非递归遍历

​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;练题 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 文章目录 递归遍历前序遍历中序遍历后…

《计算机视觉中的多视图几何》笔记(12)

12 Structure Computation 本章讲述如何在已知基本矩阵 F F F和两幅图像中若干对对应点 x ↔ x ′ x \leftrightarrow x x↔x′的情况下计算三维空间点 X X X的位置。 文章目录 12 Structure Computation12.1 Problem statement12.2 Linear triangulation methods12.3 Geomet…

AndroidStudio精品插件集

官网 项目地址&#xff1a;Github博客地址&#xff1a;Studio 精品插件推荐 使用需知 所有插件在 Android Studio 2022.3.1.18&#xff08;长颈鹿&#xff09;上测试均没有问题&#xff0c;推荐使用此版本Android Studio 2022.3.1.18&#xff08;长颈鹿&#xff09;正式版下…

计算机网络(六):应用层

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 应用层概述 应用层是计算机网络体系结构的最顶层&#xff0c;是设计和建立计算机网络的最终目的&#xff0c;也是计算机网络中发展最快的部分 早期基于文本的应用 (电子邮件、远程登…

【计算机网络】HTTPS协议详解

文章目录 一、HTTPS协议 介绍 1、1 HTTP协议不安全的体现 1、2 什么是 HTTPS协议 二、加密的一些概念 2、1 怎么理解加密 2、2 为什么要加密 2、3 常见的加密方式 2、2、1 对称加密 2、2、2 非对称加密 三、HTTPS协议探究加密过程 3、1 只使用对称加密 3、2 只是用非对称加密 3…

JVM篇---第三篇

系列文章目录 文章目录 系列文章目录一、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?二、Java内存结构三、说说对象分配规则一、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程。Java源文…

23.3 Bootstrap 框架4

1. 轮播 1.1 轮播样式 在Bootstrap 5中, 创建轮播(Carousel)的相关类名及其介绍: * 1. carousel: 轮播容器的类名, 用于标识一个轮播组件. * 2. slide: 切换图片的过渡和动画效果. * 3. carousel-inner: 轮播项容器的类名, 用于包含轮播项(轮播图底下椭圆点, 轮播的过程可以显…

【Docker】搭建 Docker 镜像仓库

文章目录 前言&#xff1a;公有仓库和私有仓库公共镜像仓库私有镜像仓库 一、搭建 Docker 镜像仓库1.1 搭建简化版的镜像仓库1.2 搭建带有图形化界面的镜像仓库1.3 配置 Docker 信任地址 二、向私有镜像仓库推送和拉取镜像2.1 推送本地镜像到私有仓库2.2 拉取私有仓库中的镜像 …

机器学习笔记(二)

过拟合 如下图左边,模型出现了过拟合现象 为了解决过拟合现象, 其中一个做法是多收集数据,如右图。 第二种做法是减少模型的特征数量,即x 第三种做法是正则化 正则化就是减少x前面的参数 w的数值, 不用消除x 正则化的梯度下降如下, 因为只是缩小了w的值,而 b的值保持不变 …