**
1.JS继承机制** 构造函数中的属性和方法是不共享的,而为了共享一些属性和方法,也为了不浪费资源,出现了prototype,挂在prototype上的属性和方法是共享的。
function Ani(name) { this.name = name; // this.act = '叫';}var dog = new Ani('狗');var cat = new Ani('猫');// dog.act = '旺旺'; //只修改了dog的act属性 不会影响cat的act属性Ani.prototype.act = '旺旺';console.log(dog.name, dog.act, cat.name, cat.act);
由此想到原型链继承:
题目:
用原型链的方式实现继承。创建一个基类PeoClass,其中有两个公开方法:eat、sleep, 再创建一个子类EngiClass, eat继承基类,重写sleep方法:
function PeoClass() {}PeoClass.prototype = { eat: function() { }, sleep: function() { }}function EngiClass() {}EngiClass.prototype = new PeoClass();EngiClass.prototype.constructor = EngiClass;EngiClass.prototype.sleep= function() { // 重写}
2.关于深拷贝
function deepClone(obj){ var newObj = obj instanceof Array ? [] : {}; for(var i in obj){ newObj[i] = typeof obj[i] == 'object'? deepClone(obj[i]) : obj[i]; } return newObj;}
3.关于数组 (1)数组去重
function norepeat(arr) { var new_arr = []; var obj = {}; for(var i = 0, len = arr.length; i < len; i ++) { if(!obj[arr[i]]) { obj[arr[i]] = arr[i]; new_arr.push(i); } } return new_arr; }123456789101112
(2)数组排序/乱序
function arrRand(arr) { arr.sort(function() { return 0.5 - Math.random(); });}
(3)出现次数
function showCount(param) { param = typeof param == 'string' ? param.split('') : param; var obj = {}; for(var i = 0, len = param.length; i < len; i ++) { if(!obj[param[i]]) { obj[param[i]] = 1; }else { obj[param[i]] += 1; } } return obj;}
4.关于作用域、闭包以及this
作用域
:javascript是基于词法作用域的语言,也就是静态作用域,即在函数定义时就确定了作用域,而不是执行时
闭包:
两个函数中间包裹一块无法直接访问的作用域,只能通过间接地方式访问;闭包可以使内部变量始终保存在内存中;有闭包就可能造成内存泄漏。
function f1() { var n = 99; add = function() { n += 1; } function f2() { console.log(n); } return f2;}var res = f1();res(); // 99add();res(); // 100 n一直保持在内存中/************************************************/var x = 20;var a = { x: 15, fn: function() { var x = 30; return function() { return x; }; }}console.log(a.fn());// function() {return x}console.log(a.fn()());// 30console.log((a.fn())());// 30console.log((a.fn())() == a.fn()());// trueconsole.log(a.fn().call(this));// console.log(a.fn().call(a)); //
关于this:
动态绑定,也就是在函数执行时从上下文中获取指向,上下文不同,this指向不同;一般指向调用者对象,也就是函数的拥有者;特殊的情况是自执行函数,this指向window;(闭包遇上this时,要注意运行时的上下文,看栗子)(当构造函数中return一个对象(除了null)时,this指向return的对象)
var x = 'windows';var obj_a = { x: 1, y: { x: 2, y: function() { return function() { return this.x; } }, z: function() { return this.x; } }}var fun = obj_a.y.y();console.log(obj_a.y.z()); // 2console.log(obj_a.y.y()()); // windowsconsole.log(fun()); // 'windows'
4.关于call/apply/bind
var obj = { a: 'obj.a', b: function() { console.log(this.a); }}var fun = obj.b;fun(); // undefined 因为执行时上下文中的this指向windowobj.b(); // 'obj.a' 执行时上下文中的this指向obj
call
:改变对象的环境,即改变this指向,并调用函数;参数:n个,第一个参数是目标对象或者对象本身,其他参数可以是原函数的参数; 上述fun()语句若改为apply
fun.call(obj);//'obj.a'上下文中原本指向window的this强制指向了obj对象
apply
:与call方法类似,效果也类似,只是参数格式不同,第一个参数都是目标对象或对象本身,但第二个参数必须是个数组,放置函数的参数
注意:非严格模式下,若call/apply的第一个参数传入null、undefined, 则this指向window对象
bind
:与以上两个方法有些不同,但是都能改变this指向,不同之处在于bind方法并不能调用原函数,而是返回一个修改后的函数,称为绑定函数,若要执行需要手动调用该函数;
fun.bind(obj)(); // 'obj.a'
同样bind也可以有多个参数,格式可以与call一样,也可以执行时再次添加
var a = { x: 'mx', y: function(a, b) { console.log(this.x); console.log(a+b); }}var b = a.y;b.call(a, 1, 2); // mx 3b.apply(a, [1, 2]); // mx 3b.bind(a, 1, 2)() // mx 3b.bind(a, 1)(2) // mx 3