JavaScript高级第2天
一、构造函数和原型
1、对象的三种创建方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| function People(name, age, sex) { this.name = name; this.age = age; this.sex = sex; this.say = function() { console.log('hello'); } } var a = new People('小明', 13, '男'); console.log(a); var obj = { name: '小敏', age: 12 }; var obj2 = new Object(); obj2.name = '小红'; obj2['age'] = 12; console.log(obj2);
|
2、静态成员和实例成员
- 静态成员:给构造函数添加的属性或方法, 只能通过构造函数本身才能访问的属性或方法
- 实例成员:只能通过实例对象才能访问的属性或方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| function People(uname, age, sex) { this.uname = uname; this.age = age; this.sex = sex; this.say = function() { console.log('hello'); } } var a = new People('小明', 13, '男'); console.log(a.uname); console.log(People.uname); People.height = 'height'; console.log(a.height); console.log(People.height);
|
3、构造函数模型
构造函数中直接添加方法的缺点
每次创建对象,要重复开辟内存空间,浪费资源
构造函数的原型 prototype
每个函数默认都有一个 propotype 属性, 它的值默认是一个对象
在 prototype 对象上的方法和属性, 会被 new 构造函数() 创建出来的实例对象所继承
注意:
(1) 只要是函数就默认有 prototype 属性, 但非函数的对象是不具有的
(2) 定义构造函数时, 公共的方法定义在原型对象上, 这样可以被所有创建出来的实例直接继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function Student(uname, age) { this.uname = name; this.age = age; } Student.prototype.sing = function() { console.log('哈哈哈哈'); } Student.prototype.study = '学习JS'; var xm = new Student('小明', 15); console.log(xm.study); xm.sing(); var obj = { a: 1 };
|
4、对象模型
1 2 3 4 5 6 7 8 9
| 对象的原型 每个对象都默认有一个 __proto__的属性, 它的值是一个对象, 默认指向创建这个对象的构造函数的原型
对象原型的访问特点 每个对象访问__proto__下的所有属性和方法,可以省略__proto__
对象上读取属性的顺序 先从自身的属性上进行查找,如果没有再去__proto__属性指向的对象上去查找
|

5、constructor构造函数
- 对象原型( __proto__)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身。
- constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
- 当我们重新建立一个对象去覆盖原先的prototype时,constuctor属性需要我们手动赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function Star(uname, age) { this.uname = uname; this.age = age; } Star.prototype = { constructor: Star, // 手动设置指回原来的构造函数 sing: function() { console.log('我会唱歌'); }, movie: function() { console.log('我会演电影'); } } var zxy = new Star('张学友', 19); console.log(zxy)
|
6、原型链
每一个实例对象又有一个__proto__属性,指向的构造函数的原型对象,构造函数的原型对象也是一个对象,也有__proto__属性,这样一层一层往上找就形成了原型链。

原型链理解(面试常问)
每个实例对象( object )都有一个私有属性(称之为 proto )指向创建它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。
7、原型链和成员的查找机制
对象访问属性时遵从原型链的顺序
(1) 当访问一个对象的属性时,首先从这个对象自身进行查找
(2) 如果没有找到就从它的原型对象(__proto__)中查找
(3) 如果还没有找到,继续沿着对象的原型链层层向上查找,直到最末尾的 null
8、原型对象中this指向
构造函数中的this和原型对象的this,都指向我们new出来的实例对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| var that; function Student(uname, age) { this.uname = name; this.age = age; } Student.prototype.sing = function() { that = this; console.log('哈哈哈哈'); } Student.prototype.sleep = function() { console.log(this === Student.prototype); console.log('去睡觉'); } var xm = new Student('小明', 15); xm.sing(); console.log(that === xm);
Student.prototype.sleep();
|
9、原型链的应用:拓展内置对象上自定义方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var arr = [1, 2, 3] console.log(arr.__proto__ === Array.prototype); arr.push(4);
Array.prototype.getSum = function() { console.log(this); var sum = 0; for (var i = 0; i < this.length; i++) { sum += this[i]; } return sum; } console.log(arr.getSum());
|
拓展原型对象上的方法时,不能直接覆盖原来的原型对象,只能添加或和修改方法 注意:内置对象(如:Object, Array, Function) 上的原型对象不允许进行覆盖,只允许修改
二、继承
1、call()
- 使用:fn.call([thisArg, arg1, arg2…])
- 作用:调用一个函数,并指定调用时 this 的值
- 参数: thisArg 函数中 this 的指定值; arg1, arg2…可选的参数列表
- 返回值:函数调用的结果
- 注意:第一个参数 thisArg 如果不传或是 null、undefined,默认函数内 this 指向 window
2、子构造函数继承父构造函数中的属性
- 先定义一个父构造函数
- 再定义一个子构造函数
- 子构造函数继承父构造函数的属性(使用call方法)
1 2 3 4 5 6 7 8 9 10 11 12 13
| function People(name, age) { console.log(this); this.name = name; this.age = age; }
function Student(name, age) { People.call(this, name, age); } var xm = new Student('小明', 15); console.log(xm);
|
3、借用原型对象继承方法
- 先定义一个父构造函数
- 再定义一个子构造函数
- 子构造函数继承父构造函数的属性(使用call方法)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| function People(name, age) { console.log(this); this.name = name; this.age = age; }; People.prototype.say = function() { console.log('hello'); };
function Student(name, age, subject) { People.call(this, name, age); this.subject = subject; }; Student.prototype = People.prototype;
var obj = { constructor: Student, //把constructor指向子构造函数 __proto__: People.prototype, //通过原型链,把父构造函数的原型直接拿过来; } Student.prototype = obj;
Student.prototype = new People(); Student.prototype.constructor = Student;
Student.prototype.sleep = function() { console.log('去睡觉啊'); } var xm = new Student('小明', 15, '语文'); xm.say(); console.log(xm); console.log(People.prototype); console.log(xm.constructor);
|
4、类的本质
- 构造函数默认有一个 prototype 属性, 它的值是一个对象
- 构造函数 prototype 属性下有 constructor 和 proto 两个默认的属性
- 构造函数可以通过在 prototype 上添加方法, 去实现所有实例继承
- 构造函数创建的实例上 __proto__指向创建它构造函数的 prototype
- class 类的本质其实就是一个改造版的构造函数
三、ES5新增数组方法
1、数组方法forEach遍历数组
- 参数:callback(元素, 索引, 数组本身)
- 返回值:无
- 例子: 使用 forEach 对数组求和
1 2 3 4
| var arr = [10, 12, 55, 13] arr.forEach(function(item, index, arr) { console.log('索引号:' + index + '===>' + '数组元素:' + item); })
|
2、filter() 方法从数组筛选出符合条件的所有元素
- 参数:callback(元素, 索引, 数组本身)
- 返回值:新数组
- 例子: 使用 filter 筛选数组中所有偶数
1 2 3 4 5 6
| var arr2 = [1, 2, 3, 4, 5, 6]; var newArr = arr2.filter(function(item,index) { return item % 2 == 0; }) console.log(newArr);
|
3、some() 方法用于查找数组中是否有符合条件的某一个元素
- 参数:callback(元素, 索引, 数组本身)
- 返回值:true(找到) || false(找不到)
1 2 3 4 5
| var arr = ['hello', '12', ' ', 'true', ''] var a = arr.some(function(item, index){ return item == ''; }) console.log(a);
|
4、 every() 方法用于查找数组中是否所有的元素都符合条件
- 参数:callback(元素, 索引, 数组本身)
- 返回值:true || false (只要有一个不满足就返回 false)
1 2 3 4 5 6 7
| var arr3 = [30, 22, 45, 16, 20]; var b = arr3.every(function(item, index) { return item > 20; }) console.log(b); console.log(arr3.__proto__ === Array.prototype);
|
5、trim方法去除字符串两端的空格
1 2 3 4
| var str = ' hello ' console.log(str.trim()) var str1 = ' he l l o ' console.log(str.trim())
|
6、获取对象的属性名
Object.keys(对象) 获取到当前对象中的属性名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var obj = { a: 1, b: 2, c: 3 }; for (var key in obj) { console.log(obj[key]); } var res = Object.keys(obj); console.log(res);
res.forEach(function(item) { console.log(item); console.log(obj[item]); })
|
7、Object.defineProperty() 方法
作用:在对象上定义一个新属性,或者修改原属性,并返回对象
使用方法:
Object.defineProperty(obj, prop, descriptor)
(1) obj: 要定义属性的对象
(2) prop: 要定义或修改的属性的名称, 字符串 ‘name’
(3) descriptor: 要定义或修改的属性描述符, 数据格式是对象 {}
属性的描述符:
(1) value: 属性值
(2) writable: 是否可以修改
(3) enumerable: 是否可以枚举(遍历到)
(4) configurable: 是否可以删除或再次修改特性
三个属性描述符默认都是 false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var obj = { name: '张三', age: '12', gender: 'man' } Object.defineProperty(obj, 'height', { value: '170', writable: true, enumerable: true, configurable: true }) obj.height = '175'; console.log(Object.keys(obj)); delete obj.height; console.log(obj.height);
|