主页

构造函数和原型

构造函数

构造函数是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 一起使用;可以把对象中的一些公共属性和方法抽取出来,然后封装到这个函数里面

1)构造函数用于创建某一类对象,其首字母要大写
2)构造函数要和 new 一起使用才有意义

new 再执行时会做四件事情:
①再内存中创建一个新的空对象
②让 this 指向这个空对象
③执行构造函数里面的代码,给这个新对象添加属性和方法
④返回这个新对象(所以构造函数里面不需要 return


构造函数中的属性和方法我们称为成员,成员可以添加

实例成员就是构造函数内部通过 this 添加的成员
实例成员只能通过实例化的对象来访问,不可以通过构造函数来访问实例成员
静态成员是指在构造函数本身上添加的成员

构造函数的问题

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


我们希望所有的的对象使用同一个函数,这样就比较节省内存

构造函数原型 prototype

构造函数通过原型分配的函数是所有对象所共享的

JS规定,每一个构造函数都有一个 prototype 属性,指向另一个对象;这个 `prototype` 就是一个对象,这个对象的使用属性和方法,都会被构造函数所拥有

我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法
    构造函数名.prototype.方法名 = function() {
        
    }
    
    Star.prototype.sing = function() {
        console.log('我会唱歌')
    }


原型是一个对象, prototype 也称为原型对象
原型的作用是共享方法

对象原型 __proto__

对象都有有一个属性 __proto__ 指向构造函数的 prototype 原型对象,之所以对象可以使用构造函数 prototype 原型对象的属性和方法,就是因为对象有 __proto__ 原型的存在

  • __peoto__ 对象原型和原型对象 prototype 是等价的
  • __peoto__ 对象原型的意义就在于为对象的查找机制提供了一个方向,或者说一条线路,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

constructor 构造函数

对象原型(__proto__原型对象(prototype里面都有一个 constructor 属性,constructor 称为构造函数,因为它指回构造函数本身

coustructor 主要用于记录该对象引用于那个构造函数,它可以让原型对象 prototype 重新指向原来的构造函数
        function Star(uname, age) {
            this.uname = uname;
            this.age = age;
        }
        // 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
        // Star.prototype.sing = function() {
        //     console.log('我会唱歌');
        // };
        // Star.prototype.movie = function() {
        //     console.log('我会演电影');
        // }
        Star.prototype = {
            // 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
            constructor: Star,
            sing: function() {
                console.log('我会唱歌');
            },
            movie: function() {
                console.log('我会演电影');
            }
        }
        var ldh = new Star('刘德华', 18);
        var zxy = new Star('张学友', 19);
        console.log(Star.prototype);
        console.log(ldh.__proto__);
        console.log(Star.prototype.constructor);
        console.log(ldh.__proto__.constructor);

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


原型链

JS的成员查找机制(规则)

  1. 当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性
  2. 如果没有就直接查找它的原型(也就是 __proto__ 指向的 prototype 原型对象
  3. 如果还没有就查找原型对象的原型(Object 的原型对象
  4. 以此类推一直找到 Object 为止(null
  5. __proto__ 对象原型的意义就在于为对象成员查找机制提供一个方向,或者说一条线路

继承

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

call()

调用这个函数,并且返回修改函数运行时的this指向

    fn.call(thisArg, arg1, arg2, ...)
  • thisArg:当前调用函数 this 的指向对象
  • arg1, arg2:传递的其他参数

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

通过 call() 把父类型的 this 指向子类型的 this ,这样就可以实现子类型继承父类型的属性
// 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        var son = new Son('刘德华', 18, 100);

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

        // 借用父构造函数继承属性
        // 1. 父构造函数
        function Father(uname, age) {
            // this 指向父构造函数的对象实例
            this.uname = uname;
            this.age = age;
        }
        Father.prototype.money = function() {
            console.log(100000);

        };
        // 2 .子构造函数 
        function Son(uname, age, score) {
            // this 指向子构造函数的对象实例
            Father.call(this, uname, age);
            this.score = score;
        }
        // Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
        Son.prototype = new Father();
        // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
        Son.prototype.constructor = Son;
        // 这个是子构造函数专门的方法
        Son.prototype.exam = function() {
            console.log('孩子要考试');

        }
        var son = new Son('刘德华', 18, 100);
        console.log(son);
        console.log(Father.prototype);
        console.log(Son.prototype.constructor);

ES5 新增方法

数组方法

迭代(遍历)方法:forEach()map()filter()some()every()

forEach()

    array.forEach(function(currentValue, index, arr) {
    
    })
  • currenValue:数组当前项的值
  • index:数组当前项的索引
  • arr:数组对象本身

filter() 筛选数组

    array.filter(function(currentValue, index, arr) {
    
    })
    let arr = [1, 2, 3, 4, 5]
    let newArr = arr.filter(function(value, index, arr) {
        return value >= 3  // 返回arr中大于等于三的给新数组newArr
        return value % 2 === 0  // 返回arr中是偶数的给新数组newArr
    })
  • filter():方法创建一个新的数组,新数组中的元素是通过检查指定数组中字符条件的所有元素,主要用于筛选数组
  • 它直接返回一个新数组
  • currenValue:数组当前项的值
  • index:数组当前项的索引
  • arr:数组对象本身

some()

    array.some(function(currentValue, index, arr) {
    
    })
    let arr = [1, 2, 3, 4, 5, 'red']
    let flag = arr.some(function(value, index, arr) {
        return value >= 3  // 如果数组中有大于大于3的元素就返回true,否则返回false
        return value === 'red'  // 如果数组中有'red'元素就返回true,否则返回false
    })
  • some():方法用于检测数组中元素的元素是否满足指定条件,通俗点:查找数组中是否满足条件的元素
  • 他返回的是布尔值,如果查找到这个元素,就返回true,否则返回false
  • 如果找到第一个满足条件的元素,则终止循环,不再继续查找
  • currenValue:数组当前项的值
  • index:数组当前项的索引
  • arr:数组对象本身
filter() 是查找满足条件的元素,返回一个新数组,是把所有满足条件的元素都返回回来
some() 是查找满足条件的元素是否存在,返回的是一个布尔值,如果查找到一个满足条件的元素就停止循环

every()

判断数组里面的每一项是否满足判断条件,如果每一项都满足就返回 true,如果有一项不满足就返回 false

const arr = [
    { id: 1, name: '西瓜', state: true },
    { id: 2, name: '榴莲', state: true },
    { id: 3, name: '草莓', state: true },
]
// 需求:判断数组中,水果是否被全选了
const result = arr.every(item => item.state)
console.log(result) // true

reduce()

reduce() 循环,就是一个累加器,是把每一次循环的结果累加起来 reduce((累加的结果, 当前的循环项) => { }, 初始值)

const arr = [
    { id: 1, name: '西瓜', state: true, price: 10, count: 2 },
    { id: 2, name: '榴莲', state: false, price: 80, count: 1 },
    { id: 3, name: '草莓', state: true, price: 20, count: 3 },
]
// 需求:把购物车数组中,已勾选的水果,总价累加起来
// reduce((累加的结果, 当前的循环项) => { }, 初始值)
const result = arr.filter(item => item.state).reduce((amt, item) => amt += item.price * item.count, 0)
console.log(result) // 80

/* const result = arr.filter(item => item.state).reduce((amt, item) => {
    return amt += item.price * item.count
}, 0) */


/* let amt = 0 //总价
arr.filter(item => item.state).forEach(item => {
    return amt += item.price * item.count
})
console.log(amt) // 80 */

字符串方法

trim() 方法会从一个字符串的两端删除空白字符

    str.trim()
    str1 = str.trim() //  trim() 方法并不影响原字符串本身,他返回的是一个新的字符串

对象方法

Object.defineProperty() 定义对象中新属性或修改原有的属性

    Object.defineProperty(obj, prop, descriptor)
    
    let obj = {
        id: 1,
        pname: '',
        price: 1999
    }
    // 以前的对象添加和修改属性的方式
    obj.num = 1000
    obj.price = 99
    
    Object.defineProperty() 定义对象中新属性或修改原有的属性
    Object.defineProperty(obj, 'num', {
        value: 1000
    })
    Object.defineProperty(obj, 'price', {
        value: 9.9
    })
    Object.defineProperty(obj, 'id', {
        writable: true //如果为false就是不允许修改这个属性值,默认是false
        enumerable: true //如果为false就是不允许遍历,默认是false
        configurable: true //如果为false就是不允许删除这个属性,默认是false
    })
  • obj:必须,目标对象
  • prop:必须,需要定义或修改的属性名字
  • descriptor:必须,目标属性所拥有的特性

Object.defineProperty() 第三个参数descriptor说明:以对象形式{ }书写

  1. value:设置属性的值;默认为undefined
  2. writable:值是否可以重写;true | false 默认为false不可被更改
  3. enumerable:目标属性是否可以被枚举(被遍历);true | false 默认为false不可被枚举(被遍历)
  4. configurable:目标属性是否可以被删除或者是否可以再次修改特性 true | false 默认为false不可被删除

Object.keys() 用于获取对象自身所有的属性

    Object.keys(obj)
  • 效果类似for...in
  • 返回一个由属性名组成的数组

ES6

版权属于:Joe
作品采用:本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。
0

目录

来自 《JS-构造函数和原型》
评论

qiaofugui

博主很懒,啥都没有
188 文章数
14 评论量
3 分类数
191 页面数
已在风雨中度过 2年133天2小时20分