class和构造函数的区别
1.构造函数本身是函数,因此会有函数声明的提升
class 声明不能提升
2. class 只能通过new实例
3. class 采用严格模式;
4. class 中的原型上的属性不能遍历
5. class 内部不能修改class的名称
ES6 class的写法
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
say() {
console.log("hello");
}
sayHi() {
console.log("hi");
}
static eat() {
console.log("eat");
}
}
ES5构造函数写法
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype = {
constructor: Person,
say: function () {
console.log("hello");
},
sayHi: function () {
console.log("hi");
}
}
Person.eat = function () {
console.log("eat");
}
new.target
在构造函数中
new.target
属性可以检测构造函数是否是通过new运算符被调用的,
- 通过new运算符调用的构造函数
new.target
属性指向该构造函数- 直接以普通函数调用的构造函数
new.target
属性指向undefined
function Person(name, age) {
console.log(new.target === Person); //true
this.name = name;
this.age = age;
}
let p = new Person("张三", 18)
function Person(name, age) {
console.log(new.target); //undefined
this.name = name;
this.age = age;
}
let p = Person("张三", 18)
在class类中
new.target
属性指向直接被new执行的构造函数
class Person {
constructor(name, age) {
console.log(new.target); //指向Son
this.name = name;
this.age = age;
}
}
class Son extends Person {
constructor(name, age) {
super(name, age);
console.log(new.target);//指向Son
}
}
let son1 = new Son();
call、bind、apply重写
call重写
function randomString() {
return (
Math.random()
.toString(36)
.substr(3, 6) + new Date().getTime().toString(36)
)
}
Function.prototype.myCall = function (context) {
// console.log(context);
if (typeof context === 'object' && context != null) {
var prop = randomString()
var args = [];
for (let i = 1; i < arguments.length; i++) {
args.push(arguments[i]);
}
context[prop] = this;
var res = eval("context[prop](" + args + ')')
delete context[prop];
return res;
}
}
function test(a, b) {
console.log(a, b);
return a + b;
}
let ans = test.myCall({}, 1, 2)
console.log(ans);
apply重写
// apply重写
Function.prototype.myApply = function (context) {
if (typeof context === "object" && context !== null) {
var prop = randomString();
var args = [];
for (let i = 0; i < arguments.length; i++) {
args.push(arguments[1][i]);
}
context[prop] = this;
var res = eval("context[prop](" + args + ")")
delete context[prop];
return res;
}
}
function test(a, b) {
console.log(a, b);
return a + b;
}
let ans = test.myApply({}, [1, 2])
console.log(ans);
bind重写
// bind重写 : 1.偏函数的特性 2.原型的问题
Function.prototype.myBind = function (context) {
var fn = this;
var args = Array.prototype.slice.call(arguments, 1);
var target = function () {
var innerArgs = Array.prototype.slice.call(arguments);
return fn.apply(context, args.concat(innerArgs));
}
function Buffer() { };
Buffer.prototype = fn.prototype;
target.prototype = new Buffer();
return target;
}
测试
// 1.测试
var obj = {};
function test(a, b) {
return a + b;
}
let ans1 = test.myBind(obj, 1, 2)();
let ans2 = test.myBind(obj, 1)(2);
let ans3 = test.myBind(obj,)(1, 2);
console.log(ans1);
console.log(ans2);
console.log(ans3);
// 测试原型问题
function Person(name, age) {
this.name = name;;
this.age = age;
}
Person.prototype.say = function () {
console.log("Hello");
}
let Person1 = Person.myBind(obj);
let p = new Person1();
p.say()