第一章:构造函数和原型

1.1 概述

  • 在典型的OOP的语言中(如Java),都存在类的概念,类就是对象的模板,对象就是类的实例,但是在ES6之前,JS并没有引入类的概念。
  • ES6,全称ECMAScript 6.0,2015.06发版。但是目前浏览器的JavaScript是ES5版本,大多数高版本的浏览器也支持ES6,不过只实现了ES6的部分特性和功能。
  • 在ES6之前,对象不是基于类创建的,而是用一种称为构造函数的特殊函数来定义对象和他们的特征。
  • 创建对象的三种方式:

    • 对象字面量。
    • new Object()。
    • 自定义构造函数。
  • 示例:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport"
  6. content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
  7. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  8. <title>利用构造函数创建对象</title>
  9. <script>
  10. /* 利用new Object()创建对象 */
  11. var obj1 = new Object();
  12. obj1.name = '刘德华';
  13. obj1.age = 55;
  14. console.log(obj1.name);
  15. console.log(obj1.age);
  16. /* 利用字面量创建对象 */
  17. var obj2 = {
  18. name: '刘德华',
  19. age: 55,
  20. show: function () {
  21. console.log(this.name + ':' + this.age);
  22. }
  23. }
  24. obj2.show();
  25. /* 利用构造函数创建对象 */
  26. function Person(name, age) {
  27. this.name = name;
  28. this.age = age;
  29. this.show = function () {
  30. console.log(this.name + '~:~' + this.age);
  31. }
  32. }
  33. var person = new Person('刘德华', 55);
  34. person.show();
  35. </script>
  36. </head>
  37. <body>
  38. </body>
  39. </html>

1.2 构造函数

  • 构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总和new一起使用。我们可以将对象中的一些公共的属性和方法抽取出来,然后封装到这个函数里面。
  • 在JS中,使用构造函数的时候需要注意以下两点:
    • 构造函数用于创建某一类的对象,其首字母要大写
    • 构造函数要和new一起使用才有意义。
  • new在执行的时候会做四件事情:
    • 在内存中创建一个新的空对象。
    • 让this指向这个新的对象。
    • 执行构造函数里面的代码,给这个新对象添加属性和方法。
    • 返回这个新对象(构造函数里面不需要return)。

1.3 静态成员和实例成员

  • JavaScript的构造函数中可以添加一些成员,可以在构造函数本身上添加,也可以在构造函数内部的this上添加。通过这两种方式添加的成员,就分别称为静态成员实例成员
  • 静态成员:在构造函数本身上添加的成员称为静态成员,只能由构造函数本身来访问
  • 实例成员:在构造函数内部创建的对象成员称为实例成员,只能由实例化的对象来访问

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>静态成员和实例成员</title>
    <script>
        //构造函数中的水性和方法我们称为成员,成员可以添加
        function Person(uname, age) {
            this.uname = uname;
            this.age = age;
            this.sing = function () {
                console.log('我会唱歌')
            }
        }

        var ldh = new Person('刘德华', 55);
        //实例成员就是构造函数内部通过this添加的成员 uname age sing就是实例成员
        //实例成员只能通过实例化的对象来访问
        console.log(ldh.uname);
        console.log(ldh.age);
        ldh.sing();
        // console.log(Person.uname); 不可以通过构造函数来访问实例成员
        //静态成员,在构造函数本身上添加的成员 sex 就是静态成员
        Person.sex = '男';
        console.log(Person.sex)
        // console.log(ldh.sex) 静态成员只能通过构造函数访问
    </script>
</head>

<body>

</body>

</html>

1.4 构造函数的问题

  • 构造函数方法很好用,但是存在浪费内存的问题

构造函数的问题.jpg

学过Java的一定要注意,这边不一样!!!

  • 我们希望所有对象使用同一个函数,这样就比较节省内存,那么我们要怎么做?

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>构造函数的问题</title>
    <script>
        function Person(uname, age) {
            this.uname = uname;
            this.age = age;
            this.sing = function () {
                console.log('我会唱歌')
            }
        }

        var ldh = new Person('刘德华', 55);
        var zxy = new Person('张学友', 50);

        console.log(ldh.sing == zxy.sing); //false
    </script>
</head>

<body>

</body>

</html>

1.5 构造函数原型prototype

  • 构造函数通过原型分配的函数是所有对象所共享的。
  • JavaScript中规定,每一个构造函数都有一个prototype属性,指向另一个对象。注意,这个prototype就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
  • 我们可以将一些不变的方法,直接定义在prototype对象上,这样所有对象的实例就可以共享这些方法

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>原型对象</title>
    <script>
        function Person(uname, age) {
            this.uname = uname;
            this.age = age;
        }

        Person.prototype.sing = function () {
            console.log('我会唱歌');
        }

        var ldh = new Person('刘德华', 55);
        var zxy = new Person('张学友', 50);

        ldh.sing();
        zxy.sing();

        console.log(ldh.sing == zxy.sing); //true

        //一般情况下,我们的公共属性定义到构造函数里面,公共的方法放到原型对象上面。
    </script>
</head>

<body>

</body>

</html>

1.6 对象原型__proto__

  • 对象都会有一个属性__proto__,这个属性指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型存在。
    • __proto__对象原型和原型对象prototype是等价的。
    • __proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此在实际开发中,不可以使用这个属性,它只是内部指向原型对象prototype。

1.7 constructor构造函数

  • 对象原型(__proto__)原型对象(prototype)里面都有一个属性constructor属性,constructor我们称之为构造函数,因为它指向构造函数本身。
  • constructor主要用于记录该对象引用于那个构造函数,它可以让原型对象重新指向原来的构造函数。
  • 一般情况下,对象的方法都是在构造函数的原型对象中设置的。但是如果对象有多个方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象constructor就不再指向当前的构造函数了,此时,我们可以在修改后的原型对象中,添加一个constructor指向原来的构造函数。

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>constructor构造函数</title>
    <script>
        function Person(uname, age) {
            this.uname = uname;
            this.age = age;
        }

        //很多情况下,我们需要手动的利用constructor这个属性指回原来的构造函数。
        /*Person.prototype.sing = function () {
            console.log('我会唱歌');
        }
        Person.prototype.movie = function () {
            console.log('我会演电影');
        }*/
        Person.prototype = {
            /* 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数 */
            constructor: Person,
            sing: function () {
                console.log('我会唱歌');
            },
            movie: function () {
                console.log('我会唱歌');
            }
        }
        var ldh = new Person('刘德华', 55);
        var zxy = new Person('张学友', 50);

        ldh.sing();
        zxy.sing();

        console.log(Person.prototype.constructor);
        console.log(ldh.__proto__.constructor);


    </script>
</head>

<body>

</body>

</html>

1.8 构造函数、实例、原型对象三者之间的关系

构造函数、实例、原型对象三者之间的关系.jpg

1.9 原型链

原型链.jpg

  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>原型链</title>
    <script>
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }

        Star.prototype.sing = function () {
            console.log('我会唱歌');
        }
        var ldh = new Star('刘德华', 55);

        // 只要是对象就有__proto__原型属性,指向原型对象
        console.log(ldh.__proto__);
        console.log(Star.prototype.__proto__ == Object.prototype); // true
        // Star原型对象里面的__proto__指的是Object里面的prototype
        console.log(Object.prototype.__proto__);//null
    </script>
</head>

<body>

</body>

</html>

1.10 Javascript的成员查找机制(规则)

  • ①当访问一个对象的属性(包括方法)的时候,首先查找这个对象本身有没有该属性。
  • ②如果没有就查找它的原型(也就是__proto__指向的prototype原型对象)。
  • ③如果还没有,就查找原型对象的原型(Object的原型对象)。
  • ④依次类推,一直找到Object为止(如果还没有,就返回null)。
  • __proto__对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条路线。

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>原型链成员查找规则</title>
    <script>
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }

        Star.prototype.sing = function () {
            console.log('我会唱歌');
        }
        //还找不到返回null

        //最后找这个
        // Object.prototype.sex = '男';

        //再找这个
        // Star.prototype.sex = '女';

        var ldh = new Star('刘德华', 55);
        //先找下面的
        // ldh.sex = '男';
        console.log(ldh.sex);
    </script>
</head>

<body>

</body>

</html>

1.11 原型对象this指向

  • 构造函数中的this指向的是实例对象。
  • 原型对象里面放的是方法,这个方法里面的this指向的是这个方法的调用者,也就是这个实例对象

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>原型对象this指向</title>
    <script>
        function Star(uname, age) {
            console.dir(this);
            this.uname = uname;
            this.age = age;
        }

        var that;
        Star.prototype.sing = function () {
            that = this;
            console.dir(this);
            console.log('我会唱歌');
        }

        // 在构造函数中,里面的this指向的是对象实例ldh。
        var ldh = new Star('刘德华', 55);

        ldh.sing();

        // 原型对象函数里面的this,指的是对象实例ldh。
        console.log(that == ldh); //true

    </script>
</head>

<body>

</body>

</html>

1.12 扩展内置对象

  • 可以通过原型对象,对原来的内置对象进行扩展自定义的方法,比如给数组增加自定义求偶数和的功能。

注意:数组和字符串内置对象不能给原型对象覆盖操作 Array.prototype = {} ,只能是 Array.prototype.xxx = function(){} 的方式。

  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>扩展内置对象方法</title>
    <script>
        Array.prototype.evenSum = function () {
            var sum = 0;
            for (var i = 0; i <= this.length; i++) {
                if (this[i] % 2 == 0) {
                    sum += this[i];
                }
            }
            return sum;
        }

        var arr = [1, 2, 3, 4, 5];
        var evenSum = arr.evenSum();
        console.log(evenSum);

    </script>
</head>

<body>

</body>

</html>

第二章:继承

2.1 概述

  • ES6之前并没有给我们提供extends继承。我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承

2.2 call()

  • 语法:
/*
    thisArg:当前调用函数this的指向对象
    arg1,arg2:传递的其他参数
*/
fun.call(thisArg,arg1,arg2,...)
  • 调用这个函数,并且修改函数运行时的this的指向。

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>call方法</title>
    <script>
        function fn(x, y) {
            console.log('我想喝手磨咖啡...');
            console.log(this);
            console.log(x);
            console.log(y);
        }

        var o = {
            name: 'tom'
        };
        // fn();
        // 1. call()方法:可以调用函数
        // fn.call(); 原来的this指向的是window
        // 2. call()方法可以改变函数的this指向
        fn.call(o, 1, 2); // 此时这个函数的this,就指向了o这个对象
    </script>
</head>

<body>

</body>

</html>

2.2 借用构造函数继承父类型属性

  • 核心原理:通过call()将父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>借用构造函数继承父类型属性</title>
    <script>
        /* 核心原理:通过call()将父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。 */
        function Father(uname, age) {
            //this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }

        function Son(uname, age) {
            //this 指向子构造函数的对象实例
            Father.call(this, uname, age);
        }

        var son = new Son('刘德华',50);
        console.log(son);
    </script>
</head>

<body>

</body>

</html>

2.3 借用原型对象继承父类型方法

  • 一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法
  • 核心原理:

    • 将子类所共享的方法提出出来,让子类的prototype 原型对象 = new 父类()
    • 本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象。
    • 将子类的constructor重新指向子类的构造函数。
  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>借用原型对象继承父类型方法</title>
    <script>
        /* 核心原理:通过call()将父类型的this指向子类型的this,这样就可以实现子类型继承父类型的属性。 */
        function Father(uname, age) {
            //this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }

        Father.prototype.money = function () {
            console.log('赚钱');
        }

        function Son(uname, age) {
            //this 指向子构造函数的对象实例
            Father.call(this, uname, age);
        }

        // Son.prototype = Father.prototype; 这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会随之发生改变。
        Son.prototype = new Father();
        Son.prototype.constructor = Son;

        Son.prototype.exam = function () {
            console.log('儿子要考试')
        }

        var son = new Son('刘德华', 50);
        console.log(son);
    </script>
</head>

<body>

</body>

</html>

第三章:ES5中的新增方法

3.1 概述

  • ES5给我们新增了一些方法,可以很方便的操作数组或者字符串,这些方法主要包括:
    • ①数组方法。
    • ②字符串方法。
    • ③对象方法。

3.2 数组方法

  • forEach()方法:
/*
  currentValue:数组当前项的值
  index:数组当前项的索引
  arr:数组对象本身
*/
array.forEach(function(currentValue,index,arr));
  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>forEach方法</title>
    <script>
        var arr = [1, 2, 3, 4, 5];
        // currentValue 数组当前项的值
        // index 数组当前项的索引
        // arr 数组本身
        arr.forEach(function (currentValue, index, arr) {
            console.log('每个数组元素:' + currentValue);
            console.log('每个数组元素的索引号:' + index);
            console.log('数组本身:' + arr);
        })
    </script>
</head>

<body>

</body>

</html>
  • filter()方法:创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用来筛选数组
/*
  currentValue:数组当前项的值
  index:数组当前项的索引
  arr:数组对象本身
*/
array.filter(function(currentValue,index,arr));
  • 返回的是一个新的数组。
  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>filter方法</title>
    <script>
        /* 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用来筛选数组,返回的是一个新的数组。 */
        var arr = [1, 2, 3, 4, 5];

        var newArr = arr.filter(function (value, index, arr) {
            return value >= 2;
        });

        console.log(newArr);

    </script>
</head>

<body>

</body>

</html>
  • some()方法:用于检测数组中的元素是否满足指定条件,通俗点的讲查找数组中是否有满足条件的元素。
array.some(function(currentValue, index, arr))
  • 注意它返回值是布尔值, 如果查找到这个元素, 就返回true , 如果查找不到就返回false。
  • 如果找到第一个满足条件的元素,则终止循环. 不在继续查找。
  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>some方法</title>
    <script>
        /* 用于检测数组中的元素是否满足指定条件,通俗点的讲查找数组中是否有满足条件的元素。 */
        var arr = [1, 2, 3, 4, 5];
        var bool = arr.some(function (value, index, array) {
            return value == 5;
        });
        console.log(bool); //true
    </script>
</head>

<body>

</body>

</html>
  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>查询商品案例</title>
    <style>
        .box {
            width: 1000px;
            height: 500px;
            margin: 100px auto;
        }

        .box div {
            width: 100%;
        }

        .box table {
            width: 500px;
            margin: 0 auto;
            margin-top: 20px;
            border-collapse: collapse;
        }

        .box table th, td {
            text-align: center;
            border: 1px solid #000;
        }
    </style>

</head>

<body>
    <!--
        1.把数据渲染到页面中。
        2.根据价格显示数据。
        3.根据商品名称显示数据。
    -->
    <div class="box">
        <div>
            按照价格查询:
            <input type="text" class="from"> - <input type="text" class="to">
            <button class="search">搜索</button>
            按照商品价格查询:
            <input type="text" class="price">
            <button class="query">查询</button>
        </div>
        <table>
            <thead>
                <tr>
                    <th>id</th>
                    <th>产品名称</th>
                    <th>价格</th>
                </tr>
            </thead>
            <tbody>
                <!--<tr>
                    <td>1</td>
                    <td>小米</td>
                    <td>3999</td>
                </tr>-->
            </tbody>
        </table>
    </div>


    <script>
        var goods = [{
            id: 1,
            name: '小米',
            price: 3999
        }, {
            id: 2,
            name: 'oppo',
            price: 999
        }, {
            id: 3,
            name: '荣耀',
            price: 1299
        }, {
            id: 4,
            name: '华为',
            price: 1999
        }];
        var tbody = document.querySelector('tbody');

        function render(goods, tbody) {
            tbody.innerHTML = '';
            goods.forEach(function (value) {
                var tr = ' <tr>\n' +
                    '         <td>' + value.id + '</td>\n' +
                    '         <td>' + value.name + '</td>\n' +
                    '         <td>' + value.price + '</td>\n' +
                    '       </tr>'
                tbody.insertAdjacentHTML('beforeend', tr);
            })
        }

        //初始化的时候渲染数据
        render(goods, tbody);

        var from = document.querySelector('.from');
        var to = document.querySelector('.to');
        var search = document.querySelector('.search');
        search.onclick = function () {
            if (from.value && to.value) {
                var newGoods = goods.filter(function (value) {
                    return value.price >= from.value && value.price <= to.value;
                })
                render(newGoods, tbody);
            } else {
                render(goods, tbody);
            }
        }

        var query = document.querySelector('.query');
        var price = document.querySelector('.price');
        query.onclick = function () {
            if (price.value) {
                var newGoods = goods.filter(function (value) {
                    return value.price == price.value;
                })
                render(newGoods, tbody);
            } else {
                render(goods, tbody);
            }
        }

    </script>
</body>

</html>

3.3 字符串方法

  • trim()方法:会将一个字符串的两端删除空白字符。
str.trim();

trim()方法并不会影响原字符串本身,它返回的是一个新的字符串。

  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>trim方法</title>
    <script>
        var str = ' 我爱你啊 ';
        console.log(str.trim());
    </script>
</head>

<body>

</body>

</html>

3.4 对象方法

  • Object.keys()方法:返回对象自身所有的属性。
Object.keys()
  • 效果类似于for…in。
  • 返回一个由属性名组成的数组。

  • 示例:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Object.keys()</title>
    <script>
        var stu = {
            name: '许大仙',
            age: 18
        }
        // 返回对象自身所有的属性
        // 返回一个由属性名组成的数组
        var arr = Object.keys(stu);
        arr.forEach(function (value) {
            console.log(value);
        })
        //name
        //age
    </script>
</head>

<body>

</body>

</html>
  • Object.defineProperty()方法:定义新属性或修改原有的属性。
//obj:目标对象,必须。
//prop:定义或修改属性的名字,必须。
//descriptor:必须,目前属性所拥有的特性
Object.defineProperty(obj, prop, descriptor)

descriptor,以对象形式{}书写。

  • value: 设置属性的值,默认为undefined。
  • writable: 值是否可以重写。true | false, 默认为false。
  • enumerable: 目标属性是否可以被枚举。true | false,默认为false。
  • configurable: 目标属性是否可以被删除或是否可以再次修改特性,true | false,默认为false。
  • 示例:
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Object.defineProperty方法</title>
    <script>
        /* 原来新增或修改对象的属性 */
        var obj = {
            id: 1,
            name: '小米',
            price: 1999
        }
        obj.num = 1000;

        console.log(obj.num);
        /* Object.defineProperty():定义新属性或修改原有属性 */
        var obj2 = {
            id: 1,
            name: '小米',
            price: 1999
        }
        /* 如果有属性,则覆盖属性值;如果没有该属性,则新增该属性。 */
        Object.defineProperty(obj2, 'num', {
            value: 1000
        });
        Object.defineProperty(obj2, 'price', {
            value: 9.9
        });
        Object.defineProperty(obj2, 'id', {
            //false表示不允许重写,不允许修改属性值。
            writable: false
        });
        Object.defineProperty(obj2, 'address', {
            value: '中国山东蓝翔技校xxx单元',
            /* 目标属性是否可以被枚举 */
            enumerable: false
        });
        console.log(Object.keys(obj2));;
        console.log(obj2);

    </script>
</head>

<body>

</body>

</html>