对象
// 第一种方式:字面量
var o1 = {name: 'o1'};
var o2 = new Object({name: 'o2'});
// 第二种方式:Object.create
var p = {name: 'p'};
var o4 = Object.create(p);
console.log(o4.__proto__ === p);
// 第三种方式 构造函数
var M = function (name) { this.name = name; };
var o3 = new M('o3');
M.prototype.say = function () {
console.log('say hi');
};
var o5 = new M('o5');
实现
new
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
- 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象
参考: https://zhuanlan.zhihu.com/p/84605717
function myNew() {
var func = Array.prototype.shift.call(arguments);
var obj = Object.create(func.prototype);
var result = func.apply(obj, arguments);
return result instanceof Object ? result : obj;
}
实现
instanceof
function myInstanceOf(obj, func) {
// 获取函数的原型对象
const FO = func.prototype;
// 获取所传进来对象的原型对象
const Obj = obj.__proto__;
while (true) {
if (Obj === null) {
return false;
}
if (Obj === FO) {
return true;
}
Obj = Obj.__proto__;
}
}
实现
call apply
apply方法传入两个参数,第一个参数就是this的指向,第二个参数就是函数参数组成的数组;而call传入多个参数,第一个参数也是this的指向,之后的参数都是函数的参数。等等,还有,在ES6解构赋值之前,可以用apply给函数传入参数数组
bind 除了返回是函数以外,它 的参数和 call 一样
参考: https://zhuanlan.zhihu.com/p/83523272
Function.prototype.myOwnCall = function(context) {
context = context || window;
var uniqueID = "00" + Math.random();
while (context.hasOwnProperty(uniqueID)) {
uniqueID = "00" + Math.random();
}
context[uniqueID] = this;
var args = [];
for (var i = 1; i < arguments.length; i++) {
args.push("arguments[" + i + "]");
}
var result = eval("context[uniqueID](" + args + ")");
delete context[uniqueID];
return result;
}
// 检测
var person = {
fullName: function(txt) {
console.log(txt + this.firstName + " " + this.lastName);
}
}
var person1 = {
firstName:"John",
lastName: "Doe"
}
person.fullName.myOwnCall(person1, "Hello, "); // 输出"Hello, John Doe"
Function.prototype.myOwnApply = function(context, arr) {
context = context || window
var uniqueID = "00" + Math.random();
while (context.hasOwnProperty(uniqueID)) {
uniqueID = "00" + Math.random();
}
context[uniqueID] = this;
var args = [];
var result = null;
if (!arr) {
result = context[uniqueID]();
} else {
for (var i = 0; i < arr.length; i++) {
args.push("arr[" + i + "]");
}
result = eval("context[uniqueID](" + args + ")");
}
delete context[uniqueID];
return result;
}
bind
原型
继承
/**
* 借助构造函数实现继承
*/
function Parent1() {
this.name = "parent1";
}
Parent1.prototype.say = function () {};
function Child1() {
Parent1.call(this);
this.type = "child1";
}
console.log(new Child1());
// 获取不到父原型对象上的 say()方法
// console.log(new Child1().say());
/**
* 借助原型链实现继承
*/
function Parent2() {
this.name = "parent2";
this.play = [1, 2, 3];
}
function Child2() {
this.type = "child2";
}
Child2.prototype = new Parent2();
var s1 = new Child2();
var s2 = new Child2();
console.log(s1.play, s2.play);
s1.play.push(4);
// new出来的两个实例其父构造器下的属性值 会同步
// [1, 2, 3, 4] [1, 2, 3, 4]
console.log(s1.play, s2.play);
/**
* 组合方式
*/
function Parent3() {
console.log("function Parent3...");
this.name = "parent3";
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = "child3";
}
Child3.prototype = new Parent3();
var s3 = new Child3();
// Parent3.call(this) 和 new Parent3() 父级构造函数 会执行了两次
/**
* 组合继承的优化1
*/
function Parent4() {
this.name = "parent4";
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = "child4";
}
Child4.prototype = Parent4.prototype;
var s5 = new Child4();
console.log(s5 instanceof Child4, s5 instanceof Parent4);
console.log(s5.constructor); // Parent4
// 实例对象s5 = new Child4()的构造器 constructor 应该为 Child4
/**
* 组合继承的优化2
*/
function Parent5() {
this.name = "parent5";
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this);
this.type = "child5";
}
// Object.create(obj)方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__
let obj = Object.create(Parent5.prototype);
Child5.prototype = obj;
Child5.prototype.constructor = Child5;
console.log( "一条原型链 ",
Child5.prototype.__proto__ === obj.__proto__,
obj.__proto__ === Parent5.prototype
);
var s7 = new Child5();
console.log("即是子类也是父类的实例",s7 instanceof Child5, s7 instanceof Parent5);
console.log(s7.constructor);
es6 class 继承
class person {
constructor() {
this.kind = "person";
}
eat(food) {
console.log(this.name + " eat " + food);
}
}
class student extends person {
constructor(name) {
super();
this.name = name;
}
}
var Tom = new student("Tom");
var Jock = new student("Jock");
console.log(Tom.kind); //person
console.log(Jock.kind); //person
Tom.eat("apple"); //Tom apple
Jock.eat("orange"); //Tom orange