封装
自定义构造函数原型对象
- 由于原型对象也是一个对象, 所以我们可以自定义构造函数的原型对象
注意点:
自定义原型对象一定要保持三角恋的关系, 一定要设置constructor: 所属的构造函数
// 自定义一个构造函数
function Person(name,age) {
this.name = name;
this.age = age;
}
// 由于原型对象也是一个对象, 所以我们可以自定义构造函数的原型对象
// 注意点: 自定义原型对象一定要保持三角恋的关系, 一定要设置constructor: 所属的构造函数
Person.prototype = {
constructor: Person,
say: function () {
console.log("我是方法");
}
};
var per = new Person("wjh",19);
per.say();
console.log(per.__proto__);
对象的公有属性(方法)和私有属性(方法)
- 什么是全局变量和函数
只要写在一对script标签中或者写在一个单独的JS文件中的变量和函数就是全局的变量和函数 - 什么是局部的变量和函数
只要在其它函数中定义的变量或者函数都是局部变量和局部函数
var num = 666; // 全局变量
function test() { // 全局函数
console.log("test");
console.log(num); // 在其它作用域中访问全局变量
}
console.log(num); // 在全局作用域中访问全局变量
test(); // 在全局作用域中访问全局函数
function demo() {
test(); // 在其它作用域中访问全局函数
}
demo();
function test() {
var num = 123; // 局部的变量
console.log(num); // 可以在当前作用域中访问当前作用域的局部变量
function demo() {
console.log("demo");
}
demo(); // 可以在当前作用域中访问当前作用域的局部函数
}
// console.log(num); // 不能在其它作用域中访问局部变量
demo(); // 不能在其它作用域中访问局部函数
- 默认情况下对象中的属性和方法都是公有的
注意点:
其实构造函数也是一个函数, 所以在构造函数中直接定义的变量, 就是局部变量, 外界就不能访问
function Person(name,age) {
this.name = name;
this.age = age;
//其实构造函数也是一个函数, 所以在构造函数中直接定义的变量, 就是局部变量, 外界就不能访问
var num = 666;//私有属性
function test() {//私有函数
console.log(test);
}
}
// console.log(num); 会报错
// test(); 会报错
var p = new Person();
// console.log(p.num); undefine
// p.test(); 会报错
对象的实例属性和方法
- 什么是实例?
通过构造函数创建出来的对象, 我们就称之为实例
也就是实例就是对象的另一个名称而已 - 什么是实例属性和实例方法?
实例的属性就是通过对象才能访问的属性
实例的方法就是通过对象才能访问的方法
// 自定义一个构造函数
function Person(name,age) {
this.name = name;
this.age = age;
this.say = function () {
console.log("say");
}
}
var p = new Person("wjh",19);
console.log(p.name);//实例属性
console.log(p.age);
p.say();//实例方法
/*
// 这里通过new Person()创建出来的p对象我们就称之为实例
var p = new Person("lnj", 13);
// 这里通过p.xxx访问的属性, 我们就称之为实例属性
console.log(p.name);
console.log(p.age);
// 这里通过p.xxx()访问的方法, 我们就称之为实例方法
p.say();
*/
对象的静态属性和方法
- 什么是静态属性和静态的方法?
通过构造函数就能够直接访问的属性和访问, 我们就称之为静态属性和方法
// 自定义一个构造函数
function Person(name,age) {
this.name = name;
this.age = age;
this.say = function () {
console.log("say");
}
}
// 将属性和方法添加给了构造函数, 这里添加的属性和方法将来就只能通过构造函数来访问
// 这里添加的属性和方法就是静态的属性和方法
Person.type = "人";
Person.eat = function () {
console.log("eat");
}
//访问静态属性和方法
console.log(Person.type);
Person.eat();
继承
修改this指向的方法
- bind方法的作用
修改函数内部的this的, 但是不会调用这个函数
, 会返回一个新的函数给我们
//定义一个函数
function test(a,b) {
console.log(this);
console.log(a, b);
}
//定义一个对象
var obj = {
name : "wjh"
};
test();
//使用bind方法
var fn = test.bind(obj);
console.log(fn);
fn();
- call方法的作用
修改函数内部的this的, 但是自动会调用这个函数
//定义一个函数
function test(a,b) {
console.log(this);
console.log(a, b);
}
//定义一个对象
var obj = {
name : "wjh"
};
test();
//使用call方法
test.call(obj,10,20);
- apply方法的作用
修改函数内部的this的, 但是会自动调用这个函数
//定义一个函数
function test(a,b) {
console.log(this);
console.log(a, b);
}
//定义一个对象
var obj = {
name : "wjh"
};
test();
//使用apply方法
test.apply(obj,[20,30]);
注意点:
call和apply的区别:
传递参数的形式不同, 如果是call那么参数依次用逗号隔开即可, 如果是apply那么参数都要放到一个数组中
子类继承父类的写法
- 借用父类构造函数, 动态给当前子类对象添加属性和方法
也就是利用call函数,将父类构造函数中的this修改为子类构造函数
- 借用父类构造函数, 动态给当前子类对象添加属性和方法
- 2.将子类原型对象修改为父类的对象
- 3.将子类原型对象的constructor属性指向对应的构造函数
// 父类
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
console.log("say");
};
//子类
function Student(score, name, age) {
//1. 借用构造函数, 动态给当前对象添加属性和方法
Person.call(this,name,age);
this.score = score;
}
Student.prototype.eat = function () {
console.log("eat");
};
//2.将子类原型对象修改为父类的对象
Student.prototype = new Person();
//3.将子类原型对象的constructor属性指向对应的构造函数
Student.prototype.constructor = Student;
var stu = new Student(66,"wjh",20);
console.log(stu.name);
console.log(stu.score);
//子类可以访问父类的原型方法
stu.say();
var per = new Person("lnj",30);
//父类的原型对象没有改变
console.log(per.__proto__);
//父类不能访问子类原型对象的方法
per.eat();
多态
- js是弱类型语言,没有明确的多态,传入任何类型都可以
对象的增删改查
- 如何访问对象的属性(查询)
对象.属性名称方式, 操作属性
对象["属性名称"]方式, 操作属性
- 删除对象属性
使用delete 关键字
删除对应的属性 - 增加属性
对象中如何没有就会新增属性
对象.属性名称方式
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
}
}
// 给Person的原型对象添加了一个type属性
Person.prototype.type = "人";
//创建一个对象
var per = new Person("HH",20);
// 2.如何访问对象的属性(查询)
// 2.1对象.属性名称方式, 操作属性
// 2.2对象["属性名称"]方式, 操作属性
console.log(per.name);
console.log(per.age);
console.log(per["name"]);
console.log(per["age"]);
// 3.如何新增属性
// 对象中如何没有就会新增(新增)
per.score = 50;
console.log(per);
// 4.如何删除对象中的属性
console.log(per);
delete per.age;
console.log(per);
- 如何判断对象中有没有某个属性
通过"属性名称" in 对象
方式来判断, 如果有就返回true, 如果没有就返回false
// 5.如何判断对象中有没有某个属性
// 5.1通过 "属性名称" in 对象方式来判断, 如果有就返回true, 如果没有就返回false
// 注意点:属性名称一定是字符串类型
// 特点: 会先在当前对象中找有没有, 如果没有会去当前对象的原型对象上找有没有, 一直找到null都没有就会返回false
console.log("name" in per);
console.log("age" in per);
console.log("type" in per);
// 5.2通过对象.hasOwnProperty("属性名称")方式来判断, 只会在当前对象上查找, 如果当前对象上有就返回true, 如果当前对象上没有就返回false, 不会去 当前对象的原型对象上查找
console.log(per.hasOwnProperty("name"));
console.log(per.hasOwnProperty("age"));
console.log(per.hasOwnProperty("type"));//false
// 问题: 我们可以判断某个属性是否是当前对象的属性
// 我们也可以判断某个属性是否是当前对象或者原型上的属性
// 那么我们能不能判断某个属性时候是原型上的属性呢?
if (!per.hasOwnProperty("type")){
if ("type" in per){
console.log("原型对象上的属性type");
}
}
//将判断是否是原型上的属性封装成方法
function prototyProperty(obj,name) {
if (!obj.hasOwnProperty(name)){
if (name in obj){
return true
}
}
return false
}
var flag = prototyProperty(per,"name");
console.log(flag);
对象的遍历
- 在JavaScript中对象是可以直接遍历的利用高级for循环就可以直接遍历对象
for(var key in obj){ }
会将对象中的每一个属性依次取出来赋值给key对象中有多少个属性,循环就会执行多少次
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
}
}
var p = new Person("lnj", 33);
for (var key in p){
//打印属性和方法名称
// console.log(key);
//打印属性和方法对应的值
// console.log(p[key]);
if (p[key] instanceof Function){
continue;
} else {
console.log(p[key]);
}
}
对象的深拷贝和浅拷贝
- 什么是对象的拷贝?
将一个对象赋值给另外一个对象, 我们称之为对象的拷贝
- 什么是深拷贝, 什么是浅拷贝?
例如将A对象赋值给B对象
深拷贝是指
, 修改B对象的属性和方法不会影响到A对象的属性和方法, 我们称之为深拷贝
浅拷贝是指
, 修改B对象的属性和方法会影响到A对象的属性和方法, 我们称之为浅拷贝
注意点:
3.1 默认情况下对象之间的直接赋值都是浅拷贝
3.2 默认情况下一个对象的属性如果是基本数据类型, 那么都是深拷贝
3.3 如果对象的属性包含了引用数据类型, 才真正的区分深拷贝和浅拷贝
浅拷贝
function Person(name, age, dog) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
};
this.dog = dog;
}
var p1 = new Person("lnj", 13, {
name: "wc",
age: "3"
});
// 1.对象之间的直接赋值
// 将p1对象赋值给p2对象
// 本质上是p1和p2都指向了同一块存储空间
// 所以无论是修改p1还是p2都会影响到另外一个
// 所以下列代码是浅拷贝
var p2 = p1;
console.log(p1.name);//lnj
p2.name = "haha";
console.log(p1.name);//haha p1对象的属性被修改
深拷贝
-
深拷贝思想:
如果是基本数据类型直接赋值,如果是引用类型就新创建一个对象
,然后把对象的值给到新创建的对象
// 2.对象属性的逐一赋值
var p2 = new Person();
p2.name = p1.name;
p2.age = p1.age;
p2.dog = p1.dog;
//可以使用遍历对象逐一拷贝
for (var key in p1){
p2[key] = p1[key];
}
- 深拷贝封装方法
function Person(name, age, dog) {
this.name = name;
this.age = age;
this.say = function () {
console.log(this.name, this.age);
};
this.dog = dog;
}
var p1 = new Person("lnj", 13, {
name: "wc",
age: "3"
});
var p2 = new Person();
//深拷贝思想:如果是基本数据类型直接赋值,如果是引用类型就新创建一个对象,然后把对象的值给到新创建的对象
function deepCopy(obj1, obj2) {
// 取出第一个对象的每一个属性
for (var key in obj1) {
// 取出第一个对象当前属性对应的值
var item = obj1[key];
// 判断当前的值是否是引用类型
// 如果是引用类型, 我们就重新开辟一块存储空间
if (item instanceof Object) {
var temp = new Object();
deepCopy(item, temp);
//把新创建的对象赋值给obj2
obj2[key] = temp;
} else {
// 基本数据类型
obj2[key] = item;
}
}
}
deepCopy(p1,p2);
console.log(p1.dog.name);
p2.dog.name = "miaomiao";
console.log(p1.dog.name);
网友评论