js继承

 
js 是弱类型语言;
 
面向对象有三个特征:
 
封装 继承 多态
 
找寻机制 -> 原型链;
 
    链:作用域链 -> 原型链;
 
继承的限制 => 只有在使用构造函数和原型编程时可以使用继承;
 
1.克隆是继承;
2.权限式继承;
 
构造函数的继承:function Father(name, age, money) {this.name = name;this.age = age;this.money = money;}var father = new Father("王健林", "60", "100亿");console.log(father);function Son(name, age, money) {Father.call(this, name, age, money);}function Son() {Father.apply(this, arguments);}var son = new Son("王思聪", "31", "50亿");console.log(son);Math.min(1, 2, 3, 4, 5, 6, 7)Math.min.apply(false, [1, 2, 3, 4, 5])


call&apply (改变this指向的方法)

this指向的两种情况:
1.指向函数的调用者;
2.在构造函数中,指向实例化对象;
3.bind => 在函数创建初期固定this指向;


function foo(a, b, c) {
console.log(this, a, b, c);
}

// foo(); // this => window

// call 第一个参数就是制定当前函数this指向的;
// foo.call({ name: "一个任意对象" }) // 调用

// call 制定函数的调用者;
   foo.apply({ name: "一个任意对象" })

// call 和 apply 都是制定函数调用者的方法(在调用时改变函数的this指向的方法);

// call 和 apply 的不同;

// call(arg1, arg2, arg3, ..., arg10)

// call 的第二个及以后的参数和形参一一对应;

// foo.call({ name: "一个任意对象" }, 1, 2, 3)
// foo.call({ name: "二个任意对象" }, 1, 2, 3)
// foo.call({ name: "三个任意对象" }, 1, 2, 3)

// foo.call(改变tihis指向,实参1,实参2,...,实参n)

// apply 只接受两个参数;
   apply(arg_this, arg_arguments_array);
   foo.apply({ name: "一个任意对象" }, [1, 2, 3]);

// call,apply 都是在调用函数的时候改变this指向的方法;

// call,接受n个参数 第一个参数改变this,其余的参数和形参一一对应
// apply,接收两个参数 第一个参数改变this,第二个参数改变arguments对象;


原型对象的继承:

// 方法有必要复制么 ?

// function foo(){
// console.log("我执行了");
// }

// var myFoo = foo;

// var myNewFoo = eval("("+foo.toString()+")");

// myFoo();
// myNewFoo();

// 函数体内的代码是不变更的;

// 在继承方法的时候,只要拿到函数的地址就可以了;

// console.log(foo === myFoo , foo === myNewFoo);


function Father() {
this.name = "马云";
};
Father.prototype.show = function () {
console.log("马云 : 我不喜欢钱,我对钱没有兴趣");
console.log("撒贝宁 : 噗呲... ");
}

// father => 由构造函数直接负责;

var father = new Father();
console.log(father);
father.show();


// 原型的动态性;

function Son() {

this.hello = function () {
console.log("say hello");
}
};

// var son = new Son();
// console.log(son);

// Son.prototype = Father.prototype;

// var son2 = new Son();
// console.log(son2);

//tip : 在实例化之前一定要完成原型的变更;

// var son = new Son();
// console.log(son);

// 新的方法就必须写在构造函数里了;

// Son.prototype.hello = function(){
// console.log("say hello");
// }

// console.log(son);

// 原型的赋值;

// 循环赋值 => 保留了子集的原型,不用把新的覆盖的方法写在构造函数中;


// 遍历父级所有方法;
for (var attr in Father.prototype) {
Son.prototype[attr] = Father.prototype[attr];
}

Son.prototype.hello = function () {
console.log("say hello");
}

var son = new Son();

console.log(son);


原型链的继承:

// 原型链
// 链 ? 找寻方式;

var obj = {};
var obj = new Object();

console.log(obj);
console.log(obj.toString());

// 实例化对象找寻某个属性是否存在的过程,在这个过程之中会按照当前对象之中存在的原型指针依次进行查找;

// 访问某个属性是解析器做了些啥 ?

// 1. 有没有某个属性 ?
// 1.1 有 => 返回;
// 1.2 没有 => 有没有原型指针;
// 1.2.1 有 => 返回;
// 1.2.2 没有 => 返回undefined;

// function Father() {

// }
// Father.prototype.hello = function () {

// }
// function Son() {

// }
// Son.prototype = new Father();

// var son = new Son();

// console.log(son);

function Father() {

}
Father.prototype.hello = function () {

}
function Son() {

}

// Son.prototype = new Father();

// 语义化更清晰了; ES5 的;

// Son.prototype = Object.create(Father.prototype);
// Son.prototype = Object.create({ name: "hello" });

// Object.create();
// Object.create 创建一个对象; 这个对象之中有一个指针指向参数对象;


// var son = new Son();
// console.log(son);

// 不要这样;

Son.prototype = Object.create(Son.prototype);
var son = new Son();
console.log(son);

// 原型链继承 => 给当前原型对象上添加一个原型指针,让当前原型对象和父级(希望继承的原型上有一个联通方式);
原文地址:https://www.cnblogs.com/Guernicas/p/10273923.html