object
1.clone
function clone1(target){
//类型判断 {} [] null
if(typeof target === 'object' && target !== null){
//判断数据是否为数组
if(Array.isArray(target)){
return [...target];
}else{
return {...target};
}
}else{
return target;
}
}
function clone2(target){
//判断
if(typeof target === 'object' && target !== null){
//创建一个容器
const result = Array.isArray(target) ? [] : {};
//遍历 target 数据
for(let key in target) {
//判断当前对象身上是否包含该属性
if(target.hasOwnProperty(key)){
//将属性设置到 result 结果数据中
result[key] = target[key];
}
}
return result;
}else{
return target;
}
}
function deepClone1(target){
//通过数据创建 JSON 格式的字符串
let str = JSON.stringify(target);
//将 JSON 字符串创建为 JS 数据
let data = JSON.parse(str);
return data;
}
function deepClone2(target){
//检测数据的类型
if(typeof target === 'object' && target !== null ){
//创建一个容器
const result = Array.isArray(target) ? [] : {};
//遍历对象
for(let key in target){
//检测该属性是否为对象本身的属性(不能拷贝原型对象的属性)
if(target.hasOwnProperty(key)){
//拷贝
result[key] = deepClone2(target[key]);
}
}
return result;
}else{
return target;
}
}
function deepClone3(target, map=new Map()){
//检测数据的类型
if(typeof target === 'object' && target !== null ){
//克隆数据之前, 进行判断, 数据之前是否克隆过
let cache = map.get(target);
if(cache){
return cache;
}
//创建一个容器
const result = Array.isArray(target) ? [] : {};
//将新的结果存入到容器中
map.set(target, result);
//遍历对象
for(let key in target){
//检测该属性是否为对象本身的属性(不能拷贝原型对象的属性)
if(target.hasOwnProperty(key)){
//拷贝
result[key] = deepClone3(target[key], map);
}
}
return result;
}else{
return target;
}
}
function deepClone4(target, map=new Map()){
//检测数据的类型
if(typeof target === 'object' && target !== null ){
//克隆数据之前, 进行判断, 数据之前是否克隆过
let cache = map.get(target);
if(cache){
return cache;
}
//判断目标数据的类型
let isArray = Array.isArray(target);
//创建一个容器
const result = isArray ? [] : {};
//将新的结果存入到容器中
map.set(target, result);
//如果目标数据为数组
if(isArray){
//forEach 遍历
target.forEach((item, index) => {
result[index] = deepClone4(item, map);
});
}else{
//如果是对象, 获取所有的键名, 然后 forEach 遍历
Object.keys(target).forEach(key => {
result[key] = deepClone4(target[key], map);
});
}
return result;
}else{
return target;
}
}
2.mergeObject
function mergeObject(...objs){
//声明一个空对象
const result = {};
//遍历所有的参数对象
objs.forEach(obj => {
//获取当前对象所有的属性
Object.keys(obj).forEach(key => {
//检测 result 中是否存在 key 属性
if(result.hasOwnProperty(key)){
result[key] = [].concat(result[key], obj[key]);
}else{
//如果没有 则直接写入
result[key] = obj[key];
}
});
});
return result;
}
3.myInstanceOf
function myInstanceOf(obj, Fn) {
//获取函数的显式原型
let prototype = Fn.prototype
//获取 obj 的隐式原型对象
let proto = obj.__proto__
//遍历原型链
while (proto) {
//检测原型对象是否相等
if (prototype === proto) {
return true
}
//如果不等于
proto = proto.__proto__
}
return false
}
function myInstanceOf(obj, Fn) {
let proto = Object.getPrototypeOf(obj)
while (true) {
if (proto === null) return false
if (proto === Fn.prototype) return true
proto = Object.getPrototypeOf(proto)
}
}
4.newInstance
function newInstance(Fn, ...args){
//1. 创建一个新对象
const obj = {};
//2. 修改函数内部 this 指向新对象并执行
const result = Fn.call(obj, ...args);
//修改新对象的原型对象
obj.__proto__ = Fn.prototype;
//3. 返回新对象
return result instanceof Object ? result : obj;
}
function
1.apply
function apply(Fn, obj, args) {
obj = obj || globalThis
obj.temp = Fn
let arr = []
for (let i = 0; i < args.length; i++) {
arr.push(args[i])
}
let res = obj.temp(...arr)
delete obj.temp
return res
}
2.bind
function bind(Fn, obj, ...args){
//返回一个新的函数
return function(...args2){
//执行 call 函数
return call(Fn, obj, ...args, ...args2);
}
}
3.call
function call(Fn, obj, ...args){
//判断
if(obj === undefined || obj === null){
obj = globalThis;// 全局对象
}
//为 obj 添加临时的方法
obj.temp = Fn;
//调用 temp 方法
let result = obj.temp(...args);
//删除 temp 方法
delete obj.temp;
//返回执行结果
return result;
}
4.debounce
function debounce(callback, time){
//定时器变量
let timeId = null;
//返回一个函数
return function(e){
//判断
if(timeId !== null){
//清空定时器
clearTimeout(timeId);
}
//启动定时器
timeId = setTimeout(() => {
//执行回调
callback.call(this, e);
//重置定时器变量
timeId = null;
}, time);
}
}
5.throttle
function throttle(callback, wait){
//定义开始时间
let start = 0;
//返回结果是一个函数
return function(e){
//获取当前的时间戳
let now = Date.now();
//判断
if(now - start >= wait){
//若满足条件, 则执行回调函数
callback.call(this, e);
//修改开始时间
start = now;
}
}
}
array
1. chunk
function chunk(arr, size = 1) {
//判断
if (arr.length === 0) {
return []
}
//声明两个变量
let result = []
let tmp = [] // [1,2,3]
//遍历
arr.forEach((item) => {
//判断tmp元素长度是否为 0
if (tmp.length === 0) {
//将 tmp 压入到 result 中
result.push(tmp)
// [ [1,2,3], [4,5,6], [7] ]
}
//将元素压入到临时数组 tmp 中
tmp.push(item)
//判断
if (tmp.length === size) {
tmp = []
}
})
return result
}
2.concat
function concat(arr, ...args){
//声明一个空数组
const result = [...arr];
//遍历数组
args.forEach(item => {
//判断 item 是否为数组
if(Array.isArray(item)){
result.push(...item);
}else{
result.push(item);
}
});
//返回 result
return result;
}
3.declares
function map(arr, callback){
//声明一个空的数组
let result = [];
//遍历数组
for(let i=0;i<arr.length;i++){
//执行回调
result.push(callback(arr[i], i));
}
//返回结果
return result;
}
function reduce(arr, callback, initValue){
//声明变量
let result = initValue;
//执行回调
for(let i=0;i<arr.length;i++){
//执行回调
result = callback(result, arr[i]);
}
//返回最终的结果
return result;
}
function filter(arr, callback){
//声明空数组
let result = [];
//遍历数组
for(let i=0;i<arr.length;i++){
//执行回调
let res = callback(arr[i], i);
//判断 如果为真则压入到 result 结果中
if(res){
result.push(arr[i]);
}
}
//返回结果
return result;
}
function find(arr, callback){
//遍历数组
for(let i=0;i<arr.length;i++){
//执行回调
let res = callback(arr[i], i);
//判断
if(res){
//返回当前正在遍历的元素
return arr[i];
}
}
//如果没有遇到满足条件的 返回 undefined
return undefined;
}
function findIndex(arr, callback){
//遍历数组
for(let i=0;i<arr.length;i++){
//执行回调
let res = callback(arr[i], i);
//判断
if(res){
//返回当前正在遍历的元素
return i;
}
}
//如果没有遇到满足条件的 返回 undefined
return -1;
}
function every(arr, callback){
//遍历数组
for(let i=0;i<arr.length;i++){
// 执行回调 如果回调执行返回结果为 false
if(!callback(arr[i], i)){
return false;
}
}
//如果都满足条件则返回 true
return true;
}
function some(arr, callback){
//遍历数组
for(let i=0;i<arr.length;i++){
// 执行回调 如果回调执行返回结果为 false
if(callback(arr[i], i)){
return true;
}
}
//如果都满足条件则返回 true
return false;
}
4.difference
function difference(arr1, arr2=[]){
//判断参数
if(arr1.length === 0){
return [];
}
if(arr2.length === 0){
return arr1.slice();
}
const result = arr1.filter(item => !arr2.includes(item));
return result;
}
5.drop
function drop(arr, size){
//过滤原数组 产生新数组
// return arr.filter((value, index) => {
// //
// return index >= size;
// });
return arr.filter((value, index) => index>=size);
}
function dropRight(arr, size){
// return arr.filter((value,index)=>{
// return index < arr.length - size;
// });
return arr.filter((value, index) => index < arr.length - size);
}
6.flatten
function flatten1(arr){
//声明空数组
let result = [];
//遍历数组
arr.forEach(item => {
//判断
if(Array.isArray(item)){
result = result.concat(flatten1(item));
}else{
result = result.concat(item);
}
});
//返回结果
return result;
}
function flatten2(arr){
//声明数组
let result = [...arr];
//循环判断
while(result.some(item => Array.isArray(item))){
// [1,2,[3,4,[5,6]],7]
// result = [].concat(1,2,[3,4,[5,6]],7);// [1,2,3,4,[5,6],7]
// result = [].concat(1,2,3,4,[5,6],7);// [1,2,3,4,5,6,7]
result = [].concat(...result);//
}
//返回结果
return result;
}
7.pull
function pull(arr, ...args){
//声明空数组 保存删掉的元素
const result = [];
//遍历 arr
for(let i=0;i<arr.length;i++){
//判断当前元素是否存在于 args 数组中
if(args.includes(arr[i])){
//将当前元素的值存入到 result 中
result.push(arr[i]);
//删除当前的元素
arr.splice(i, 1);
//下标自减
i--;
}
}
//返回
return result;
}
function pullAll(arr, values){
return pull(arr, ...values);
}
8.slice
function slice(arr, begin, end){
//若arr数组长度为 0
if(arr.length === 0){
return [];
}
//判断 begin
begin = begin || 0;
if(begin >= arr.length){
return [];
}
//判断 end
end = end || arr.length;
if(end < begin){
end = arr.length;
}
//声明一个空数组
const result = [];
//遍历对象
for(let i=0;i<arr.length;i++){
if(i >= begin && i < end){
//将下标对应的元素压入数组
result.push(arr[i]);
}
}
return result;
}
9.unique
function unique1(arr){
//声明一个空数组
const result = [];
//遍历原始数组
arr.forEach(item => {
//检测 result 数组中是否包含这个元素
if(result.indexOf(item) === -1) {
//若没有该元素 则插入到result中
result.push(item);
}
});
//返回
return result;
}
function unique2(arr){
//声明空数组
const result = [];
//声明空对象
const obj = {};
//遍历数组
arr.forEach(item => {
if(obj[item] === undefined){
//将 item 作为下标存储在 obj 中
obj[item] = true;
result.push(item);
}
});
//返回结果
return result;
}
function unique3(arr){
// //将数组转化为集合 Set
// let set = new Set(arr);
// //将 set 展开创建一个数组
// let array = [...set];
// return array;
return [...new Set(arr)];
}
其它
1. array to tree \ tree to array
// 转换前:
source = [
{
id: 1,
pid: 0,
name: 'body',
},
{
id: 2,
pid: 1,
name: 'title',
},
{
id: 3,
pid: 2,
name: 'div',
},
]
// 转换为:
tree = [
{
id: 1,
pid: 0,
name: 'body',
children: [
{
id: 2,
pid: 1,
name: 'title',
children: [
{
id: 3,
pid: 1,
name: 'div',
},
],
},
],
},
]
代码实现:
//数组转树
function arrayToTree(data) {
// 初始化结果数组,并判断输入数据的格式
let result = []
if(!Array.isArray(data)) {
return result
}
// 使用map,将当前对象的id与当前对象对应存储起来
let map = {};
data.forEach(item => {
map[item.id] = item;
});
//
data.forEach(item => {
let parent = map[item.pid];
if(parent) {
(parent.children || (parent.children = [])).push(item);
} else {
result.push(item);
}
});
return result;
}
//树转数组
function treeToList(data, res = []) {
data.forEach((item) => {
res.push(item)
if (item.children) {
treeToList(item.children, res)
delete item.children
}
})
return res
}
//树转数组
function treeToArray(obj) {
const stack = [] // 声明栈,用来存储待处理元素
const res = [] // 接收结果
stack.push(obj) // 将初始元素压入栈
while (stack.length) {
// 栈不为空则循环执行
const item = stack[0] // 取出栈顶元素
res.push(item) // 元素本身压入结果数组
stack.shift() // 将当前元素弹出栈
// 逻辑处理,如果当前元素包含子元素,则将子元素压入栈
if (item.children && item.children.length) {
stack.push(...item.children)
}
}
return res
}
2. 手写 Promise
//声明构造函数
function Promise(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的 this 的值
const self = this;// self _this that
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//执行失败的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
});
});
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//添加 then 方法
Promise.prototype.then = function(onResolved, onRejected){
const self = this;
//判断回调函数参数
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
//value => { return value};
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type){
try{
//获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if(result instanceof Promise){
//如果是 Promise 类型的对象
result.then(v => {
resolve(v);
}, r=>{
reject(r);
})
}else{
//结果的对象状态为『成功』
resolve(result);
}
}catch(e){
reject(e);
}
}
//调用回调函数 PromiseState
if(this.PromiseState === 'fulfilled'){
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected'){
setTimeout(() => {
callback(onRejected);
});
}
//判断 pending 状态
if(this.PromiseState === 'pending'){
//保存回调函数
this.callbacks.push({
onResolved: function(){
callback(onResolved);
},
onRejected: function(){
callback(onRejected);
}
});
}
})
}
//添加 catch 方法
Promise.prototype.catch = function(onRejected){
return this.then(undefined, onRejected);
}
//添加 resolve 方法
Promise.resolve = function(value){
//返回promise对象
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}else{
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
Promise.reject = function(reason){
return new Promise((resolve, reject)=>{
reject(reason);
});
}
//添加 all 方法
Promise.all = function (promises) {
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0
let arr = []
//遍历
for (let i = 0; i < promises.length; i++) {
//
promises[i].then(
(v) => {
//得知对象的状态是成功
//每个promise对象 都成功
count++
//将当前promise对象成功的结果 存入到数组中
arr[i] = v
//判断
if (count === promises.length) {
//修改状态
resolve(arr)
}
},
(r) => {
reject(r)
}
)
}
})
}
//添加 race 方法
Promise.race = function(promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promises.length;i++){
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
},r=>{
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
class Promise{
//构造方法
constructor(executor){
//添加属性
this.PromiseState = 'pending';
this.PromiseResult = null;
//声明属性
this.callbacks = [];
//保存实例对象的 this 的值
const self = this;// self _this that
//resolve 函数
function resolve(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'fulfilled';// resolved
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//调用成功的回调函数
setTimeout(() => {
self.callbacks.forEach(item => {
item.onResolved(data);
});
});
}
//reject 函数
function reject(data){
//判断状态
if(self.PromiseState !== 'pending') return;
//1. 修改对象的状态 (promiseState)
self.PromiseState = 'rejected';//
//2. 设置对象结果值 (promiseResult)
self.PromiseResult = data;
//执行失败的回调
setTimeout(() => {
self.callbacks.forEach(item => {
item.onRejected(data);
});
});
}
try{
//同步调用『执行器函数』
executor(resolve, reject);
}catch(e){
//修改 promise 对象状态为『失败』
reject(e);
}
}
//then 方法封装
then(onResolved,onRejected){
const self = this;
//判断回调函数参数
if(typeof onRejected !== 'function'){
onRejected = reason => {
throw reason;
}
}
if(typeof onResolved !== 'function'){
onResolved = value => value;
//value => { return value};
}
return new Promise((resolve, reject) => {
//封装函数
function callback(type){
try{
//获取回调函数的执行结果
let result = type(self.PromiseResult);
//判断
if(result instanceof Promise){
//如果是 Promise 类型的对象
result.then(v => {
resolve(v);
}, r=>{
reject(r);
})
}else{
//结果的对象状态为『成功』
resolve(result);
}
}catch(e){
reject(e);
}
}
//调用回调函数 PromiseState
if(this.PromiseState === 'fulfilled'){
setTimeout(() => {
callback(onResolved);
});
}
if(this.PromiseState === 'rejected'){
setTimeout(() => {
callback(onRejected);
});
}
//判断 pending 状态
if(this.PromiseState === 'pending'){
//保存回调函数
this.callbacks.push({
onResolved: function(){
callback(onResolved);
},
onRejected: function(){
callback(onRejected);
}
});
}
})
}
//catch 方法
catch(onRejected){
return this.then(undefined, onRejected);
}
//添加 resolve 方法
static resolve(value){
//返回promise对象
return new Promise((resolve, reject) => {
if(value instanceof Promise){
value.then(v=>{
resolve(v);
}, r=>{
reject(r);
})
}else{
//状态设置为成功
resolve(value);
}
});
}
//添加 reject 方法
static reject(reason){
return new Promise((resolve, reject)=>{
reject(reason);
});
}
//添加 all 方法
static all(promises){
//返回结果为promise对象
return new Promise((resolve, reject) => {
//声明变量
let count = 0;
let arr = [];
//遍历
for(let i=0;i<promises.length;i++){
//
promises[i].then(v => {
//得知对象的状态是成功
//每个promise对象 都成功
count++;
//将当前promise对象成功的结果 存入到数组中
arr[i] = v;
//判断
if(count === promises.length){
//修改状态
resolve(arr);
}
}, r => {
reject(r);
});
}
});
}
//添加 race 方法
static race (promises){
return new Promise((resolve, reject) => {
for(let i=0;i<promises.length;i++){
promises[i].then(v => {
//修改返回对象的状态为 『成功』
resolve(v);
},r=>{
//修改返回对象的状态为 『失败』
reject(r);
})
}
});
}
}
3.axios
function axios({ method, url, params, data }) {
//方法转化大写
method = method.toUpperCase()
//返回值
return new Promise((resolve, reject) => {
//四步骤
//1. 创建对象
const xhr = new XMLHttpRequest()
//2. 初始化
//处理 params 对象 a=100&b=200
let str = ""
for (let k in params) {
str += `${k}=${params[k]}&`
}
str = str.slice(0, -1)
xhr.open(method, url + "?" + str)
//3. 发送
if (method === "POST" || method === "PUT" || method === "DELETE") {
//Content-type mime类型设置
xhr.setRequestHeader("Content-type", "application/json")
//设置请求体
xhr.send(JSON.stringify(data))
} else {
xhr.send()
}
//设置响应结果的类型为 JSON
xhr.responseType = "json"
//4. 处理结果
xhr.onreadystatechange = function () {
//
if (xhr.readyState === 4) {
//判断响应状态码 2xx
if (xhr.status >= 200 && xhr.status < 300) {
//成功的状态
resolve({
status: xhr.status,
message: xhr.statusText,
body: xhr.response,
})
} else {
reject(new Error("请求失败, 失败的状态码为" + xhr.status))
}
}
}
})
}
axios.get = function (url, options) {
//发送 AJAX 请求 GET
let config = Object.assign(options, { method: "GET", url: url })
return axios(config)
}
axios.post = function (url, options) {
//发送 AJAX 请求 GET
let config = Object.assign(options, { method: "POST", url: url })
return axios(config)
}
axios.put = function (url, options) {
//发送 AJAX 请求 GET
let config = Object.assign(options, { method: "PUT", url: url })
return axios(config)
}
axios.delete = function (url, options) {
//发送 AJAX 请求 GET
let config = Object.assign(options, { method: "delete", url: url })
return axios(config)
}
4.event-bind
function addEventListener(el, type, fn, selector){
//判断 el 的类型
if(typeof el === 'string'){
el = document.querySelector(el);
}
//事件绑定
//若没有传递子元素的选择器, 则给 el 元素绑定事件
if(!selector){
el.addEventListener(type, fn);
}else{
el.addEventListener(type, function(e){
//获取点击的目标事件源
const target = e.target;
//判断选择器与目标元素是否相符合
if(target.matches(selector)){
//若符合 则调用回调
fn.call(target, e);
}
});
}
}
5.event-bus
const eventBus = {
//保存类型与回调的容器
callbacks: {}
};
//绑定事件
eventBus.on = function(type, callback){
//判断
if(this.callbacks[type]){
//如果 callbacks 属性中存在该类型事件
this.callbacks[type].push(callback);
}else{
//如果 callbacks 属性中不存在该类型事件
this.callbacks[type] = [callback];
}
}
//触发事件
eventBus.emit = function(type, data){
//判断
if(this.callbacks[type] && this.callbacks[type].length > 0){
//遍历数组
this.callbacks[type].forEach(callback => {
//执行回调
callback(data);
});
}
}
//事件的解绑
eventBus.off = function(eventName){
//若传入了 eventName 事件类型
if(eventName){
//只是删除 eventName 对应的事件回调
delete this.callbacks[eventName];
}else{
this.callbacks = {};
}
}
6.pub-sub
const PubSub = {
//订阅唯一id
id: 1,
//频道与回调保存容器
callbacks: {
// pay: {
// token_1: fn
// token_2: fn
// },
// cancel: {
// token_3:
// token_4
// },
// other: {
// token_10
// }
},
}
/**订阅频道 */
PubSub.subscribe = function (channel, callback) {
//创建唯一的编号
let token = "token_" + this.id++ //
//pay token_1
//判断 callbacks 属性中是否存在 pay
if (this.callbacks[channel]) {
this.callbacks[channel][token] = callback
} else {
this.callbacks[channel] = {
[token]: callback,
}
}
//返回频道订阅的 id
return token
}
/* 发布消息 */
PubSub.publish = function (channel, data) {
//获取当前频道中所有的回调
if (this.callbacks[channel]) {
//
Object.values(this.callbacks[channel]).forEach((callback) => {
//执行回调
callback(data)
})
}
}
/**取消订阅 */
// 1). 没有传值, flag 为 undefined
// 2). 传入token字符串
// 3). msgName字符串
PubSub.unsubscribe = function (flag) {
//如果flag为undeined 则清空所有订阅
if (flag === undefined) {
this.callbacks = {}
} else if (typeof flag === "string") {
//判断是否为 token_ 开头
if (flag.indexOf("token_") === 0) {
//如果是 标明是一个订阅id
let callbackObj = Object.values(this.callbacks).find((obj) =>
obj.hasOwnProperty(flag)
)
//判断
if (callbackObj) {
delete callbackObj[flag]
}
} else {
//表明是一个频道的名称
delete this.callbacks[flag]
}
}
}
7.string
function reverseString(str){
//将字符串转为数组
// let arr = str.split('');
let arr = [...str];
//翻转数组
arr.reverse();
//将数组拼接成字符串
let s = arr.join('');
return s;
}
function palindrome(str){
return reverseString(str) === str;
}
function truncate(str, size){
return str.slice(0, size) + '...';
}