当前位置: 首页 > news >正文

day22JS-对象静态方法

1. 创建对象的三种方法

  1. 用{}字面量创建:var 对象名 = {};
  2. 用new的方式创建:var 对象名 = new Object();
  3. 以什么对象为原型创建一个新对象:Object.create(对象名);

注意!!!

  • Object.create(对象名)方法的参数只能是对象或null。
  • 如果使用Object.create(null)作为原型创建对象,无属性,没有原型链,所以不能使用对象的任何方法。
  • Object.create(对象名)方法可以设置原型链。

 案例1:

    // 方法一:var o = {};// 方法二:var o = new Object();// 方法三: Object.create() 以什么对象为原型创建一个新对象var o = { a: 1, b: 2 };var o1 = Object.create(o);o1.c = 3;o1.d = 4;console.log(o1);

案例2:

    var o = Object.create(null);console.log(o);//无属性console.log(o + "1");//报错

案例3:

    var o1 = { a: 1 };var o2 = Object.create(o1);o2.b = 2;o2.z = 10;var o3 = Object.create(o2);o3.c = 3;o3.z = 100;var o4 = Object.create(o3);o4.d = 4;console.log(o4);

2. 对象属性

        对象属性分为对象属性原型属性。

        当获取对象属性时,首先查找对象的对象属性,如果没有则向下继续查找原型属性,找到最近的原型属性返回。

        当给对象设置属性时,不能设置原型属性只能设置对象的对象属性。原型对象的引用地址和对应的对象是一致。

案例1:

    var o1 = { a: 1 };var o2 = Object.create(o1);o2.b = 2;o2.z = 10;var o3 = Object.create(o2);o3.c = 3;o3.z = 100;var o4 = Object.create(o3);o4.d = 4;console.log(o4);// 对象属性中分为对象属性和原型属性// 当获取对象属性时,首先查找对象的对象属性,如果没有则向下继续查找原型属性,找到最近的原型属性返回console.log(o4.d);console.log(o4.b);console.log(o4.z);// 当给对象设置属性时,不能设置原型属性,只能设置对象的对象属性o4.z = 1000;console.log(o4);// 原型对象的引用地址和对应的对象是一致o3.z = 1;console.log(o4);

3. 获取原型链的方法

获取原型链的方法:

  1. 对象名.__proto__ :禁止使用__proto__
  2. Object.getPrototypeOf(对象名)

设置原型链的方法:

  1. 对象名.__proto__ = 对象名;:禁止使用__proto__
  2. Object.setPrototypeOf(目标对象, 作为原型链的对象);
  3. Object.create(对象名);

案例1: 

    var o1 = { a: 1 };var o2 = Object.create(o1);o2.b = 2;o2.z = 10;var o3 = Object.create(o2);o3.c = 3;o3.z = 100;var o4 = Object.create(o3);o4.d = 4;// 原型对象的引用地址和对应的对象是一致// 获取原型链  禁止使用__proto__console.log(o4.__proto__ === o3);// 获取原型链console.log(Object.getPrototypeOf(o4));

 案例2:

    var o1 = { a: 1 };var o2 = { b: 2 };// 禁止使用// o2.__proto__ = o1;// 设置原型链Object.setPrototypeOf(o2, o1);console.log(o2);

案例3: 使用两种方法让第一个对象{a:1}作为第二个对象{b:2}的原型,第二个对象{b:2}作为第三个对象 {c:3}的原型,形成原型链。

    // 方法一:var o1 = { a: 1 };var o2 = Object.create(o1);o2.b = 2;var o3 = Object.create(o2);o3.c = 3;console.log(o3);
-----------------------------------------------// 方法二:var o1 = { a: 1 };var o2 = { b: 2 };var o3 = { c: 3 };Object.setPrototypeOf(o2, o1);Object.setPrototypeOf(o3, o2);console.log(o3);

4. 迭代器和判断属性是否是当前对象的对象属性

遍历方法:

  1. for in 遍历:遍历对象时,可以遍历对象中的对象属性原型链属性不能遍历不可枚举属性。
  2. for of 遍历 :只能遍历迭代器。不能遍历对象。对象要使用for of必须使用迭代器。

判断这个属性是不是当前对象的对象属性的方法:

  1. Object.hasOwn(对象名,属性名):判断这个属性是不是当前对象的对象属性。

        Object.hasOwn(数组名,所以下标):判断数组的下标是不是空元素。

     2. 对象.hasOwnProperty(属性名) :判断这个属性是不是当前对象的对象属性。

迭代器:

  1. Object.entries(对象名):将对象转换为数组迭代器(二维数组)。例如:[["a",1],["b",2]]。
  2. Object.fromEntries(数组迭代器) :将数组迭代器(二维数组)转换为对象

案例1:

    var o1 = { a: 1 };var o2 = { b: 2 };var o3 = { c: 3 };Object.setPrototypeOf(o2, o1);Object.setPrototypeOf(o3, o2);// 遍历对象时,可以遍历对象中的对象属性和原型链属性,不能遍历不可枚举属性// Object.hasOwn(对象,属性)判断这个属性是不是当前对象的对象属性// 对象.hasOwnProperty(属性) 判断这个属性是不是当前对象的对象属性for (var key in o3) {console.log(key);console.log(key, Object.hasOwn(o3, key));console.log(o3.hasOwnProperty(key));}

案例2:

    var arr = ["a", "b", , "c"];// Object.hasOwn(数组,下标)判断数组的下标是不是空元素console.log(Object.hasOwn(arr, 2));console.log(arr.hasOwnProperty(2));

案例3:

    var o = { a: 1, b: 2, c: 3 };console.log(Object.entries(o));// [["a",1],["b",2],["c",3]]// 对象不是迭代器,本身不能使用for offor (var [key, value] of Object.entries(o)) {console.log(key, value);}

案例4:

    // 将迭代器转换为对象var o = Object.fromEntries([["a", 1], ["b", 2]])console.log(o);

 5. 对象浅复制

 Object.assign(目标对象,...源对象) :将源对象中所有可枚举的对象属性复制到目标对象的对象属性上,如果源对象中的属性有重复,后面的会覆盖前面的源对象可以是多个。 这个方法最后返回目标对象

 案例1:

    var o = { a: 1, b: 2 };var o1 = Object.create(o);o1.c = 3;o1.d = 4;var o2 = { e: 4, f: 5 };Object.assign(o2, o1);console.log(o2);

案例2:

    var o1 = { a: 1 };var o2 = { b: 2, z: 1 };var o3 = { c: 3, z: 2 };var o4 = { d: 4 };Object.assign(o4, o1, o2, o3)console.log(o4);

案例3:

    var o1 = { a: 1 };var o2 = { b: 2 };var o3 = Object.assign({}, o1, o2);console.log(o3);// {...}这种写法一般用于创建一个新对象// Object.assign() 用于已有对象复制使用var o4 = { ...o1, ...o2 };console.log(o4);

 6. 冻结、密封、禁止扩展对象

  1. Object.freeze(对象名):冻结对象。对象不能删除属性,不能添加新属性,不能修改属性值。在js中没有enum枚举所以使用该方法可以属性enum 枚举。
  2. Object.isFrozen(对象名):当前对象是否被冻结。

  1. Object.seal(对象名): 密封对象,可以修改属性,但是不能删除和添加新属性。
  2. Object.isSealed(对象名):判断是否被密封。

  1. Object.preventExtensions(对象名) : 禁止扩展对象,可以删除属性,可以修改属性,但是不能添加新属性。
  2. Object.isExtensible(对象名) : 判断是否被禁止扩展对象。false代表禁止扩展, true表示可扩展。

案例1:

    // 冻结对象 对象不能删除属性,不能添加新属性,不能修改属性值var o = { a: 1, b: 2 };Object.freeze(o)// 删除对象属性delete o.a;console.log(o);// 修改对象属性o.a = 10;console.log(o);// 添加对象属性o.c = 10;console.log(o);

案例2:

    const COLOR = Object.freeze({ RED: "RED", BLUE: "BLUE", YELLOW: "YELLOW", GREEN: "GREEN" })// 当前对象是否被冻结console.log(Object.isFrozen(COLOR));//true

案例3:

    var o1 = Object.seal({ a: 1, b: 2 })o1.a = 10;console.log(o1);// 判断是否被密封console.log(Object.isSealed(o1));

案例4:

    // 禁止扩展 可以删除属性,可以修改属性,但是不能添加新属性var o1 = Object.preventExtensions({ a: 1, b: 2 })delete o1.a;o1.b = 10;o1.c = 20;console.log(o1);// false代表禁止扩展 true表示可扩展console.log(Object.isExtensible(o1));

7. 添加属性并定义该属性特性的方法

1. Object.defineProperty(对象, "属性名", 属性描述对象) :定义单个属性。该方法不能删除,在严格模式下,删除会报错;不能重新定义;属性定义为不可枚举时for in是不能遍历到该属性的,但能拿到该属性的值;当该属性定义为不可修改时,该属性不能修改,如果在严格模式下,删除会报错。

属性描述对象中的属性:

  • enumerable:是否可枚举。布尔值。
  • configurable: 是否可删除或者重新设置属性描述对象。布尔值。
  • writable:是否可写,是否可以修改。布尔值。
  • value : 如果value是非函数,则这是一个属性值,如果value是一个函数,则这是一个方法。value:function(){...}或value(){...}都表示value是一个函数。

该方法的使用模板1:

    Object.defineProperty(对象名, "属性名", {

      enumerable: true,

      configurable: true,

      writable: true,

      value: 属性值,

    })

该方法的使用模板2:

    Object.defineProperty(对象名, "属性名",{

      enumerable: true,

      configurable: true,

      set(value) {

      },

      get() {

      }

    })

特性写法:这个写法默认该属性不可删除,不可修改,不可枚举

    Object.defineProperty(对象名, "属性名", {

      // 默认如果不写则为false

      value: 属性值

    })

2. Object.defineProperties(对象,对象多属性描述对象):定义多个属性。

该方法使用模板:

    Object.defineProperties(对象名, {

      // 属性名:属性描述对象

      a: {

        enumerable: true,

        configurable: true,

        writable: false,

        value: 1

      },

      b: {

        value: 2

      }

    })

案例1:

    // 属性var o = { a: 1, b: 2 };Object.defineProperty(o, "c", {enumerable: true,configurable: true,writable: true,value: 3,})console.log(o);

案例2: 

    var o = { a: 1, b: 2 };Object.defineProperty(o, "play", {enumerable: true,configurable: true,writable: true,// value:function(){}value() {console.log("play");}})console.log(o);

案例3:

    var o = { a: 1, b: 2 };Object.defineProperty(o, "c", {configurable: false,writable: true,enumerable: true,value: 3})// 不能删除delete o.c;console.log(o);// 不能重新定义Object.defineProperty(o, "c", {//报错configurable: true,writable: true,enumerable: true,value: 3})console.log(o);

案例4:属性c不能被遍历出来。

    var o = { a: 1, b: 2 };Object.defineProperty(o, "c", {configurable: true,enumerable: false,//不可枚举writable: true,value: 3})console.log(o);for (var key in o) {console.log(key);}

 案例5:

    var o = { a: 1, b: 2 };Object.defineProperty(o, "c", {configurable: true,enumerable: true,writable: false,//不可修改,不可写value: 3})o.c = 10;console.log(o.c);//3

案例6:定义多个属性

    var o = {};Object.defineProperties(o, {// 属性名:属性描述对象a: {enumerable: true,configurable: true,writable: false,value: 1},b: {value: 2}})console.log(o);

 案例7:

    var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})console.log(o);

8. 遍历不可枚举属性的方法

for in遍历:不靠谱,只能遍历可枚举,并且只能是字符的串属性名。

  1. Object.getOwnPropertyNames(对象名) :获取对象的所有可枚举和不可枚举的字符串属性名。
  2. Object.getOwnPropertySymbols(对象名):获取对象的所有可枚举和不可枚举的Symbol属性名。
  3. Reflect.ownKeys(对象名): Reflect 针对Object对象的所有方法反射方法集,获取到对象中所有的可枚举和不可枚举的任意类型属性名。

案例1:

    var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})console.log(o);// 不靠谱 只能遍历可枚举,并且字符串属性名// for (var key in o) {//   console.log(key, o[key]);// }// 获取对象的所有可枚举和不可枚举的字符串属性名var arr = Object.getOwnPropertyNames(o);// 获取对象的所有可枚举和不可枚举的Symbol属性名var arr1 = Object.getOwnPropertySymbols(o);console.log(arr, arr1);

案例2:遍历

    var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})console.log(o);// 合并写法一;var arr = Object.getOwnPropertyNames(o).concat(Object.getOwnPropertySymbols(o))for (var i = 0; i < arr.length; i++) {console.log(arr[i], o[arr[i]]);}-----------------------------------------------------------------------------------------var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})console.log(o);// 合并写法二;var arr = [...Object.getOwnPropertyNames(o), ...Object.getOwnPropertySymbols(o)]for (var i = 0; i < arr.length; i++) {console.log(arr[i], o[arr[i]]);}
-----------------------------------------------------------------------------------------var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})console.log(o);// 获取到对象中所有的可枚举和不可枚举的任意类型属性名// Reflect 针对Object对象的所有方法反射方法集var arr = Reflect.ownKeys(o);for (var i = 0; i < arr.length; i++) {console.log(arr[i], o[arr[i]]);}

 

9. 获取对象属性的描述对象

  1. Object.getOwnPropertyDescriptor(对象名, "属性名") :获取对象属性的描述对象。
  2. Object.getOwnPropertyDescriptors(对象名) : 获取对象属性上所有的描述对象。

案例1:

    var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})// 获取对象属性的描述对象var desc = Object.getOwnPropertyDescriptor(o, "c");console.log(desc);

 案例2:

    var o = {a: 1,"b-1": 2,[Symbol("a")]: 3}Object.defineProperties(o, {c: {value: 4},[Symbol("b")]: {writable: true,value: 5}})// 获取对象属性上所有的描述对象var descs = Object.getOwnPropertyDescriptors(o);console.log(descs);

 10. 对象群组方法

Object.groupBy( 数组迭代器, function (元素, 索引下标) { }):遍历或分组。返回的是数组。

案例1:

   var o = { a: 1, b: 2 };Object.groupBy(Object.entries(o), function (item, index) {console.log(item, index);})

案例2:

    var arr = ["a", "b", "c"];Object.groupBy(arr, function (item, index) {console.log(item, index);})

 案例3:

    var list = [{ a: 1, type: 0, price: 1000 },{ a: 2, type: 1, price: 2000 },{ a: 3, type: 0, price: 2000 },{ a: 4, type: 1, price: 3000 },{ a: 5, type: 1, price: 4000 },{ a: 6, type: 0, price: 5000 },]var list1 = Object.groupBy(list, (item) => item.type);console.log(list1);

 

11. isNaN()、Number.isNaN()和Object.is()的区别

  1. isNaN() :该方法会隐式转化,在判断是不是NaN。
  2. Number.isNaN():该方法直接判断NaN。不会隐式转化。
  3. Object.is():该方法是判断两个值是否绝对相等(===),不会隐式转化。能判断与NaN是否绝对相等(===)。

 案例1:

    // isNaN()// Number.isNaN()不会隐式转换// Object.is()  与===相类似  判断是否绝对相等var a = 1;var b = "1";console.log(Object.is(a, b));//false// ===永远不等于NaNconsole.log(Number("a") === NaN);console.log(Object.is("a", NaN)); 

12. 获取对象key-valus的方法

Object.keys(对象名) :只能获取到对象中所有可枚举的字符串属性名组成数组。

Object.values(对象名) :只能获取到对象中所有可枚举的字符串属性名对应属性值组成数组。

 案例:

    var obj = { a: 1, b: 2, c: 3 };// 只能获取到对象中所有可枚举的字符串属性名组成数组console.log(Object.keys(obj));// 只能获取到对象中所有可枚举的字符串属性名对应属性值组成数组console.log(Object.values(obj));

 13. 对象的getter和setter

 getter和setter是访问器属性。

希望可以像属性一样使用=号赋值,并且在赋值后还可以执行多条语句。

案例:本案例中,怎么做到重新执行 obj.init();就能到达重新渲染页面的效果。

        var obj = {list: [1, 2, 3, 4],init() {document.body.innerHTML = `<ul>${this.list.reduce((v, t) => v + `<li>${t}</li>`, "")}</ul>`}}obj.init();//怎么做到重新执行 obj.init();就能到达重新渲染页面的效果obj.list = ["a", "b", "c", "d"]obj.init();

解决方法:定义对象时,直接加入set和get方法。

  1. set 方法:有且仅有一个参数,并且不允许使用return返回任何值;当赋值时,执行set这个方法,参数就是赋值的结果,可以在赋值后执行多条语句;如果只写set 不写get,表示这个属性只能设置值,不能获取该属性,是只写属性
  2.  get 方法:不能有参数,并且必须return返回一个值;获取对象属性 时,执行get方法,获取最后要有一个获取的结果,所以需要return结果;如果只写get 不写set,表示这个属性只能获取值,不能设置改变值 ,是只读属性;这个get这个属性不能用来存储任何内容,需要借助第三方属性存储。

 案例1:

        // 定义对象时,直接加入set和getvar obj = {_list: 1,// set 方法 有且仅有一个参数,并且不允许使用return返回任何值// list 这个getset属性不能用来存储任何内容,需要借助第三方属性存储set list(value) {this._list = value;// console.log("set",value);},// get 方法 不能有参数,并且必须return返回一个值get list() {// console.log("get");// return ""return this._list;}}// 和属性的赋值方法完全相同// 当赋值时,执行set list这个方法,参数就是赋值的结果,可以在赋值后执行多条语句// 如果只写set 不写get,表示这个属性只能设置值,不能获取该属性  只写obj.list = "a";// 获取对象属性  执行get list方法,获取最后要有一个获取的结果,所以需要return结果// 如果只写get 不写set,表示这个属性只能获取值,不能设置改变值  只读console.log(obj.list);

案例2:

        var obj = {_list: [],// 重新给属性赋值时才会执行setset list(value) {if (!Array.isArray(value)) return;this._list = value;document.body.innerHTML = `<ul>${this.list.reduce((v, t) => v + `<li>${t}</li>`, "")}</ul>`},get list() {return this._list;}}obj.list = [1, 2, 3, 4]document.addEventListener("click", () => {obj.list = ["a", "b", "c", "d", "e"]// obj.list.push(5);obj.list = obj.list.concat(5);})

 案例3:div自动移动案例

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 50px;height: 50px;background-color: red;position: absolute;left: 0;top: 0;}</style>
</head><body><div></div><script type="module">var div = document.querySelector("div");var obj = {_x: 0,_y: 0,set x(value) {this._x = value;div.style.left = value + "px";},get x() {return this._x},set y(value) {this._y = value;div.style.top = value + "px";},get y() {return this._y;}}setInterval(() => {//               set   getobj.x++;//相当于obj.x=obj.x+1obj.y++;}, 16)</script>
</body></html>

案例4:div自动移动案例的升级版

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>div {width: 50px;height: 50px;background-color: red;position: absolute;left: 0;top: 0;}</style>
</head><body><div></div><script type="module">var div = document.querySelector("div");// 如果对象已经存在,如果要给对象中添加setget属性,就必须使用defineProperty或者definePropertiesHTMLElement.prototype.a = 10;console.log(div.a);Object.defineProperties(HTMLElement.prototype, {_x: {writable: true,//可修改,不可枚举,不可删除value: 0},_y: {writable: true,//可修改,不可枚举,不可删除value: 0},x: {set(value) {this._x = value;this.style.left = value + "px"},get() {return this._x;}},y: {set(value) {this._y = value;this.style.top = value + "px"},get() {return this._y;}}})setInterval(() => {div.x++;div.y++;}, 16)</script>
</body></html>

14. 对象深复制

14.1 对象浅复制的弊端

复制对象的目的,修改对象后,不会引起源对象的改变,保留源对象的内容。

  1. JSON.stringify(对象名) :将对象转换为JSON格式的字符串。格式  '{"属性名":属性值}'。 属性值如果是字符串需要使用""。
  2. JSON.parse():把JSON格式的字符串转换为对象,返回新对象;可以用于把字符串强转为布尔类型和数值类型。

案例:将下面对象的age属性进行随机修改,修改范围在25<x<35的范围内就停止修改。

        var data = {name: "xietian",age: 30,sex: "男"}

解决方法:下面的方法都是浅复制

        var data = {name: "xietian",age: 30,sex: "男"}while (1) {// 复制对象方法一:// var newData = {}// for (var key in data) {//     newData[key] = data[key]// }// 复制对象方法二:// var newData = Object.assign({}, data);// var newData = { ...data };// 复制对象方法三:var newData = Object.keys(data).reduce((v, k) => v[k] = data[k], {})newData.age = ~~(Math.random() * 100)if (newData.age < data.age + 5 && newData.age > data.age - 5) {break;}}console.log(newData);

浅复制只能复制一层,遇到对象中属性值还是对象的,改变复制新对象的属性,还是会改变源对象的属性值。属性值的引用地址没有变。例如:如下图所示:

        var data = {a: 1,b: {c: 2}}

 为了解决上述问题,使用要使用深复制。

14.2 对象深复制使用

14.2.1 方法一:使用lodash插件可以进行对象深复制

lodash插件的方法:

 _.cloneDeep(对象名) :深复制

1. 下载lodash插件,打开集成终端输入npm i lodash

2. 创建一个js的文件夹,在node_modules下把lodash.js放在js文件夹下,删除node_modules。

3. 在页面中引入lodash插件。

<script src="./js/lodash.js"></script>

4. 编写代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="./js/lodash.js"></script>
</head><body><script>var data = {a: 1,[Symbol("a")]: 2,c: /a/g,b: {c: 3,play() {console.log("aa");}}}//深复制方法一:// var newData = JSON.parse(JSON.stringify(data));// console.log(newData);//深复制方法二:var newData = _.cloneDeep(data);// 改变源对象的值,查看是否会改变新对象的值data.b.c = 30;console.log(newData, data);</script>
</body></html>

 lodash插件进行深复制也有弊端,有些数据还有引用关系。

14.2.2 方法二:封装对象深复制(重点)

遍历分为 广度遍历(  for ,for in ,for of)和 深度遍历( while ,递归)

1. 怎样做递归?递归的方式分两种。

  • 方法一:先做深度遍历,在做广度遍历。
  • 方法二:先做广度遍历,在做深度遍历。

案例1:二叉树的遍历

    var tree = {value: 1,left: {value: 2,left: {value: 4,left: null,right: null},right: {value: 5,left: null,right: null},},right: {value: 3,left: {value: 6,left: null,right: null},right: {value: 7,left: null,right: null},},};// 先序遍历// function showTree(tree) {//   console.log(tree.value);//   if (tree.left) showTree(tree.left)//   if (tree.right) showTree(tree.right)// }// 中序遍历// function showTree(tree) {//   if (tree.left) showTree(tree.left)//   console.log(tree.value);//   if (tree.right) showTree(tree.right)// }// 后序遍历function showTree(tree) {if (tree.left) showTree(tree.left)if (tree.right) showTree(tree.right)console.log(tree.value);}showTree(tree);

案例2:

    var obj = {a: 1,b: {c: [1, 2, 3, 4],d: {e: 3,},},f: {g: {h: 4,},},};//方法一:先做深度遍历,在做广度遍历。// function showDeep(obj) {//   for (var key in obj) {//     // 是对象,但不是null//     if (obj[key] && typeof obj[key] === "object") {//       showDeep(obj[key])//     } else {//       console.log(obj[key]);//     }//   }// }// 方法二:先做广度遍历,在做深度遍历。function showDeep(obj) {if (typeof obj !== "object" || !obj) {console.log(obj);}for (var key in obj) {showDeep(obj[key])}}showDeep(obj);

 案例3:尾递归 ,在尾部递归。

    // 递归  尾递归  在尾部递归var i = 0;var sum = 0;function getSum() {i++;if (i > 100) return;sum += i;getSum();}getSum();console.log(sum);

案例4:

 


http://www.mrgr.cn/news/29518.html

相关文章:

  • ssm103宠物领养系统+vue(论文+源码)_kaic
  • SpringBoot单体服务无感更新启动,动态检测端口号并动态更新
  • hive的tblproperties支持修改的属性
  • SQL50题
  • C#实现在windows上实现指定句柄窗口的指定窗口坐标点击鼠标左键和右键的详细情况
  • 数字字符串格式化
  • 如何编写可维护的代码:最佳实践与技巧
  • 克隆centos网卡uuid相同如何修改
  • 进程的重要函数
  • 基于树表的查找
  • 网络封装分用
  • OpenHarmony(鸿蒙南向开发)——标准系统方案之瑞芯微RK3568移植案例(下)
  • 伪工厂模式制造敌人
  • 喜报!亲笔签数字科技荣获2024年“数据要素X”大赛重庆分赛三等奖
  • 构建 LLM 应用程序时经常遇到的高级概念的快速指南
  • 3.postman脚本语言、接口关联(json引用(变量)、脚本用正则表达式)、断言封装、自动化构造接口请求(Postman工具)
  • 直播开播极速流,如何有效接入?
  • 基于Spring Boot的学生社区故障维修预约系统的设计与实现(开题报告)
  • C++面试模拟01
  • C++:日期类的实现
  • YOLOv8改进:SA注意力机制【注意力系列篇】(附详细的修改步骤,以及代码,与其他一些注意力机制相比,不仅准确度更高,而且模型更加轻量化。)
  • 隐藏excel单元格数据的两个方法
  • 【d2l安装超详细老妈子教程】
  • 史上最强异步编程~CompletableFuture精读
  • hym8563/pcf8563 定时关机后,中断没有清除,导致INT脚一直为低,系统不开机。
  • GEE教程:1950-2023年ECMWF数据中积雪的长时序统计分析