J S 高级知识汇总——构造函数

一、构造函数

1.1 概述

1.2 对象的三种创建方式(复习)

  1. 字面量方式

    var obj = {};

  2. new关键字

    var obj = new Object();

  3. 构造函数方式

    function Person(name,age){
      this.name = name;
      this.age = age;
    }
    var obj = new Person('zs',12);

1.3 构造函数

 

// 3. 利用构造函数创建对象
function Star(uname, age) {
    this.uname = uname;
    this.age = age;
    this.sing = function() {
        console.log('我会唱歌');
​
    }
}
​
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
console.log(ldh);
ldh.sing();
zxy.sing();

1.4 静态成员和实例成员

成员:属性和方法。

实例成员

实例成员就是构造函数内部通过this添加的成员,

如下列代码中:uname age sing 就是实例成员,

实例成员只能通过实例化的对象来访问

 // 构造函数中的属性和方法我们称为成员, 成员可以添加
function Star(uname, age) {
     this.uname = uname;
     this.age = age;
     this.sing = function() {
     console.log('我会唱歌');
    }
}
var ldh = new Star('刘德华', 18);
console.log(ldh.uname);//实例成员只能通过实例化的对象来访问

静态成员

构造函数本身也是1个对象!

静态成员:在构造函数本身上添加的成员。

如下列代码中 sex 就是静态成员,静态成员

只能通过构造函数来访问

function Star(uname, age) {
     this.uname = uname;
     this.age = age;
     this.sing = function() {
     console.log('我会唱歌');
    }
}
// 静态成员 在构造函数本身上添加的成员  sex 就是静态成员
Star.sex = '男';
var ldh = new Star('刘德华', 18);
console.log(Star.sex);//静态成员只能通过构造函数来访问

二、原型对象

2.1 构造函数的问题

构造函数创建对象很好用,但是如果把方法定义在构造函数内,就存在浪费内存的问题。

我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上。

2.2 构造函数的原型prototype

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

JavaScript 规定,每一个构造函数都有一个prototype 属性,指向另一个对象,这个对象叫做【原型对象】。

我们可以把那些不变的方法,直接定义在 prototype 对象上,这样所有对象的实例就可以共享这些方法。

function Star(uname, age) {
    // 构造函数中定义属性
    this.uname = uname;
    this.age = age;
}
// 把方法定义到原型对象身上
Star.prototype.sing = function() {
    console.log('我会唱歌');
}
var ldh = new Star('刘德华', 18);
var zxy = new Star('张学友', 19);
​
ldh.sing();
zxy.sing();
​
// 所有的实例对象,共用一个方法,省内存
console.log(ldh.sing === zxy.sing);

2.3 对象原型

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

 

2.4 constructor构造函数

 

如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数如:

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

2.5 三角关系

构造函数、实例对象和原型对象的三角关系。

1.构造函数的prototype属性指向了构造函数原型对象
2.实例对象是由构造函数创建的,实例对象的__proto__属性指向了构造函数的原型对象
3.构造函数的原型对象的constructor属性指向了构造函数,实例对象的原型的constructor属性也指向了构造函数

四、原型链与对象成员的查找规则

4.1 原型链

<!--任何原型对象也是一个对象,该对象就有 __proto__ 属性,这样一层一层往上找,就形成了一条链,我们称此为原型链;-->

4.2 对象成员的查找机制

当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。
​
如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。
​
如果还没有就查找:原型对象的原型(Object的原型对象)。
​
依此类推一直找到 Object 为止(null)。

沿着原型链查找!!

五、原型对象的应用

5.1 原型对象函数中this指向

不管构造函数中的this,还是原型对象中的this,都指向我们new出来的实例对象。

<script>
    function Star(uname, age) {
        this.uname = uname;
        this.age = age;
    }
    var that;
    Star.prototype.sing = function() {
        console.log('我会唱歌');
        that = this;
    }
    var ldh = new Star('刘德华', 18);
    // 1. 在构造函数中,里面this指向的是对象实例 ldh
    ldh.sing();
    console.log(that === ldh);
​
    // 2.原型对象函数里面的this 指向的是 实例对象 ldh
</script>

5.2 通过原型为数组扩展内置方法

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

// 系统中内置了很多构造函数:例如:Object、Array
// Array构造函数也有一个对应的原型对象
Array.prototype.sum = function() {
    var sum = 0;
    for (var i = 0; i < this.length; i++) {
        sum += this[i];
    }
    return sum;
};
// 数组的实例对象 arr
var arr = [1, 2, 3];
// 调用sum方法(成员的查找规则)
console.log(arr.sum());
console.log(Array.prototype);
​
// 数组的实例对象 arr1
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());

六、继承

子构造函数 继承 父构造函数!

6.1 call()方法

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

  • call()可以调用函数

  • call()可以修改this的指向,使用call()的时候 参数1是修改后的this指向,参数2,参数3。。。是函数的实参列表。

function fn(x, y) {
     console.log('我想喝手磨咖啡');
     console.log(this);
     console.log(x + y);
}
  var o = {
    name: 'andy'
  };
  // fn();
  // 1. call() 可以调用函数
  // fn.call();
  // 2. call() 可以改变这个函数的this指向 此时这个函数的this 就指向了o这个对象
  fn.call(o, 1, 2);

6.2 继承属性

  1. 先定义一个父构造函数

  2. 再定义一个子构造函数

  3. 子构造函数继承父构造函数的属性(使用call方法)

// 1. 父构造函数
 function Father(uname, age) {
   // this 指向父构造函数的对象实例
   this.uname = uname;
   this.age = age;
 }
  // 2 .子构造函数 
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例 ldh
  // 3.使用call方式实现子继承父的属性【调用父构造函数,并让其this变为ldh】
  Father.call(this, uname, age);
  this.score = score;
}
var ldh = new Son('刘德华', 18, 100);
console.log(son);

6.3 继承方法

借用原型对象继承方法!

  1. 先定义一个父构造函数

  2. 再定义一个子构造函数

  3. 修改子构造函数的原型对象(new 父构造函数得到的对象)

// 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);

七、类的本质

 

 

<script>
    // ES6 之前通过 构造函数 + 原型 实现面向对象编程
    // (1)构造函数有原型对象prototype
    // (2)构造函数原型对象prototype里面有constructor 指向构造函数本身
    // (3)构造函数可以通过原型对象添加方法
    // (4)构造函数创建的实例对象有__proto__原型指向 构造函数的原型对象
​
    // ES6 通过 类 实现面向对象编程
    class Star {
​
    }
    console.log(typeof Star);
    // 1. 类的本质其实还是一个函数,我们也可以简单的认为 类就是 构造函数的另外一种写法
    // (1)类有原型对象prototype
    console.log(Star.prototype);
    // (2)类 也有原型对象,这个原型对象指向类本身
    console.log(Star.prototype.constructor);
    // (3)类 可以通过原型对象添加方法
    Star.prototype.sing = function() {
        console.log('冰雨');
    };
    // (4)类创建的实例对象,有__proto__原型,指向类的原型对象
    var ldh = new Star();
    console.dir(ldh);
    console.log(ldh.__proto__ === Star.prototype);
</script>

八、ES5新增方法

8.1 数组方法forEach遍历数组

 arr.forEach(function(value, index, array) {
       //参数一是:数组元素
       //参数二是:数组元素的索引
       //参数三是:当前的数组
 })
  //相当于数组遍历的 for循环 没有返回值

8.2 数组方法filter过滤数组

  var arr = [12, 66, 4, 88, 3, 7];
  var newArr = arr.filter(function(value, index,array) {
     //参数一是:数组元素
     //参数二是:数组元素的索引
     //参数三是:当前的数组
     return value >= 20;
  });
  console.log(newArr);//[66,88] //返回值是一个新数组

8.3 数组方法some

some 查找数组中是否有满足条件的元素 
 var arr = [10, 30, 4];
 var flag = arr.some(function(value,index,array) {
    //参数一是:数组元素
     //参数二是:数组元素的索引
     //参数三是:当前的数组
     return value < 3;
  });
console.log(flag);//返回值是布尔值,只要查找到满足条件的一个元素就立马终止循环

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值