js_继承及原型链等(三)
1. 继承
- 依赖于原型链来完成的继承
- 发生在对象与对象之间
- 原型链,如下:
function Father() {
this.name = 'eloise'
}
Father.prototype.giveMoney = function () {
console.log('im eloise, hello');
}
function Son() {
this.age = '2222'
}
Son.prototype = new Father();
var s = new Son();
console.log(s.age);
console.log(s.name);
s.giveMoney()
console.log(Father.prototype.__proto__); //Object[[proto]]
console.log(Object.prototype.__proto__); //null
- ==原型链是查找属性和方法的路径==
- 原型链的顶端,一般认为就是Object的原型对象(或者是Null)
- Object的proto指向null(原型链最顶端?/)
2. 继承中属性的共享问题
- 函数中的this到底是谁,和这个函数声明在什么地方没有关系,只和调用方式有关系
- 对象.方法()
- new构造函数()
- 函数()
- 直接调用函数,函数中的this是window
2.1 - 函数的借调
call
- ==函数.call()==
- 每个函数对象a的都有一个方法call,使用这个方法也可以调用函数a。
- 它可以指定a中的this是一个指定的对象。
function Father(name, say){ this.name = name; this.say = say; } Father.prototype.speak = function(){ console.log("我是父类型的方法。speak"); } function Son(age, name, say){ // this.name = name; // Father(name); this.name = window.name Father.call(this, name, say); //静态方法 //参数一: 重新指定Father中的this指向的是谁 this.age = age; } Son.prototype = new Father("eloise"); var s1 = new Son(10, "eloise2222", "helloWorld"); var s2 = new Son(20, "eloise33333"); // s1.__proto__.name = "eloise2222"; //又造成共享 console.log(s1.name); console.log(s1.say); console.log(s2.name); // console.log(window.name);
apply
- ==函数.apply()==
-
和call()的区别
- 函数的实参的传递方式不同,call是一个一个的传递的
-
apply是传递一个数组,js引擎会自动的拆封
function foo(a, b){ console.log(this, a, b); } foo(10, 20); // foo.call({}, 20, 30); var arr = [20, 30]; // foo.call({}, arr[0], arr[1]); foo.apply({}, arr); //{}, 20, 30
// var m = Math.max(10, 20, 40, 3, 5, 90); // console.log(m); var arr = [10, 20, 40, 3, 5, 90]; // var m = Math.max.apply(Math, arr); //this会出问题。 var m = Math.max(...arr); //展开运算符 console.log(m);
3. 函数借调的深入理解
function foo(){
console.log(this);
console.log(this.age);
}
foo(); //undefined
foo.call({age:20}); //20
foo(); //undefined
function foo(){
console.log(this[0]);
}
foo(); //undefined
foo.call([10, 20]); //10
window.age = 100;
var obj1 = {
age : 10,
speak : function(){
console.log(this.age);
}
}
obj1.speak(); //10
var f1 = obj1.speak;
f1(); //100
window.age = 10;
function speak(){
console.log(this.age);
}
var obj1 = {
age: 20,
speak : speak
}
var obj2 = {
age : 30,
speak:obj1.speak
}
speak(); //10
obj1.speak(); //20
obj2.speak(); //30
3. 借调的应用
- typeof
- instanceof
- Array.isArray
-
测试内置类型:
- 借调Object.prototype上的toString
- 对自定义类型,结果永远是[object Object]
function foo(){ } var arr = []; // console.log(foo.toString()); console.log(Object.prototype.toString.call(foo)); //[object Function] console.log(Object.prototype.toString.call(arr)); //[object Array] console.log(Object.prototype.toString.call(3)); //[object Number] console.log(Object.prototype.toString.call(null)); //[object Null]
4. 作用域链
是变量或函数的查找路径
5. 闭包
理论基础就是作用域链
- 认为闭包就是一个内部的函数
function foo(){
var a = 1;
function f1(){ //闭包/但是不是很准确
a++;
}
f1();
}
foo();
- 闭包是内部函数和它访问的外部的局部变量的组合
- 内部和它环境的组合
-
形成闭包的冲要条件:
- 一个内部函数(声明在函数内部的函数),如果访问了外部函数的局部变量,就一定会有闭包的产生
-
特点:
- 会持有外部函数的局部变量,而且访问局部变量的时候,访问的到的一定是那个局部变量的最新的值
- 当把闭包作为一个函数的返回值的时候,才会真正的有意义
function foo(){
var a = 10, b=20;
function f1(){
a++;
b++;
console.log(a, b);
}
return f1;
}
// var f = foo(); //在外部拿到了一个闭包
// f();
// f();
var f1 = foo(); //返回一个闭包
var f2 = foo(); //返回一个新的闭包
f1();
f2();
5.1 - 闭包的应用
//柯里化
function addFun(m){
return function f(n){
return m + n;
}
return f;
}
var sum = addFun(5);
console.log(sum(6)); //11
console.log(sum(7)); //12
6. 三个常用的高阶函数
- 都是数组的方法;
map //映射
- 内部有内循环,可以对每一个元素做一个映射,然后映射出来的值会组成一个新的数组
var arr = [10, 20, 30, 40];
/*
内部有内循环,可以对每一个元素做一个映射,然后映射出来的值会组成一个新的数组
*/
// var mapArr = arr.map(function(e, index, self){
// return e * e * e;
// });
var mapArr = arr.map(e => e * e); //拉姆达表达式 Lambda
console.log(mapArr); //[1000, 8000, 27000, 64000]
console.log(arr); //[10, 20, 30, 40]
filter //过滤
- 过滤函数,会把回调函数的返回值是true的那些元素给过滤出来,组成一个新的数组
var arr = [10, 11, 20,33, 30, 40];
var filterArr = arr.filter(function(e, index, self){
return !(e % 2);
// return index % 2;
})
/*
过滤函数,会把回调函数的返回值是true的那些元素给过滤出来,组成一个新的数组
*/
// var filterArr = arr.filter(e => e % 2);
console.log(filterArr);
//数组中的质数,平方之后的到新数组
var arr = [10, 20, 30, 5, 9, 3, 17, 19];
var filterArr = arr.filter(function(ele){
for(var i=2; i<=ele/2; i++){
return ele % i;
}
}).map(e => e * e).sort(function(a,b){
return b-a;
});
console.log(filterArr); //[361, 289, 81, 25]
reduce //减少, 归纳
var arr = [10, 20, 30, 5, 9, 3, 17, 19];
var a = arr.reduce(function(pre, e, index, self){
console.log(e, index, self);
return pre * e;
}, 1); //初始值
// var a = arr.reduce((pre, e) => pre * e, 1);
console.log(a); //113
7. 回调函数的this丢失问题
function foo(f){
f();
}
var obj = {
age : 20,
f : function(){
console.log(this.age);
}
}
foo(obj.f); //undefined
var age = 30;
function foo(f){
f();
}
var obj = {
age : 20,
f : function(){
console.log(this.age);
foo(function(){
console.log(this.age);
})
}
}
obj.f(); //20 30;
- 解决:
```
var age = 30;
function foo(f){
f();
}
var obj = {
age : 20,
f : function(){
var that = this; //将动态的this变成变量that/self...
//闭包的运用
foo(function(){
console.log(that.age);
})
}
}
obj.f(); //20
```
8. 字符串中一些常用的方法和属性
- ==在JS中,字符串永远是不可变的==
- 字符串的不可变性。(为了节省内存)
- 很多方法,会有更改字符串的操作,都是重新创建了新的字符串而已
var s1 = "abc你好"; // console.log(s1.length); //5 console.log(s1.charAt(0)); //a console.log(s1[0]);
- length: 返回字符串中字符的个数
- charAt(index): 返回指定索引位置的字符,由于JS中没有字符类型,所以返回的是字符串类型的数据
- s1[0]: 也可以使用方括号语法来访问字符串中的字符。
- charCodeAt(index): 返回字符的Unicode码
//生成随机的一个长度为4的字符串可以是数字可以是字母(大小写)
//验证码
// var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B"];
var arr = [];
for(var i=0; i<10; i++){
arr.push(i + "")
}
for(var j=97, z="z".charCodeAt(0); j<=z; j++){
arr.push(String.fromCharCode(j));
arr.push(String.fromCharCode(j-32));
}
var s = "";
for(var i=0; i<4; i++){
s += arr[randomInt(0, arr.length-1)];
}
console.log(s);
function randomInt(m, n){
return parseInt(Math.random() * (n-m+1) + m);
}
9. 常用方法
字符串的切片
-
substring(start, stop)
- 不能是负数
var s = "abcca"; console.log(s.substring(0, 3)); //abc
-
substr(start, len)
- 参数2: 从start开始切到的字符串的长度
var s = "abcca"; console.log(s.substr(1, 2)); //bc
-
slice(start, stop)
- 唯一的区别在于,这里的下标允许负数
var s = "abcca"; console.log(s.slice(-2, -1)); //c
大小写转换
- toUpperCase
- toLowerCase
var s = "abcca";
console.log(s.toUpperCase()); //ABCCA
console.log(s.toLowerCase()); //abcca
去除字符串的首尾空白字符
- trim()
var s = "\n abcca ddddad \t";
console.log("--" + s.trim() + "---"); //--abcca ddddad---
-
search(参数支持正则)
- 查找——查找参数在字符串中出现的位置
-
match(字符串或正则)
- 找出满足字符串或正则的子字符串,通过数组访问
-
replace(old, new)
- 用new去把old给替换掉
-
split(切割用的字符串)
- 正则表达式更加的强大
10. 数学对象
- Math.PI
- Math.E //自然对数2.7....
- Math.pow(num, m) //求次方
- Math.abs(-num) //绝对值
- Math.sqrt(num) //平方根
- Math.pow(num, 1/3) //num的开次方。
- js中用到角度的,一定是弧度,不是角度
- CSS中一般都是用角度,JS是弧度
- 360° == 2pi
- 180° == pi
function toRadian(deg){ //转弧度
return deg / 180 * Math.PI;
}
function toDegree(red){ //转角度
return red / Math.PI * 180;
}
11. 时间对象
- 用一个整数来表示一个具体的时间点
- 9435890348590 毫秒值 1970 1 1 0 0 0
//如何知道某年某月一共多少天
function daysOfMonth(year, month){
return new Date(year, month, 0).getDate();
}
console.log(daysOfMonth(2016, 12)); //31
网友评论