面向对象编程
JavaScript 对象体系,不是基于“类”的,而是基于构造函数constructor和原型链prototype的。
Vehicle就是构造函数。第一个字母大写以区分普通函数。内部使用了this关键字,代表了所要生成的对象
实例。必须使用new命令生成对象。
var Vehicle = function (p) {
this.price = p;
};
var v = new Vehicle(500);
new
使用new命令时,它后面的函数依次执行下面的步骤。
- 创建一个空对象,作为将要返回的对象实例。
- 将这个空对象的原型,指向构造函数的
prototype属性。 - 将这个空对象赋值给函数内部的
this关键字。 - 开始执行构造函数内部的代码。
如果当前函数是new命令调用,new.target指向当前函数,否则为undefined。
function f() {
console.log(new.target === f);
}
f() // false
new f() // true
Object.create()传入一个现有的对象,生成新的实例对象。
this
this的指向:
function f() {
return '姓名:'+ this.name;
}
var A = {
name: '张三',
describe: f
};
var B = {
name: '李四',
describe: f
};
A.describe() // "姓名:张三"
B.describe() // "姓名:李四"
this设计目的就是在函数体内部,指代函数当前的运行环境。
var f = function () {
console.log(this.x);
}
var x = 1;
var obj = {
f: f,
x: 2,
};
// 单独执行
f() // 1
// obj 环境执行
obj.f() // 2
this的主要使用场合。
- 全局环境使用
this,它指的就是顶层对象window - 构造函数中的
this,指的是实例对象。 - 对象的方法里面包含
this,this的指向就是方法运行时所在的对象。
call、apply、bind这三个方法,来切换/固定this的指向
var n = 123;
var obj = { n: 456 };
function a() {
console.log(this.n);
}
a.call() // 123
a.call(null) // 123
a.call(undefined) // 123
a.call(window) // 123
a.call(obj) // 456
apply和call相似, 区别是apple传参用数组
function f(x, y){
console.log(x + y);
}
f.call(null, 1, 1) // 2
f.apply(null, [1, 1]) // 2
bind()方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。
var counter = {
count: 0,
inc: function () {
this.count++;
}
};
var obj = {
count: 100
};
var func = counter.inc.bind(obj);
func();
obj.count // 101
继承
prototype所有属性和方法,都能被实例对象共享。
原型链:所有对象都有自己的原型对象(prototype),最终都可以上溯到Object.prototype(即null)。
prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
function P() {}
var p = new P();
p.constructor === P // true
p.constructor === P.prototype.constructor // true
p.hasOwnProperty('constructor') // false
instanceof运算符返回一个布尔值,表示对象是否为某个构造函数的实例。
继承
// 第一步,子类继承父类的实例
function Rectangle() {
Shape.call(this); // 调用父类构造函数
}
// 另一种写法
function Rectangle() {
this.base = Shape;
this.base();
}
// 第二步,子类继承父类的原型
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect instanceof Rectangle // true
rect instanceof Shape // true
对象方法
Object.getPrototypeOf方法返回参数对象的原型Object.setPrototypeOf方法为参数对象设置原型,返回该参数对象- 实例对象的
isPrototypeOf方法,用来判断该对象是否为参数对象的原型。 - 实例对象的
__proto__属性(前后各两个下划线),返回该对象的原型。即prototype。 Object.getOwnPropertyNames返回一个参数对象本身的所有非继承属性的键名的数组。- 对象实例的
hasOwnProperty用于判断某个属性定义在对象自身,还是定义在原型链上。 in和for...in。Object.getOwnPropertyDescriptors对象拷贝。
Object
Object对象本身的方法
Object.print = function (o) { console.log(o) };
实例方法就是定义在Object原型对象Object.prototype上的方法。
Object.prototype.print = function () {
console.log(this);
};
var obj = new Object();
obj.print() // Object
象属性模型的相关方法
Object.getOwnPropertyDescriptor():获取某个属性的描述对象。Object.defineProperty():通过描述对象,定义某个属性。Object.defineProperties():通过描述对象,定义多个属性。
控制对象状态的方法
Object.preventExtensions():防止对象扩展。Object.isExtensible():判断对象是否可扩展。Object.seal():禁止对象配置。Object.isSealed():判断一个对象是否可配置。Object.freeze():冻结一个对象。Object.isFrozen():判断一个对象是否被冻结。
原型链相关方法
Object.create():该方法可以指定原型对象和属性,返回一个新的对象。Object.getPrototypeOf():获取对象的Prototype对象。
实例对象的方法
Object.prototype.valueOf():返回当前对象对应的值。Object.prototype.toString():返回当前对象对应的字符串形式。Object.prototype.toLocaleString():返回当前对象对应的本地字符串形式。Object.prototype.hasOwnProperty():判断某个属性是否为当前对象自身的属性,还是继承自原型对象的属性。Object.prototype.isPrototypeOf():判断当前对象是否为另一个对象的原型。Object.prototype.propertyIsEnumerable():判断某个属性是否可枚举。
属性描述对象:JS内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。每个属性都有属性描述对象(元信息)。
属性描述对象提供6个元属性。
{
value: 123,// 该属性的属性值,默认为`undefined`。
writable: false,//是否可改变
enumerable: true,//是否可遍历,默认`true`。如`false` Object.keys()会跳过该属性。
configurable: false,//可配置性 可写性。 默认为`true`
get: undefined,// 取值函数(getter)
set: undefined//存值函数(setter)
}
Object.getOwnPropertyDescriptor()获取自身属性描述对象:
var obj = { p: 'a' };
Object.getOwnPropertyDescriptor(obj, 'p')
// Object { value: "a",
// writable: true,
// enumerable: true,
// configurable: true
// }
Object.getOwnPropertyNames返回对象自身的全部属性的属性名。
元属性
value属性是目标属性的值。
var obj = {};
obj.p = 123;
Object.getOwnPropertyDescriptor(obj, 'p').value
// 123
Object.defineProperty(obj, 'p', { value: 246 });
obj.p // 246
configurable为false时,writable、enumerable和configurable都不能被修改了
value属性的情况比较特殊。
下面这样实现,属性p的configurable和enumerable都为true
var obj = {
get p() {
return 'getter';
},
set p(value) {
console.log('setter: ' + value);
}
};
JavaScript 提供了三种冻结方法,最弱的一种是Object.preventExtensions,其次是Object.seal,最强的是Object.freeze。防止对象被改变。然后可以通过 isFrozen isSealed检查。
Object.preventExtensions方法可以使得一个对象无法再添加新的属性。