var Vehicle = function () {
this.price = 1000;
};
var Vehicle = function () {
this.price = 1000;
return 1000;
};
(new Vehicle()) === 1000
// false
上面代码中,构造函数 Vehicle 的 return 语句返回一个数值。这时,new 命令就会忽略这个 return 语句,返回“构造”后的 this 对象
如果 return 语句返回的是一个跟 this 无关的新对象,new 命令会返回这个新对象,而不是 this 对象。这一点需要特别注意
var Vehicle = function (){
this.price = 1000;
return { price: 2000 };
};
(new Vehicle()).price
// 2000
上面代码中,构造函数 Vehicle 的 return 语句,返回的是一个新对象。new 命令会返回这个对象,而不是 this 对象
如果对普通函数(内部没有 this 关键字的函数)使用 new 命令,则会返回一个空对象
function getMessage() {
return 'this is a message';
}
var msg = new getMessage();
msg // {}
typeof msg // "object"
var Vehicle = function () {
this.price = 1000;
};
var v = new Vehicle();
每个函数都有一个 prototype 属性,这个属性是指向一个对象的引用,这个对象称为原型对象,原型对象包含函数实例共享的方法和属性,也就是说将函数用作构造函数调用(使用 new 操作符调用)的时候,新创建的对象会从原型对象上继承属性和方法
每个函数都有一个 prototype 属性,指向一个对象
原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上
原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的原因,而实例对象可以视作从原型对象衍生出来的子对象
所有对象都有自己的原型对象(prototype),任何一个对象,都可以充当其他对象的原型;另一方面,由于原型对象也是对象,所以它也有自己的原型。因此,就会形成一个“原型链”:对象到原型,再到原型的原型
原型链的尽头就是 null
prototype 对象下有个 constructor 属性,默认指向 prototype 对象的构造函数
公有是指,在外部环境中可以获取的,可以直接通过实例对象用”.”运算符操作获得。(在构造函数中用 this 进行声明)
私有是指,在外部环境中不能直接访问,该属性/方法只能在对象的构造函数内访问。(声明在构造函数里的变量和方法,没有用到 this)
静态是指,属性/方法是归属于构建函数/类的,而非实例对象。可以直接通过类名来调用得到func.静态方法名 = function () {....};
func.静态方法名()
共享是指,实例对象之间,共享属性和方法,借助向原型对象添加属性和方法,可以实现继承
super 这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同
super 作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类
<script>
// 构造函数
let Animal = function (name) {
this.height = 120;
this.name = name;
};
// 通过原型对象给实例添加共享方法
Animal.prototype.walk = function () {
return `${this.name} 在缓慢行动`;
};
Animal.prototype.foot = function () {
return this.name + "有四条腿";
};
let tigger = new Animal("tigger");
console.log(tigger);
console.log(tigger.foot());
console.log(tigger.walk());
let cat = new Animal("cat");
console.log(cat);
console.log(cat.walk());
</script>
<script>
// class用法
class animal {
// 私有属性 只能在类内部使用
#foot = 4;
// constructor 引用构造函数
constructor(name) {
// this指向animal的实例化对象
// 公有属性
this.name = name;
}
// 共享方法/属性,和构造函数的prototype对象的一样
walk() {
return this.name + "开始行走";
}
run() {
return this.name + "跑向猎物";
}
// 静态只需要在前面机上static关键字
// 如果静态方法包含this关键字,这个this指的是类,而不是实例
static eat() {
console.log("快跑野兽要进食了");
}
}
// 静态属性
animal.live = "live";
// new一个对象
let tigger = new animal("tigger");
// 调用静态方法
animal.eat();
console.log(tigger.walk());
console.log(tigger.run());
console.log(animal.live);
// 继承
class Dog extends animal {
constructor(name, color) {
// 子类必须使用一次super函数
super(name);
this.color = color;
}
growl() {
console.log("growl");
}
// 访问器属性 get set方法读写
get dogColor() {
console.log(this.color);
}
set reColor(value) {
this.color = value;
}
}
// 父类的静态方法会也被子类继承
Dog.eat();
let lucky = new Dog("lucky", "black");
console.log(lucky.walk());
lucky.reColor = "white";
lucky.dogColor;
</script>
从数组和对象中提取值,对变量进行赋值,这被称为解构
let [a, b, c] = [1, 2, 3];
// 如果解构不成功,变量的值就等于undefined
var [j, q, k] = [11, 12];
console.log(j, q, k);
// 可以使用默认的值来避免结构不成功造成的undefined
var [j, q, k = 13] = [11, 12];
console.log(j, q, k);
// 使用...rest参数把多余的值,放入一个数组
let [z, x, ...v] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
console.log(z, x, v);
// 两个变量交换值很方便
let [one, two] = [10, 100];
console.log(one, two);
one = one + two;
two = one - two;
one = one - two;
console.log(one, two);
// 上面方法太麻烦了
// 再用解构的方法变回去
[one, two] = [two, one];
console.log(one, two);
// 对象解构
let { name, age, sex } = { name: "terry", age: 28, sex: "male" };
console.log(name, age, sex);
// 更新使用括号当作表达式
({ name, age, sex } = { name: "marry", age: 26, sex: "female" });
console.log(name, age, sex);
// 变量名冲突
({
name: nickname,
age,
sex,
} = { name: "jordan", age: 36, sex: "female" });
console.log(nickname, age, sex);
// 函数的参数解构
function pValues({ name, age, sex }) {
console.log(name, age, sex);
}
let userValues = { name: "ice", age: 26, sex: "male" };
pValues(userValues);